属性动画(Property Animation)

内容如下:
  • 属性动画与补间动画的不同
  • 属性动画工作原理
  • API 概述
  • 计算器 Evaluators
  • 插值器 Interpolators
  • 使用ValueAnimator
  • 使用ObjectAnimator
  • AnimatorSet
  • 动画监听
  • 视图容器中布局的动画改变
  • 使用TypeEvaluator
  • 使用插值器 (Interpolators)
  • 关键帧
  • ViewPropertyAnimator
  • 声明XML

属性动画与补间动画的不同

补间动画只提供了运动可视对象的能力,如果你想操作非可视对象,就不得不自己用代码实现。实际上,补间动画具有局限性,它只能够使一个视图对象的几个方面做运动,比如:视图的缩放、旋转,而不能操作背景颜色等等。

补间动画另一个缺点是:它只能够改变视图绘制的位置,并不能改变它的真实位置。例如:你在屏幕中运动一个按钮,按钮将被正确的绘制,但是当你点击当前位置的按钮时,按钮并不会有任何改变。所以你不得不通过实现自己的逻辑来操作它。

对于属性动画而言,这些限制被全部移除。你能够使任何对象(可视和非可视)的任何属性运动,并且对象自身被修改。属性动画就是通过不停修改属性值实现动画效果的。属性动画在实现动画方面更加强大。你可以根据需求将动画分派给对象的属性,比如:颜色、位置、大小;你也可以定义动画的差值器以及多动画的同步。

不管怎样,补间动画的创建可以用更少的时间和更少的代码。如果补间动画能够完成你需要的每件事,或者代码中已存在的补间动画代码能够实现你的需求。你就没必要使用属性动画。通过不同的使用场景来确定使用两种动画系统的哪一种。


属性动画工作原理

图1描述了一个假想的对象,沿x轴运动,表示它在屏幕上的水平位置。在40ms内运动40px,每10毫秒(默认帧刷新率),对象水平移动10像素。到40ms时,动画结束。对象停在40px处。这是一个线性插值动画的例子,表示对象匀速运动。

image.png

还可以指定具有非线性插值的动画。图2假设一个对象,在动画开始时加速,然后减速动画结束时。该对象仍然在40ms移动40px,但非线性。

image.png

属性动画系统的重要组件如何计算上面提到的动画:
image.png

ValueAnimator 对象保持跟踪动画的时间,比如动画的已运动时间和动画的当前值。
TimeInterpolator 定义动画的插值器。
TypeEvaluator 定义如何计算动画属性的值。

开始一个动画:

  • 创建一个ValueAnimator并给它的开始属性值、结束属性值以及动画的持续时间。
  • 调用start()开始动画。
  • ValueAnimator计算一个在0和1之间的逝去分数,基于动画的持续时间和经过的多少时间。该分数表示动画完成的时间百分比,0表示0%,1表示100%。
  • 当ValueAnimator完成计算一个逝去分数,它调用当前设置的TimeInterpolator计算插值分数。
  • 当插值分数计算完成,ValueAnimator调用合适的TypeEvaluator,计算该属性的值,基于插值分数、起始值和动画结束值。

API 概述
  • ValueAnimator 属性动画的计时引擎,通过属性值进行动画处理。包括计算动画值的核心功能,动画随时间变化的细节,动画重复监听以及更新时间,自定义evaluate。属性动画包括两部分:1.计算动画值;2.对正在进行动画的对象设置这些值。ValueAnimator不能直接完成第二部分,所以必须在UpdateListener中更新属性值。

  • ObjectAnimator ValueAnimator的子类,可以直接设置目标对象和属性进行动画。ObjectAnimator使用起来更方便,也有限制,对于进行的动画的属性必须要有setter,getter的访问方法。

  • AnimatorSet 提供一种将多动画分组并使之关联运行的机制。可以使动画同时执行,顺序执行,延时执行。


