Как использовать вид (мерцание) в качестве заполнителя для imageView (Glide)

Я использую Glide для загрузки изображений в свой imageView (которые находятся внутри recyclerview):

Glide.with(image.context).load(url)
        .error(context.getDrawable(R.drawable.placeholder))
        .into(image)

Я вижу, что в библиотеке Glide также есть функция "заполнитель", которая дает возможность загружать Drawable, который будет отображаться, когда изображение еще загружается.

С другой стороны, для всего recyclerView я использую библиотеку Facebook Shimmer, чтобы показать, что загружается recyclerview.

Глядя на мое приложение, все работает нормально. Тем не менее, все еще есть промежуток времени между закрытием мерцания (извлечением данных) и показом изображения. Именно тогда и нужен заполнитель. Мне интересно, есть ли способ использовать Shimmer в качестве заполнителя для imageView? Функция Placeholder в Glide поддерживает только Drawable, а Shimmer - это View.

В любом случае преобразовать Shimmer в Drawable? или GIF? Или любое другое предложение?

3 ответа

Решение

Благодаря приведенному выше комментарию Майка: существует класс ShimmerDrawable, в котором вы можете создать мерцающий вид в качестве тяги, которую можно использовать в Glide:

private val shimmer = Shimmer.AlphaHighlightBuilder()// The attributes for a ShimmerDrawable is set by this builder
    .setDuration(1800) // how long the shimmering animation takes to do one full sweep
    .setBaseAlpha(0.7f) //the alpha of the underlying children
    .setHighlightAlpha(0.6f) // the shimmer alpha amount
    .setDirection(Shimmer.Direction.LEFT_TO_RIGHT)
    .setAutoStart(true)
    .build()

// This is the placeholder for the imageView
    val shimmerDrawable = ShimmerDrawable().apply {
        setShimmer(shimmer)
    }


Glide.with(image.context).load(url)
        .placeholder(shimmerDrawable)
        .error(context.getDrawable(R.drawable.placeholder))
        .into(image)

В моем случае я хотел рисовать с закругленными углами в качестве заполнителя, который не поддерживался библиотекой, и я обнаружил, что вы можете добиться этого, используя ShapeableImageView из Google Material Designs.

1. Добавьте в свои зависимости библиотеку Google Material Designs. 'com.google.android.material:material:1.2.1' с версией 1.2.1 и выше.

2. В представлении элемента списка определите ImageView как ShapeableImageView, как показано ниже:

      <com.google.android.material.imageview.ShapeableImageView
   android:id="@+id/shapeImageView"
   android:layout_width="70dp"
   android:layout_height="70dp"
   android:background="@android:color/holo_red_dark"
   app:layout_constraintStart_toStartOf="parent"
   app:layout_constraintTop_toTopOf="parent"/>

3.И в классе RecyclerView.ViewHolder установите для ShapeAppearanceModel вышеуказанного ShapeableImageView значение CornerFamily.ROUNDED с радиусом угла в пикселях и загрузите ShimmerDrawable в качестве заполнителя в Glide, как показано ниже:

      //initialize shimmer
val shimmer = Shimmer.ColorHighlightBuilder()
     .setBaseColor(ContextCompat.getColor(itemView.context, R.color.teal_200))
     .setBaseAlpha(0.7f)
     .setHighlightAlpha(0.7f)
     .setHighlightColor(ContextCompat.getColor(itemView.context, R.color.purple_700))
     .setDuration(1800)
     .setDirection(Shimmer.Direction.LEFT_TO_RIGHT)
     .setAutoStart(true)
     .build()

 //create ShimmerDrawable()
 val shimmerDrawable = ShimmerDrawable()
 shimmerDrawable.setShimmer(shimmer)

 //set the ShapeAppearanceModel to CornerFamily.ROUNDED and the radius in pixels
 val radius: Float = dpToPx(itemView.context, 15).toFloat();
 shapeImageView.setShapeAppearanceModel(shapeImageView.getShapeAppearanceModel()
                .toBuilder()
                .setAllCorners(CornerFamily.ROUNDED, radius)
                .build())

 //load url from Glide and add shimmerDrawable as placeholder
 Glide.with(itemView.context).load(item.url)
        .placeholder(shimmerDrawable)
        .into(shapeImageView)

со вспомогательным классом для преобразования радиуса из dp в пиксели

      fun dpToPx(context: Context, dp: Int): Int {
  return (dp * context.resources.displayMetrics.density).toInt()
}

И результат выше будет:

Я разработал библиотеку для простого добавления эффектов загрузки мерцания / скелета. https://github.com/AgnaldoNP/AGSkeletonLoading

На README.md есть объяснение о том, как его использовать. Не нужно добавлять кучу макетов для имитации скелета, он рассчитывается автоматически. Макет, используемый для отображения скелета, такой же, как и для отображения содержимого.

Если вы используете SkeletonImageView в файле макета, вы просто вызываете startLoading() и stopLoading() для управления анимацией. Надеюсь я помог тебе

Другие вопросы по тегам