如何在android中为imageview添加微光效果?

如何在android中为imageview添加微光效果?,android,android-animation,android-imageview,Android,Android Animation,Android Imageview,我需要添加到ImageView的链接中给出的图像视图。动画应该从下到上,而不是像示例图片中那样从左到右。我已经试过了,但是它只支持上面的API 16。我需要支持如果从14以上。我也尝试过,但它不支持ImageView以及从下到上的动画。是否有任何库可以实现Imageview的微光效果(具有从下到上的动画)?或者是否有任何方法可以使用ImageView实现此功能?Facebook Shimmer库支持API级别14。我在具有以下设置的项目中使用它: defaultConfig { .

我需要添加到ImageView的链接中给出的图像视图。动画应该从下到上,而不是像示例图片中那样从左到右。我已经试过了,但是它只支持上面的API 16。我需要支持如果从14以上。我也尝试过,但它不支持ImageView以及从下到上的动画。是否有任何库可以实现Imageview的微光效果(具有从下到上的动画)?或者是否有任何方法可以使用ImageView实现此功能?

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

 defaultConfig {
      ....
        minSdkVersion 14
        targetSdkVersion 23
      ....
    }
对于此依赖项:

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

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

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
}
类ShimmerView:View,ValueAnimator.AnimatorUpdateListener{
构造函数(上下文:上下文)
:super(上下文){init()}
构造函数(上下文:上下文,属性:属性集)
:super(上下文,属性){init()}
构造函数(context:context,attrs:AttributeSet,defStyleAttr:Int)
:super(context,attrs,defStyleAttr){init()}
伴星{
const val EDGE_ALPHA=12
常量值着色器颜色=170
const val SHADER_COLOR_G=170
常量值着色器颜色=170
常数值中心α=100
const val ITEM_BG_COLOR=COLOR.WHITE
val EDGE\u COLOR=COLOR.argb(EDGE\u ALPHA,SHADER\u COLOR\R,SHADER\u COLOR\G,SHADER\u COLOR\B)
val CENTER\u COLOR=COLOR.argb(CENTER\u ALPHA,SHADER\u COLOR\R,SHADER\u COLOR\G,SHADER\u COLOR\B)
常量值列表\项目\行=3
常数值角半径=2
const val LINE_HEIGHT=15
const val H_间距=12
常量值W_间距=16
常量值图像大小=50
持续时间=1500L
}
私有变量listItems:位图?=null
私有变量animator:ValueAnimator?=null
私有变量绘制:绘制?=null
私有变量shaderPaint:绘制?=null
私有变量着色器颜色:IntArray?=null
专用变量线宽:浮点=0F
专用变量hSpacing:浮动=0F
私有变量wspacking:Float=0F
私有变量imageSize:浮点=0F
专用var转弯半径:浮动=0F
// 1. Инициализируем переменные.
//1.初始化变量。
fun init(){
val metric=context.resources.displayMetrics
拐角半径=dpToPixels(公制,拐角半径)
hSpacing=dpToPixels(公制,H_间距)
wspacking=dpToPixels(公制,W_间距)
线宽=像素(公制,线宽)
imageSize=dpToPixels(公制,图像大小)
animator=ValueAnimator.offload(-1F,2F)
动画师?.duration=动画\u duration
动画师?.interpolator=LinearInterpolator()
animator?.repeatCount=ValueAnimator.INFINITE
动画师?.addUpdateListener(此)
油漆=油漆()
shaderPaint=Paint()
shaderPaint?.Isatarias=真
ShaderColor=intArrayOf(边缘颜色、中心颜色、边缘颜色)
}
//2.卡夫卡夫视图卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫卡夫。
//2.当屏幕上显示视图时,运行动画。
覆盖VisibilityChanged(更改视图:视图?,可见性:Int){
super.onVisibilityChanged(更改视图、可见性)
何时(能见度){
可见->动画师?.start()
不可见,消失->动画师?.cancel()
}
}
//3.视图。
//3.播放动画时,更改着色器的位置并重新绘制视图。
覆盖动画更新(valueAnimator:valueAnimator){
如果(isAttachedToWindow){
val factor:Float=valueAnimator.animatedValue为Float
updateShader(width=width.toFloat(),factor=factor)
使无效
}
}
// 4. Одновременно со стартом анимации, рисуем элементы.
//4.在动画开始的同时,绘制元素。
覆盖乐趣已更改(w:Int,h:Int,oldw:Int,oldh:Int){
super.onSizeChanged(w,h,oldw,oldh)
updateShader(宽度=w.toFloat())
如果(h>0&&w>0){
图纸列表项目(w、h)
}否则{
listItems=null
动画师?.cancel()
}
}
private fun updateShader(宽度:浮点,因子:浮点=-1F){
val left=宽度*系数
val shader=LinearGradient(
左、0F、左+宽度、0F、着色器颜色、floatArrayOf(0F、0.5f、1f)、着色器.TileMode.CLAMP)
shaderPaint?.shader=着色器
}
覆盖onDraw(画布:画布){
画布.drawColor(边缘颜色)
canvas.drawRect(0F,0F,canvas.width.toFloat(),canvas.height.toFloat(),shaderPaint)
if(listItems!=null){canvas.drawBitmap(listItems,0F,0F,paint)}
}
私人趣味drawListItems(w:Int,h:Int){
listItems=Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888)
val画布=画布(列表项)
val item=getItemBitmap(w)
var top=0
做{
canvas.drawBitmap(项,0F,top.toFloat(),绘制)
顶部+=项目高度
}while(顶部<画布高度)
canvas.drawColor(ITEM_BG_COLOR,PorterDuff.Mode.SRC_IN)
}
私有趣味getItemBitmap(w:Int):位图{
val h=计算机构高度(列表项目行)
val item=Bitmap.createBitmap(w,h,Bitmap.Config.ALPHA_8)
val画布=画布(项目)
canvas.drawColor(Color.argb(255,0,0,0))
val itemPaint=Paint()
itemPaint.Isatarias=true
itemPaint.color=color.argb(0,0,0,0)
itemPaint.xfermode=PorterDuffXfermode(PorterDuff.Mode.DST_IN)
//化身
val rectF=rectF(wspacking,hspacking,wspacking+imageSize,hspacking+imageSize)
canvas.drawOval(rectF、itemPaint)
val textLeft=rectF.right+hSpacing
val textRight=canvas.width-wspacking
//标题行
val titleWidth=(textRight-textLeft)*0.5F
rectF.set(文本左,hSpacin