估算器 Evaluators
  • IntEvaluator 计算int型属性
  • FloatEvaluator 计算float型属性
  • ArgbEvaluator 计算16进制的颜色值
  • TypeEvaluator 自定义计算器(更多见下文)

插值器 Interpolators
  • AccelerateDecelerateInterpolator 先加速后减速
  • AccelerateInterpolator 加速
  • AnticipateInterpolator 向相反运动一小段后再开始运行
  • AnticipateOvershootInterpolator 前后都超出一小段
  • BounceInterpolator 结束时振动结束
  • CycleInterpolator 往返运行动画
  • DecelerateInterpolator 减速运行
  • LinearInterpolator 匀速运行
  • OvershootInterpolator 结束时超出一小段
  • TimeInterpolator 自定义

使用ValueAnimator

示例:使用ValueAnimator做曲线运动

通过调用ofInt(),ofFloat(),ofObject()方法获得一个ValueAnimator,如下:

ValueAnimator animation = ValueAnimator.ofFloat(0f, 100f);
animation.setDuration(1000);
animation.start();

还可以通过以下操作指定一个自定义类型来进行动画:

ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator(), startPropertyValue, 
 endPropertyValue);
animation.setDuration(1000);
animation.start();

上述代码,当调用start()时,ValueAnimator 将在1s内计算0-1之间的动画值。它只是在计算一个值并没有影响到一个具体的对象。你需要实现ValueAnimator.AnimatorUpdateListener这个接口,通过调用getAnimatedValue()方法可以获得特定帧的计算值,通过这个值可以对目标对象进行需要的变换。

animation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator updatedAnimation) {
    // You can use the animated value in a property that uses the
    // same type as the animation. In this case, you can use the
    // float value in the translationX property.
        float animatedValue = (float)updatedAnimation.getAnimatedValue();
        textView.setTranslationX(animatedValue);
    }
});

使用ObjectAnimator

示例:卫星菜单

ObjectAnimator animation = ObjectAnimator.ofFloat(textView, "translationX", 100f);
animation.setDuration(1000);
animation.start();

拥有setter,getter方法的属性都可以进行动画操作。
经常操作的属性:

“alpha” 透明度;

“translationY” 沿Y轴平移;

“translationX” 沿X轴平移;

“scaleX” 横向缩放;

“scaleY” 纵向缩放;

“rotation” 平面旋转;

“rotationX” 关于X轴旋转;

“rotationY” 关于Y轴旋转;


AnimatorSet

你可以使用AnimatorSet控制多个Animator的播放顺序,同时播放,顺序播放,谁在前谁在后等。可以嵌套使用。例:

AnimatorSet bouncer = new AnimatorSet();
bouncer.play(bounceAnim).before(squashAnim1);
bouncer.play(squashAnim1).with(squashAnim2);
bouncer.play(squashAnim1).with(stretchAnim1);
bouncer.play(squashAnim1).with(stretchAnim2);
bouncer.play(bounceBackAnim).after(stretchAnim2);
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(bouncer).before(fadeAnim);
animatorSet.start();

常用方法:
playSequentially (Animator…) 顺序播放;
playTogether (Animator…) 一起播放;

Builder方式:
play(Animator a);
创建一个Builder对象;

例1:有四个动画anim1, amin2, anim3,anim4。anim1和anim2同时播放;当anim2播放结束时播放anim3;当anim3播放结束时播放anim4。

 AnimatorSet s = new AnimatorSet();
 s.play(anim1).with(anim2);
 s.play(anim2).before(anim3);
 s.play(anim4).after(anim3);

动画监听

Animator.AnimatorListener
* onAnimationStart() 动画开始时
* onAnimationEnd() 动画结束时
* onAnimationRepeat() 动画重复时
* onAnimationCancel() 动画取消时,同时调用onAnimationEnd()

ValueAnimator.AnimatorUpdateListener
* onAnimationUpdate() 每帧动画都将被调用
通过getAnimatedValue()方法获取动画值。

