In my app I load data from API which is using paginating so I have to use paging 3 library and I use facebook shimmer library to show shimmer effect when items are being loaded but the problem is always shimmer effect is shown even when items are completely loaded
ArticlePagingAdapter.kt
class ArticlePagingAdapter(private val listener: OnItemClickListener) :
PagingDataAdapter<Article, ArticlePagingAdapter.ViewHolder>(ArticleDiffUtil()) {
private val TAG = ArticlePagingAdapter::class.simpleName
private lateinit var context: Context
var showShimmer: Boolean = true
inner class ViewHolder(itemView: View) :
RecyclerView.ViewHolder(itemView), View.OnClickListener {
lateinit var item: Article
val shimmerLayout: ShimmerFrameLayout = itemView.shimmer_layout
val articleImageView: ShapeableImageView = itemView.findViewById(R.id.article_image_view)
val articleTitleTextView: TextView = itemView.findViewById(R.id.article_title_text_view)
val articleEstimatedTextView: TextView =
itemView.findViewById(R.id.article_estimated_read_time_text_view)
val clockImageView: ImageView = itemView.findViewById(R.id.clock_icon)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
if (showShimmer) {
holder.shimmerLayout.startShimmer()
} else {
holder.shimmerLayout.stopShimmer()
holder.shimmerLayout.setShimmer(null)
holder.articleImageView.background = null
holder.clockImageView.background = null
holder.articleEstimatedTextView.background = null
holder.articleTitleTextView.background = null
val item = getItem(position)
if (item != null) {
Log.d(TAG, "position $position, isNull != null ")
holder.item = item
holder.articleTitleTextView.text = item.title
holder.articleEstimatedTextView.text = (item.estimatedReadingTime.toString()
val requestOptions = RequestOptions().transform(
CenterCrop(), RoundedCorners(
context.resources.getDimension(R.dimen.item_article_image_view_radius)
.toInt()
)
)
Glide.with(context).load(item.imageUrl!!.toUri())
.placeholder(R.drawable.ic_article_placeholder).apply(requestOptions)
.into(holder.articleImageView)
holder.clockImageView.setImageResource(R.drawable.ic_clock)
} else {
Log.d(TAG, "position $position, isNull= null ")
}
}
}
}
ArticleFragmnet.kt
class LatestArticlesFragment : Fragment(), ArticlePagingAdapter.OnItemClickListener {
val TAG = LatestArticlesFragment::class.simpleName
lateinit var binding: FragmentLatestArticlesBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// some unrelated code
val adapter = ArticlePagingAdapter(this)
binding.recyclerView.adapter = adapter
viewModel.getArticles().observe(viewLifecycleOwner) { data ->
lifecycleScope.launch {
adapter.submitData(data)
Log.d(TAG,"data ${data.toString()}")
adapter.showShimmer = false
}
}
}
}
ArticleFragmentViewModel.kt
class LatestArticlesFragmentViewModel @AssistedInject constructor(
private val repository: ArticleRepository, ...) : ViewModel() {
fun getArticles(): LiveData<PagingData<Article>> {
currentArticles = repository.getArticlesStream().cachedIn(viewModelScope)
return currentArticles?.asLiveData()!!
}
}
item_article.xml
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
style="@style/card_view_style"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/small_margin"
android:clipToPadding="false"
android:paddingBottom="@dimen/_2sdp">
<com.facebook.shimmer.ShimmerFrameLayout
android:id="@+id/shimmer_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/very_small_padding">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/article_image_view"
android:layout_width="0dp"
android:layout_height="@dimen/_70sdp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="3:2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/article_title_text_view"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/ic_icon" />
<TextView
android:id="@+id/article_title_text_view"
style="@style/Widget.MyWidget.TextView.VerySmall.Bold"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/very_small_margin"
android:layout_marginEnd="@dimen/very_small_margin"
android:ellipsize="end"
android:gravity="start"
android:maxLines="2"
android:minLines="2"
android:textAlignment="textStart"
android:textColor="?attr/textColor"
app:layout_constraintBottom_toTopOf="@id/clock_icon"
app:layout_constraintEnd_toStartOf="@id/article_image_view"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/article_image_view"
tools:text="This is a dummy title" />
<TextView
android:id="@+id/article_estimated_read_time_text_view"
style="@style/Widget.MyWidget.TextView.VerySmall"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/very_small_margin"
android:background="@color/shimmer_background"
android:textColor="?attr/textColor"
app:layout_constraintBottom_toBottomOf="@id/article_image_view"
app:layout_constraintEnd_toEndOf="@id/article_title_text_view"
app:layout_constraintStart_toEndOf="@id/clock_icon"
app:layout_constraintTop_toBottomOf="@id/article_title_text_view"
tools:text="5 min" />
<ImageView
android:id="@+id/clock_icon"
android:layout_width="@dimen/_10sdp"
android:layout_height="@dimen/_10sdp"
android:background="@color/shimmer_background"
app:layout_constraintBottom_toBottomOf="@id/article_estimated_read_time_text_view"
app:layout_constraintEnd_toStartOf="@id/article_estimated_read_time_text_view"
app:layout_constraintStart_toStartOf="@id/article_title_text_view"
app:layout_constraintTop_toTopOf="@id/article_estimated_read_time_text_view"
tools:src="@drawable/ic_clock" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.facebook.shimmer.ShimmerFrameLayout>
</com.google.android.material.card.MaterialCardView>
fragment_article_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/root_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/articleBackground">
<TextView
android:id="@+id/article_text_view"
style="@style/Widget.MyWidget.TextView.Large.Bold"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/medium_margin"
android:text="@string/articles"
android:textColor="?attr/textColor"
app:layout_constraintStart_toStartOf="@id/left_guideline"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/line_separator"
style="@style/Divider"
android:layout_marginStart="@dimen/_10sdp"
app:layout_constraintBottom_toBottomOf="@id/article_text_view"
app:layout_constraintEnd_toEndOf="@id/right_guideline"
app:layout_constraintStart_toEndOf="@id/article_text_view"
app:layout_constraintTop_toTopOf="@id/article_text_view"
app:layout_constraintVertical_chainStyle="packed" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@android:color/transparent"
android:clipToPadding="false"
android:orientation="vertical"
android:paddingHorizontal="@dimen/small_padding"
android:paddingTop="@dimen/small_padding"
android:paddingBottom="@dimen/small_padding"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/article_text_view"
tools:itemCount="8"
tools:listitem="@layout/item_article" />
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:src="?attr/listFadeBackground"
app:layout_constraintTop_toTopOf="@id/recycler_view" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/left_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.03" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/right_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.97" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>