繁体   English   中英

如何在Android中的ImageView中添加闪光效果?

[英]How to add shimmer effect to imageview in android?

我需要按照ImageView链接中的说明在图像视图中添加微光效果 动画应从下至上,而不是如示例图片中从左至右。 我尝试了facebook shimmer libraby,但仅从以上API 16支持。 我需要支持,如果从14以上。 我也尝试过该库,但它不支持ImageViews以及自下而上的动画。 是否有任何库可以实现Imageview的闪烁效果(从下到上的动画)? 还是有什么方法可以使用ImageView实现此功能?

您可以创建自己的自定义视图!

class ShimmerView : View, ValueAnimator.AnimatorUpdateListener{

constructor(context: Context)
        : super(context) { init() }

constructor(context: Context, attrs: AttributeSet)
        : super(context, attrs) { init() }

constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int)
        : super(context, attrs, defStyleAttr) { init() }


companion object {
    const val EDGE_ALPHA      = 12
    const val SHADER_COLOR_R  = 170
    const val SHADER_COLOR_G  = 170
    const val SHADER_COLOR_B  = 170
    const val CENTER_ALPHA    = 100
    const val ITEM_BG_COLOR   = Color.WHITE

    val EDGE_COLOR   = Color.argb(EDGE_ALPHA, SHADER_COLOR_R, SHADER_COLOR_G, SHADER_COLOR_B)
    val CENTER_COLOR = Color.argb(CENTER_ALPHA, SHADER_COLOR_R, SHADER_COLOR_G, SHADER_COLOR_B)

    const val LIST_ITEM_LINES    = 3
    const val CORNER_RADIUS      = 2
    const val LINE_HEIGHT        = 15
    const val H_SPACING          = 12
    const val W_SPACING          = 16
    const val IMAGE_SIZE         = 50
    const val ANIMATION_DURATION = 1500L
}


private var listItems:    Bitmap?        = null
private var animator:     ValueAnimator? = null
private var paint:        Paint?         = null
private var shaderPaint:  Paint?         = null
private var shaderColors: IntArray?      = null

private var lineHeight:   Float = 0F
private var hSpacing:     Float = 0F
private var wSpacing:     Float = 0F
private var imageSize:    Float = 0F
private var cornerRadius: Float = 0F


// 1. Инициализируем переменные.
// 1. Initialize variables.
fun init() {
    val metric = context.resources.displayMetrics
    cornerRadius    = dpToPixels(metric, CORNER_RADIUS)
    hSpacing        = dpToPixels(metric, H_SPACING)
    wSpacing        = dpToPixels(metric, W_SPACING)
    lineHeight      = spToPixels(metric, LINE_HEIGHT)
    imageSize       = dpToPixels(metric, IMAGE_SIZE)

    animator = ValueAnimator.ofFloat(-1F, 2F)
    animator?.duration     = ANIMATION_DURATION
    animator?.interpolator = LinearInterpolator()
    animator?.repeatCount  = ValueAnimator.INFINITE
    animator?.addUpdateListener(this)

    paint = Paint()

    shaderPaint = Paint()
    shaderPaint?.isAntiAlias = true
    shaderColors = intArrayOf(EDGE_COLOR, CENTER_COLOR, EDGE_COLOR)
}


// 2. Когда View отобразилась на экране, запускаем анимацию.
// 2. When View is displayed on the screen, run the animation.
override fun onVisibilityChanged(changedView: View?, visibility: Int) {
    super.onVisibilityChanged(changedView, visibility)
    when(visibility) {
        VISIBLE         -> animator?.start()
        INVISIBLE, GONE -> animator?.cancel()
    }
}


// 3. При выполнении анимации, изменяем положение шейдера и перерисовываем View.
// 3. When the animation, change the position of the shader and redraw View.
override fun onAnimationUpdate(valueAnimator: ValueAnimator) {
    if(isAttachedToWindow) {
        val factor: Float = valueAnimator.animatedValue as Float
        updateShader(width = width.toFloat(), factor = factor)
        invalidate()
    }
}


