Property Animator 提高部分

参考:

  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
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容