AnimatorListenerAdapter

ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
fadeAnim.addListener(new AnimatorListenerAdapter() {
    public void onAnimationEnd(Animator animation) {
        balls.remove(((ObjectAnimator)animation).getTarget());
    }
)};

视图容器中布局的动画改变
使用TypeEvaluator

如果你想以系统未知的方式运动,你可以通过实现TypeEvaluator接口来创建。实现TypeEvaluator接口只需要实现一个方法evaluate()。如下:

public class FloatEvaluator implements TypeEvaluator {
    public Object evaluate(float fraction, Object startValue, Object endValue) {
        float startFloat = ((Number) startValue).floatValue();
        return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
    }
}

例:使TextView沿正弦曲线运动

创建包装类:

   private class TextHolder
        private TextView view;
        public TextHolder(TextView textView){
            view=textView;
        }
        public XYHolder getXY() {
            return new XYHolder(view.getX(),view.getY());
        }

        public void setXY(XYHolder xyHolder) {
            view.setX(xyHolder.getX());
            view.setY(xyHolder.getY());
        }
    }

估值器:

public class SineTypeEvaluator implements TypeEvaluator<XYHolder> {
    @Override
    public XYHolder evaluate(float fraction, XYHolder startValue, XYHolder endValue) {
        float xHolder=startValue.getX()+fraction*(endValue.getX()-startValue.getX());
        float yHolder=(float) (300*Math.sin(xHolder/100)+endValue.getY());
        return new XYHolder(xHolder,yHolder );
    }
}

开始动画:

ObjectAnimator objectAnimator=ObjectAnimator.ofObject(new TextHolder(mText1),"xY",new 
SineTypeEvaluator(),new XYHolder(0f,400f),new XYHolder(628f,400f));
        objectAnimator.setDuration(2000);
        objectAnimator.start();
使用插值器

一个随时间计算动画值的函数

AccelerateDecelerateInterpolator

public float getInterpolation(float input) {
    return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}

LinearInterpolator

public float getInterpolation(float input) {
    return input;
}
关键帧

例如:

Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);
Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation)
rotationAnim.setDuration(5000ms);
ViewPropertyAnimator

ViewPropertyAnimator提供一种更简单的多属性运动的方式。如下对比:

使用多个ObjectAnimator:

ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();

使用一个ObjectAnimator:

PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();

使用ViewPropertyAnimator:

myView.animate().x(50f).y(100f);</pre>
声明XML

将xml文件保存在res/animator/ 目录下

动画类与xml标签的对应关系:
ValueAnimator -
ObjectAnimator -
AnimatorSet-

下面的示例依次播放两组对象动画,第一个动画集合同时播放两个对象动画:

<set android:ordering="sequentially">
    <set>
        <objectAnimator
            android:propertyName="x"
            android:duration="500"
            android:valueTo="400"
            android:valueType="intType"/>
        <objectAnimator
            android:propertyName="y"
            android:duration="500"
            android:valueTo="300"
            android:valueType="intType"/>
    </set>
    <objectAnimator
        android:propertyName="alpha"
        android:duration="500"
        android:valueTo="1f"/>
</set>

运行上述动画:

AnimatorSet set = (AnimatorSet) 
    AnimatorInflater.loadAnimator(myContext,R.anim.property_animator);
set.setTarget(myObject);
set.start();

在XML中声明ValueAnimator:

<animator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:valueType="floatType"
    android:valueFrom="0f"
    android:valueTo="-100f" />

ValueAnimator必须实现AnimatorUpdateListener,如下:

ValueAnimator xmlAnimator = (ValueAnimator) AnimatorInflater.loadAnimator(this,
    R.animator.animator);
xmlAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator updatedAnimation) {
        float animatedValue = (float)updatedAnimation.getAnimatedValue();
        textView.setTranslationX(animatedValue);
    }
});
xmlAnimator.start();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值