美文网首页
Android过渡动画Scene and Transition(

Android过渡动画Scene and Transition(

作者: 猫爸iYao | 来源:发表于2018-11-16 20:13 被阅读0次

    自定义Transition

    Android Transition框架提供了丰富的内建Transition,一般情况下能够满足我们的需求。但是有些时候仅仅依靠内建Transition已经不能满足射击师的狂想,此时我们需要自己实现一些满足特殊场景的Transition。
    一个自定义的Transition同内建的Transition实现方式一致,创建一个类继承自Transition类。该类需要处理的逻辑主要有以下三点:

    1. 开始场景和结束场景的发生变化的对应view的属性;
    2. 依据开始场景view的属性值和结束场景view的属性值创建属性动画;
    3. 指定该Transition的target views。

    继承Transition类

    Transition类是一个抽象类,一个自定义Transition一般只需要重写三个方法,如下:

    class CustomTransition : Transition {
    
        constructor() : super()
        
        constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
        
        override fun captureStartValues(startValues: TransitionValues?) {
        }
    
        override fun captureEndValues(endValues: TransitionValues?) {
        }
    
        override fun createAnimator(sceneRoot: ViewGroup?, startValues: TransitionValues?, endValues: TransitionValues?): Animator? {
            return null
        }
    }
    

    两个构造方法

    transition类有两个构造方法,无参构造器只能用于code方式构造transition对象实例。但是如果要在XML文件中使用自定义Transition,则必须实现constructor(context: Context?, attrs: AttributeSet?)构造器。使用方式:

    <transition class="com.iyao.transition.ChangeRectRadiusAndColor"/>
    

    Transition框架使用属性动画实现过渡动画。因此,Transition类需要属性的开始值和结束值来构建动画。然而,一个属性动画通常只需要一个view的全部属性的一部分。一旦一个Transiton动画所需要的属性被指定,那么Transition类没必要再关注view的其他属性。因此,Transition框架提供回调方法用于捕获该Transition关注的属性。其中fun captureStartValues(transitionValues: TransitionValues)fun captureEndValues(transitionValues: TransitionValues)这两个方法分别用于获取开始和结束的view属性,然后保存到TransitionValues对象的values中,用于fun createAnimator(sceneRoot: ViewGroup, startValues: TransitionValues?, endValues: TransitionValues?): Animator?方法创建属性动画。

    captureStartValues方法捕获startingScene属性值集合

    Transition框架会采用深度优先遍历方法遍历startingScene的所有views。并在递归过程中为每一个view调用captureStartValues()方法,该方法的参数TransitionValues对象持有该view的引用和一个Map实例用于保存过渡动画需要的属性值。在这个方法中,我们只要获取该view实现动画所需要的属性值,然后保存到Map对象中,Transition框架会把TransitionValues对象保存起来,用于创建动画。

    captureEndValues方法捕获endingScene属性值集合

    captureEndValues()方法和captureStartValues()方法作用一致,不过遍历的views是endingScene中的。

    createAnimator方法构建属性动画

    当Transition框架捕获到用于构建动画的属性集合后,会调用Transition类的createAnimator()方法获取一个Animator对象。该方法默认实现返回一个null,Transition子类需要重写该方法以构建自己的属性动画。

    方法参数中,sceneRoot是TransitionManager.go()方法传入的Scene的SceneRoot,startValues和endValues是captureStartValues()方法和captureEndValues()方法传入的TransitionValues对象。

    示例代码:

    package com.iyao.transition
    
    import ArgbEvaluator
    import android.animation.Animator
    import android.animation.AnimatorSet
    import android.animation.ObjectAnimator
    import android.os.Build
    import android.transition.Transition
    import android.transition.TransitionValues
    import android.view.ViewGroup
    
    class ChangeRectRadiusAndColor : Transition() {
    
        //官方建议属性键名命名规则:package:class:property
        private val propertyRadius = "com.iyao.transition:RectView:radius"
        private val propertyColor = "com.iyao.transition:RectView:color"
    
        //init {
        //   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        //        addTarget(RectView::class.java)
        //    }
        //}
    
    
        override fun captureEndValues(transitionValues: TransitionValues) {
            captureValues(transitionValues)
        }
    
    
        override fun captureStartValues(transitionValues: TransitionValues) {
            captureValues(transitionValues)
        }
    
        
        private fun captureValues(transitionValues: TransitionValues) {
            if (transitionValues.view is RectView) {
                val rectView = transitionValues.view as RectView
                transitionValues.values.put(propertyRadius, rectView.radius)
                transitionValues.values.put(propertyColor, rectView.color)
            }
        }
    
        override fun createAnimator(sceneRoot: ViewGroup, startValues: TransitionValues?, endValues: TransitionValues?): Animator? {
            return when {
                startValues?.view is RectView && endValues?.view is RectView -> {
                    val startColor: Int = startValues.values[propertyColor] as Int
                    val endColor: Int = endValues.values[propertyColor] as Int
                    val startRadius = startValues.values[propertyRadius] as Float
                    val endRadius = endValues.values[propertyRadius] as Float
                    val rectView = endValues.view as RectView
                    var radiusAnimator : Animator? = null
                    var argbAnimator : Animator? = null
                    if (startRadius != endRadius) {
                        rectView.radius = startRadius
                        radiusAnimator = createRadiusAnimator(rectView, startRadius, endRadius)
                    }
                    if (startColor != endColor) {
                        rectView.color = startColor
                        argbAnimator = createArgbAnimator(rectView, startColor, endColor)
                    }
                    when {
                        radiusAnimator != null && argbAnimator != null -> {
                            AnimatorSet().apply {
                                playTogether(radiusAnimator, argbAnimator)
                            }
                        }
                        else -> radiusAnimator ?: argbAnimator
                    }
                }
                else -> null
            }
        }
    
        private fun createRadiusAnimator(target: Any, vararg radius : Float): Animator
                = ObjectAnimator.ofFloat(target, "radius", *radius)
    
    
        private fun createArgbAnimator(target: Any, vararg colors: Int): Animator {
            return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                ObjectAnimator.ofArgb(target, "color", *colors)
            } else {
                ObjectAnimator.ofInt(target, "color", *colors).apply {
                    setEvaluator(ArgbEvaluator.instance)
                }
            }
        }
    }
    
    
    

    效果图:

    ChangeBounds and ChangeRectRadiusAndColor效果图ChangeBounds and ChangeRectRadiusAndColor效果图
    完整代码github

    上一篇:Android过渡动画Scene and Transition(一):使用Transition框架实现场景过渡动画

    下一篇:Android过渡动画Scene and Transition(三):Transition的辅助工具

    相关文章

      网友评论

          本文标题:Android过渡动画Scene and Transition(

          本文链接:https://www.haomeiwen.com/subject/jwdkoftx.html