// 4. Одновременно со стартом анимации, рисуем элементы.
// 4. Simultaneously with the start of the animation, draw the elements.
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
    super.onSizeChanged(w, h, oldw, oldh)
    updateShader(width = w.toFloat())
    if (h > 0 && w > 0) {
        drawListItems(w, h)
    } else {
        listItems = null
        animator?.cancel()
    }
}


private fun updateShader(width: Float, factor: Float = -1F) {
    val left = width * factor
    val shader = LinearGradient(
            left, 0F, left+width, 0F, shaderColors, floatArrayOf(0f, 0.5f, 1f), Shader.TileMode.CLAMP)
    shaderPaint?.shader = shader

}


override fun onDraw(canvas: Canvas) {
    canvas.drawColor(EDGE_COLOR)
    canvas.drawRect(0F, 0F, canvas.width.toFloat(), canvas.height.toFloat(), shaderPaint)
    if (listItems != null) { canvas.drawBitmap(listItems, 0F, 0F, paint) }
}


private fun drawListItems(w: Int, h: Int) {
    listItems  = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(listItems)
    val item   = getItemBitmap(w)
    var top    = 0

    do {
        canvas.drawBitmap(item, 0F, top.toFloat(), paint)
        top += item.height
    } while (top < canvas.height)

    canvas.drawColor(ITEM_BG_COLOR, PorterDuff.Mode.SRC_IN)
}


private fun getItemBitmap(w: Int): Bitmap {
    val h    = calculateListItemHeight(LIST_ITEM_LINES)
    val item = Bitmap.createBitmap(w, h, Bitmap.Config.ALPHA_8)

    val canvas = Canvas(item)
    canvas.drawColor(Color.argb(255, 0, 0, 0))

    val itemPaint = Paint()
    itemPaint.isAntiAlias = true
    itemPaint.color       = Color.argb(0, 0, 0, 0)
    itemPaint.xfermode    = PorterDuffXfermode(PorterDuff.Mode.DST_IN)

    //Avatar
    val rectF = RectF(wSpacing, hSpacing, wSpacing+imageSize, hSpacing+imageSize)
    canvas.drawOval(rectF, itemPaint)

    val textLeft  = rectF.right  + hSpacing
    val textRight = canvas.width - wSpacing

    //Title line
    val titleWidth = (textRight - textLeft)*0.5F
    rectF.set(textLeft, hSpacing, textLeft+titleWidth, hSpacing+lineHeight)
    canvas.drawRoundRect(rectF, cornerRadius, cornerRadius, itemPaint)

    //Time stamp
    val timeWidth = (textRight - textLeft)*0.2F
    rectF.set(textRight-timeWidth, hSpacing, textRight, hSpacing+lineHeight)
    canvas.drawRoundRect(rectF, cornerRadius, cornerRadius, itemPaint)

    //Text lines
    for (i in 0..LIST_ITEM_LINES-1) {
        val lineTop = rectF.bottom + hSpacing
        rectF.set(textLeft, lineTop, textRight, lineTop+lineHeight)
        canvas.drawRoundRect(rectF, cornerRadius, cornerRadius, itemPaint)
    }

    return item
}


private fun calculateListItemHeight(lines: Int): Int {
    return ((lines*lineHeight) + (hSpacing*(lines+1))).toInt()
}


private fun dpToPixels(metrics: DisplayMetrics, dp: Int): Float {
    return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp.toFloat(), metrics)
}


private fun spToPixels(metrics: DisplayMetrics, sp: Int): Float {
    return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp.toFloat(), metrics)
}


override fun onDetachedFromWindow() {
    super.onDetachedFromWindow()
    animator?.removeAllUpdateListeners()
    animator  = null
    listItems = null
}

}

资源

Facebook Shimmer Library确实支持API级别14。我正在具有以下设置的项目中使用它:

 defaultConfig {
      ....
        minSdkVersion 14
        targetSdkVersion 23
      ....
    }

具有这种依赖性:

dependencies {
     ....
    compile 'com.facebook.shimmer:shimmer:0.1.0'
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM