kotlin实现Android动画-阿里云开发者社区

开发者社区> 开发与运维> 正文
登录阅读全文

kotlin实现Android动画

简介:

属性动画

简述

在手机上去实现一些动画效果算是件比较炫酷的事情,因此Android系统在一开始的时候就给我们提供了两种实现动画效果的方式,逐帧动画(frame-by-frame animation)和补间动画(tweened animation)。逐帧动画的工作原理很简单,其实就是将一个完整的动画拆分成一张张单独的图片,然后再将它们连贯起来进行播放,类似于动画片的工作原理。补间动画则是可以对View进行一系列的动画操作,包括淡入淡出、缩放、平移、旋转四种。
然而自Android 3.0版本开始,系统给我们提供了一种全新的动画模式,属性动画(property animation),它的功能非常强大,弥补了之前补间动画的一些缺陷,几乎是可以完全替代掉补间动画了。对于逐帧动画和补间动画的用法,我不想再多讲,它们的技术已经比较老了,而且网上资料也非常多,那么今天我们这篇文章的主题就是对Android属性动画进行一次完全解析。
为什么要引入属性动画?
Android之前的补间动画机制其实还算是比较健全的,在android.view.animation包下面有好多的类可以供我们操作,来完成一系列的动画效果,比如说对View进行移动、缩放、旋转和淡入淡出,并且我们还可以借助AnimationSet来将这些动画效果组合起来使用,除此之外还可以通过配置Interpolator来控制动画的播放速度等等等等。那么这里大家可能要产生疑问了,既然之前的动画机制已经这么健全了,为什么还要引入属性动画呢?
其实上面所谓的健全都是相对的,如果你的需求中只需要对View进行移动、缩放、旋转和淡入淡出操作,那么补间动画确实已经足够健全了。但是很显然,这些功能是不足以覆盖所有的场景的,一旦我们的需求超出了移动、缩放、旋转和淡入淡出这四种对View的操作,那么补间动画就不能再帮我们忙了,也就是说它在功能和可扩展方面都有相当大的局限性,那么下面我们就来看看补间动画所不能胜任的场景。
注意上面我在介绍补间动画的时候都有使用“对View进行操作”这样的描述,没错,补间动画是只能够作用在View上的。也就是说,我们可以对一个Button、TextView、甚至是LinearLayout、或者其它任何继承自View的组件进行动画操作,但是如果我们想要对一个非View的对象进行动画操作,抱歉,补间动画就帮不上忙了。可能有的朋友会感到不能理解,我怎么会需要对一个非View的对象进行动画操作呢?这里我举一个简单的例子,比如说我们有一个自定义的View,在这个View当中有一个Point对象用于管理坐标,然后在onDraw()方法当中就是根据这个Point对象的坐标值来进行绘制的。也就是说,如果我们可以对Point对象进行动画操作,那么整个自定义View的动画效果就有了。显然,补间动画是不具备这个功能的,这是它的第一个缺陷。
然后补间动画还有一个缺陷,就是它只能够实现移动、缩放、旋转和淡入淡出这四种动画操作,那如果我们希望可以对View的背景色进行动态地改变呢?很遗憾,我们只能靠自己去实现了。说白了,之前的补间动画机制就是使用硬编码的方式来完成的,功能限定死就是这些,基本上没有任何扩展性可言。
最后,补间动画还有一个致命的缺陷,就是它只是改变了View的显示效果而已,而不会真正去改变View的属性。什么意思呢?比如说,现在屏幕的左上角有一个按钮,然后我们通过补间动画将它移动到了屏幕的右下角,现在你可以去尝试点击一下这个按钮,点击事件是绝对不会触发的,因为实际上这个按钮还是停留在屏幕的左上角,只不过补间动画将这个按钮绘制到了屏幕的右下角而已。
也正是因为这些原因,Android开发团队决定在3.0版本当中引入属性动画这个功能,那么属性动画是不是就把上述的问题全部解决掉了?下面我们就来一起看一看。
新引入的属性动画机制已经不再是针对于View来设计的了,也不限定于只能实现移动、缩放、旋转和淡入淡出这几种动画操作,同时也不再只是一种视觉上的动画效果了。它实际上是一种不断地对值进行操作的机制,并将值赋值到指定对象的指定属性上,可以是任意对象的任意属性。所以我们仍然可以将一个View进行移动或者缩放,但同时也可以对自定义View中的Point对象进行动画操作了。我们只需要告诉系统动画的运行时长,需要执行哪种类型的动画,以及动画的初始值和结束值,剩下的工作就可以全部交给系统去完成了。
既然属性动画的实现机制是通过对目标对象进行赋值并修改其属性来实现的,那么之前所说的按钮显示的问题也就不复存在了,如果我们通过属性动画来移动一个按钮,那么这个按钮就是真正的移动了,而不再是仅仅在另外一个位置绘制了而已。
好了,介绍了这么多,相信大家已经对属性动画有了一个最基本的认识了,下面我们就来开始学习一下属性动画的用法。

核心类

  • ValueAnimator:该类是Animator的子类,实现了动画的整个处理逻辑也是属性动画的核心类
  • ObjectAnimator:对象属性动画的操作类,继承自ValueAnimator,通过该类使用动画的形式操作对象的属性
  • TimeInterpolator:时间插值器,他的作用是根据时间流逝的百分比来计算出当前属性值改变的百分比,系统预置的有线性插值器(LinearInterpolator)、加速插值器(AccelerateDeceleratenterpolator)和减速插值器(DecelerateInterpolator)等。
  • TypeEvaluator:TypeEvaluator的中文为类型估值算法,他的作用是根据当前属性改变的百分比来计算改变后的属性值,系统预支的有针对整形属性(IntEvaluator)、针对浮点型(FloatEvaluator)和针对Color属性(ArgbEvaluator)
  • Property:属性对象,主要是定义了属性的set和get方法。
  • PropertyValuesHolder: PropertyValuesHolder是持有目标属性Property、setter和getter方法以及关键帧的集合
  • KeyframeSet:储存一个动画的关键帧集合。
  • AnimotionProxy:再3.0以下使用View的属性动画的辅助类

基本使用

这是一个让textview点击向下移动的demo
效果展示

2017-12-08 16.42.48.gif

xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="transformation.numberutils.wushaocong.manimotor.MainActivity">
    
    <TextView
        android:text="移动"
        android:textSize="20sp"
        android:layout_centerInParent="true"
        android:id="@+id/mtext"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</RelativeLayout>
kotlin:
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        var y = 100f
        mtext.setOnClickListener { v ->
            ObjectAnimator.ofFloat(v, "translationY", y).start()
            y+=100f
        }
    }
}

这是一个将textview的背景3秒钟从0xF000000变为0xF00ffff 无限播放且有反转效果

2017-12-09 10.45.20.gif

直接把刚才的代码修改为

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        var y = 100f
        mtext.setOnClickListener { v ->
            val colorAnimator = ObjectAnimator.ofInt(v,"backgroundColor",0xF000000,0xF00ffff)
            //设置动画时间
            colorAnimator.setDuration(3000)
            //设置插值器
            colorAnimator.setEvaluator(ArgbEvaluator())
            //设置播放次数为无限
            colorAnimator.repeatCount = ValueAnimator.INFINITE
            //播放完成之后反转
            colorAnimator.repeatMode = ValueAnimator.REVERSE
            colorAnimator.start()
        }
    }
}
  • 最后再来一个终极的动画组合

2017-12-08 17.25.36.gif

将代码修改为:


class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        var y = 100f
        mtext.setOnClickListener { v ->
            var animators = listOf<ObjectAnimator>(
                    ObjectAnimator.ofFloat(v,"rotationX",0f,360f),
                    ObjectAnimator.ofFloat(v,"rotationY",0f,180f),
                    ObjectAnimator.ofFloat(v,"rotation",0f,-90f),
                    ObjectAnimator.ofFloat(v,"translationX",0f,90f),
                    ObjectAnimator.ofFloat(v,"translationY",0f,90f),
                    ObjectAnimator.ofFloat(v,"scaleY",1f,1.5f),
                    ObjectAnimator.ofFloat(v,"scaleX",1f,0.5f),
                    ObjectAnimator.ofFloat(v,"alpha",0f,1f,0.25f,1f)
            )
            val set  = AnimatorSet()
            set.playTogether(animators)
            set.setDuration(6*1000).start()
        }
    }
}

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
开发与运维
使用钉钉扫一扫加入圈子
+ 订阅

集结各类场景实战经验,助你开发运维畅行无忧

其他文章
最新文章
相关文章