【问题标题】:Transitioning a GradientDrawable过渡 GradientDrawable
【发布时间】:2019-05-14 16:58:49
【问题描述】:

我有一个函数可以在我的MainActivity 的背景上创建一个渐变。渐变以编程方式创建为GradientDrawable。应用中的某些交互会改变渐变的颜色。

渐变和颜色已正确显示,并且它们会相应地发生变化,但是,我想要颜色变化的过渡效果。现在,颜色会立即过渡,没有交叉渐变。

fun createGradient() {
    gd.shape = GradientDrawable.RECTANGLE
    mainActivityID.background = gd
    gd.gradientType = GradientDrawable.LINEAR_GRADIENT
    gd.orientation = (GradientDrawable.Orientation.BL_TR)
}

基于App中的交互,我使用when语句来改变GradientDrawable的颜色

fun changeGradient(){

    //val td = gd as TransitionDrawable
    //td.isCrossFadeEnabled = true
    //td.startTransition(1500)

    when(calories){
        in 0..50 -> gd.colors = intArrayOf(
            ContextCompat.getColor(this, R.color.dBlue),
            ContextCompat.getColor(this, R.color.lBlue)
        )
        in 51..100 -> gd.colors = intArrayOf(
            ContextCompat.getColor(this, R.color.dRed),
            ContextCompat.getColor(this, R.color.lRed)
        )
        // etc...
    }
}

我尝试将 GradientDrawable 转换为 TransitionDrawable(如上面注释的代码中所示),但会崩溃:

java.lang.ClassCastException: android.graphics.drawable.GradientDrawable 不能转换为 android.graphics.drawable.TransitionDrawable

如何在 GradientDrawable 颜色变化之间添加 1500 毫秒的过渡?

Progress 因java.lang.NegativeArraySizeException: -16777216 而崩溃

when(calories){
    in 0..50 -> animateGradient(gd, IntArray(Color.BLACK), IntArray(Color.CYAN))
    in 51..100 -> animateGradient(gd, IntArray(Color.RED), IntArray(Color.BLUE))
    in 101..150 -> animateGradient(gd, IntArray(Color.GREEN), IntArray(Color.YELLOW))
    // etc... about 15 more statements.
}

【问题讨论】:

    标签: android kotlin transitiondrawable gradientdrawable


    【解决方案1】:

    我认为渐变 drawable 没有内置过渡方法,但您可以运行自己的值动画器来执行颜色过渡。

    var anim : Animator? = null
    
    fun animateGradient(gd: GradientDrawable, from : IntArray, to: IntArray){
        require(from.size == to.size)
        anim?.cancel()
        val arraySize = from.size
        val props = Array<PropertyValuesHolder>(arraySize){
            PropertyValuesHolder.ofObject(it.toString(), ArgbEvaluator(), from[it], to[it])
        }
        val anim = ValueAnimator.ofPropertyValuesHolder(*props)
        anim.addUpdateListener {
            gd.colors = IntArray(arraySize){i ->
                it.getAnimatedValue(i.toString()) as Int
            }
        }
        anim.duration = 1500
        anim.start()
        this.anim = anim
    }
    

    编辑:修改方法,使其跟踪当前颜色本身,减少参数数量。

    var anim : Animator? = null
    // variable that tracks current color - must be initialized with default gradient colors
    var currentGradient = intArrayOf(
            ContextCompat.getColor(this, R.color.dBlue),
            ContextCompat.getColor(this, R.color.lBlue)
        )
    
    fun animateGradient(targetColors: IntArray){
        val from = currentGradient
        require(from.size == targetColors.size)
        anim?.cancel()
        val arraySize = from.size
        val props = Array<PropertyValuesHolder>(arraySize){
            PropertyValuesHolder.ofObject(it.toString(), ArgbEvaluator(), from[it], targetColors[it])
        }
        val anim = ValueAnimator.ofPropertyValuesHolder(*props)
        anim.addUpdateListener {valueAnim ->
            IntArray(arraySize){i ->
                valueAnim.getAnimatedValue(i.toString()) as Int
            }.let{
                currentGradient = it
                gd.colors = it
            }
        }
        anim.duration = 1500
        anim.start()
        this.anim = anim
    }
    

    调用站点:

    when(calories){
        in 0..50 -> animateGradient(intArrayOf(
            ContextCompat.getColor(this, R.color.dBlue),
            ContextCompat.getColor(this, R.color.lBlue)
        ))
        in 51..100 -> animateGradient(intArrayOf(
            ContextCompat.getColor(this, R.color.dRed),
            ContextCompat.getColor(this, R.color.lRed)
        ))
        // etc...
    }
    

    【讨论】:

    • 您的 animateGradient 函数是否应该替换我在 when 语句中的内容?或者它会去追求?你能提供这个用法吗?
    • @Joe 您从每个 when 案例而不是 gd.setColors(..) 调用它,这将创建并运行过渡动画。您需要提供当前渐变颜色作为from 参数和目标颜色作为to
    • 我编辑了我的问题以显示进度。您的解决方案正在崩溃。我不明白为什么有两个数组参数。这些不应该是单色来处理从(渐变的颜色 1)到(渐变的颜色 2)吗?
    • @Joe 修改了在其中跟踪当前渐变颜色的方法,这替换了from 参数,因此您只需要提供新的渐变颜色。
    • 经过反复试验,我让它工作了!谢谢!唯一不起作用的是使用默认颜色初始化 currentGradient 。看起来它不希望我使用 ContextCompat.getColor(this, R.color.dBlue), ContextCompat.getColor(this, R.color.lBlue)。但是,如果我使用 Color.BLUE、Color.RED 来初始化 currentGradient,它就可以正常工作。这个问题超出了我的问题范围,但你知道它为什么不允许我使用 ContextCompat 吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-22
    • 2012-02-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多