美文网首页
Property Animator 提高部分

Property Animator 提高部分

作者: zhaoyubetter | 来源:发表于2018-03-22 23:00 被阅读14次

    参考:

    1. http://blog.csdn.net/harvic880925/article/details/50759059
      非常感谢;

    联合动画 AnimatorSet

    ValueAnimator和ObjectAnimator都只能单单实现一个动画,如果要多个效果,如:边放大,边改变颜色,边移动,或者顺序播放等,这个时候,就需要用到AnimatorSet,组合型动画了;

    View动画对应的为AnimationSet

    AnimatorSet

    1. playSequentially 多个动画顺序播放;
    2. playTogether 多个动画同时播放;
    val animator1 = ObjectAnimator.ofFloat(text1, "translationY", 0f, 300f, 0f).setDuration(1000)
    val animator2 = ObjectAnimator.ofFloat(text2, "rotation", 0f, -180f, +180f, 0f).setDuration(1000)
    
    btn_seque.setOnClickListener {
                AnimatorSet().apply {
                    duration = 2000
                    playSequentially(animator1, animator2)
                }.start()
            }
    
    btn_together.setOnClickListener {
                AnimatorSet().apply {
                    duration = 2000
                    playTogether(animator1, animator2)
                }.start()
            }
    

    playSequentially 与 playTogether说明,源博客的例子举得很好

    • playTogether和playSequentially在激活动画后,控件的动画情况与它们无关,他们只负责定时激活控件动画。
    • playSequentially只有上一个控件做完动画以后,才会激活下一个控件的动画,如果上一控件的动画是无限循环,那下一个控件就别再指望能做动画了。

    自由设置动画顺序 - AnimatorSet.Builder

    对于3个动画A,B,C要实现A播放后,同时播放B与C,这个时候,就需要用到AnimatorSet.Builder了;

    播放1后,再2,3同时播放:

       // AnimatorSet.Builder
            btn_builder.setOnClickListener {
                AnimatorSet().apply {
                    val builder = play(animator2).with(animator3)
                    builder.after(animator1)
                }.start()
            }
    

    AnimatorSet.Builder

    通过animatorSet.play(animator2)生成Builder对象,这是生成AnimatorSet.Builder对象的唯一途径;
    一些控制动画播放顺序的方法如下:

    //和前面动画一起执行
    public Builder with(Animator anim)
    //执行前面的动画后才执行该动画
    public Builder before(Animator anim)
    //执行先执行这个动画再执行前面动画
    public Builder after(Animator anim)
    //延迟n毫秒之后执行动画
    public Builder after(long delay)
    

    play(Animator anim)表示当前在播放哪个动画,另外的with(Animator anim)、before(Animator anim)、after(Animator anim)都是以play中的当前所播放的动画为基准的;

    AnimatorSet.Builder 监听器

    AnimatorSet().apply {
                    val builder = play(animator2).with(animator3)
                    builder.after(animator1)
                    addListener(object : Animator.AnimatorListener {
                        override fun onAnimationRepeat(animation: Animator?) {
                        }
                        override fun onAnimationEnd(animation: Animator?) {
                        }
                        override fun onAnimationCancel(animation: Animator?) {
                        }
                        override fun onAnimationStart(animation: Animator?) {
                        }
                    })
                }.start()
    

    因为ValueAnimator和AnimatorSet都派生自Animator类,而AnimatorListener是Animator类中的函数;

    AnimatorSet的监听说明:

    • AnimatorSet的监听函数也只是用来监听AnimatorSet的状态的,与其中的动画无关;
    • AnimatorSet中没有设置循环的函数,所以AnimatorSet监听器中永远无法运行到onAnimationRepeat()中!

    分享的时候,现场写代码;

    动画逐个设置与AnimatorSet设置的区别

    AnimatorSet设置的几个方法:

    //设置单次动画时长
    public AnimatorSet setDuration(long duration);
    //设置加速器
    public void setInterpolator(TimeInterpolator interpolator)
    //设置ObjectAnimator动画目标控件
    public void setTarget(Object target)
    

    对应的单个ObjectAnimator也可以设置这些参数,AnimatorSet中设置与在单个ObjectAnimator中的区别如下:

    在AnimatorSet中设置以后,会覆盖单个ObjectAnimator中的设置;即如果AnimatorSet中没有设置,那么就以ObjectAnimator中的设置为准。如果AnimatorSet中设置以后,ObjectAnimator中的设置就会无效。

    setTarget的覆盖

    // AnimatorSet.Builder会覆盖具体的ObjectAnimator设置
    btn_builder_target.setOnClickListener {
        AnimatorSet().apply {
        duration = 5000     // 覆蓋
        playTogether(animator1,animator2,animator3)
        setTarget(text1)    // 這個setTarget必須放在這裡,放在playTogether之前無效
        }.start()
    }
    

    注意:setTarget位置,放在了最后,这样才能确保将动画的目标统一设置为当前控件;

    setStartDelay

    设置延迟开始动画组;setStartDelay函数不会覆盖单个动画的延时,而且仅针对性的延长AnimatorSet的激活时间,单个动画的所设置的setStartDelay仍对单个动画起作用。

    btn_delay.setOnClickListener {
        animator1.startDelay = 2000
        AnimatorSet().apply {
        duration = 2000
        startDelay = 2000
        play(animator1).with(animator2)
        }.start()
    }
    

    整体延迟2s后,再开始animator2,animtor1



    通过xml实现ValueAnimator、ObjectAnimator,AnimatorSet

    在xml中对应animator总共有三个标签:

    • <animator />:对应ValueAnimator
    • <objectAnimator />:对应ObjectAnimator
    • <set />:对应AnimatorSet

    View动画标签相对多几个;对比Vew动画,animator相关的xml放在 animator文件夹下:

    animator与anim

    Animator

    对应ValueAnimator

    <animator
        android:duration="int"
        android:valueFrom="float | int | color"
        android:valueTo="float | int | color"
        android:startOffset="int"
        android:repeatCount="int"
        android:repeatMode=["repeat" | "reverse"]
        android:valueType=["intType" | "floatType"]
        android:interpolator=["@android:interpolator/XXX"]/>
    

    字段解释,参考原博客
    http://blog.csdn.net/harvic880925/article/details/50763286

    Animator xml 动画实现过程:

    1. 建立Animator动画文件;
    2. 通过AnimatorInflater装载,并强制类型转换;
    3. 绑定到对象并播放动画;
    // 动画xml,类似 ValueAnimator.ofInt(0,300) 
    <animator xmlns:android="http://schemas.android.com/apk/res/android"
        android:valueFrom="0"
        android:valueTo="300"
        android:duration="1000"
        android:valueType="intType"
        android:interpolator="@android:anim/bounce_interpolator">
    </animator>
    
    // 装载动画
    val animator1 = AnimatorInflater.loadAnimator(baseContext, R.animator.property_animator)
        as ValueAnimator        // 强转一下
    
    // 播放
    btn_start.setOnClickListener {
        animator1.apply {
        addUpdateListener { it ->
            val offset = it.animatedValue as Int        //
            text.layout( offset,offset,text.width+offset,text.height + offset)
        }
        }.start()
    }
    

    xml中根属性是<animator/>所以它对应的是ValueAnimator,所以在加载后,将其强转为valueAnimator;然后对其添加控件监听。

    objectAnimator

    <objectAnimator
        android:propertyName="string"
        android:duration="int"
        android:valueFrom="float | int | color"
        android:valueTo="float | int | color"
        android:startOffset="int"
        android:repeatCount="int"
        android:repeatMode=["repeat" | "reverse"]
        android:valueType=["intType" | "floatType"]
        android:interpolator=["@android:interpolator/XXX"]/>
    

    字段的解释原博客很详细;

    使用方法与ValueAnimator类似,需要一个target

     // 装置ObjectAnimator动画
    val animator2 = AnimatorInflater.loadAnimator(baseContext, R.animator.property_object_animator) as ObjectAnimator
    btn_start_object.setOnClickListener {
        animator2.target = text
        animator2.start()
    }
    

    set

    这个是AnimatorSet所对应的标签。它只有一个属性:

    <set android:ordering=["together" | "sequentially"]>
    
    // 装载set
    val set = AnimatorInflater.loadAnimator(baseContext, R.animator.property_set_animator) as AnimatorSet
    btn_set.setOnClickListener {
            set.setTarget(text)
            set.start()
    }
    

    总结

    对于属性动画用代码来创建,比xml装载更便捷,直观;

    例子:旋转菜单:

      fun toggle() {
            // 1.分别获取各个按钮的位置 5个按钮,4个角度平分90度
            val degree = 90 * 1.0f / 4
            val totalSet = AnimatorSet()
            (0..4).forEach { it ->
                // 获取x , y 坐标
                val radians = Math.toRadians(degree * it.toDouble())
                val delay = it * 50.toLong()
                val duration = 1000L
                val target = find<View>(baseContext.resources.getIdentifier("btn_${it}", "id", packageName))
    
                val x = -radius!! * Math.sin(radians).toFloat()
                val y = -radius!! * Math.cos(radians).toFloat()
    
                lateinit var obj1: ObjectAnimator
                lateinit var obj2: ObjectAnimator
                lateinit var obj3: ObjectAnimator
                lateinit var obj4: ObjectAnimator
                lateinit var obj5: ObjectAnimator
                lateinit var obj6: ObjectAnimator
    
                if (!isOpen) {
                    target.visibility = View.VISIBLE
                    obj1 = ObjectAnimator.ofFloat(target, "translationX", 0f, x)
                    obj2 = ObjectAnimator.ofFloat(target, "translationY", 0f, y)
                    obj3 = ObjectAnimator.ofFloat(target, "scaleX", 0.1f, 1.0f)
                    obj4 = ObjectAnimator.ofFloat(target, "scaleY", 0.1f, 1.0f)
                    obj5 = ObjectAnimator.ofFloat(target, "alpha", 0.5f, 1.0f)
                    obj6 = ObjectAnimator.ofFloat(target, "rotation", 0f, 720f)
                    obj6.addUpdateListener {
                        if (it.animatedFraction >= 1.0f) isOpen = true
                    }
                } else {
                    obj1 = ObjectAnimator.ofFloat(target, "translationX", x, 0f)
                    obj2 = ObjectAnimator.ofFloat(target, "translationY", y, 0f)
                    obj3 = ObjectAnimator.ofFloat(target, "scaleX", 1.0f, 0.1f)
                    obj4 = ObjectAnimator.ofFloat(target, "scaleY", 1.0f, 0.1f)
                    obj5 = ObjectAnimator.ofFloat(target, "alpha", 1.0f, 0.5f)
                    obj6 = ObjectAnimator.ofFloat(target, "rotation", 0f, 720f)
                    obj6.addUpdateListener {
                        if (it.animatedFraction >= 1.0f) {
                            target.visibility = View.GONE
                            isOpen = false
                        }
                    }
                }
    
                totalSet.playTogether(AnimatorSet().apply {
                    setDuration(duration)
                    startDelay = delay
                    playTogether(obj1, obj2, obj3, obj4, obj5, obj6)
                })
                totalSet.start()
            }
        }
    
    image.png

    相关文章

      网友评论

          本文标题:Property Animator 提高部分

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