Android基础动画实现和剖析

本文原创:转载请声明出处

Android动画共有三大类:

1.补间动画(Tween 动画),补间动画仅仅提供了四种动画API类,都是Animation的子类,分别为:渐变(AlphaAtion),缩(ScaleAnimation),旋转(RotateAnimation),位移(TranslateAnimation)。这种动画都只是针对View作为对象在视觉上发生的改变,实质上View的属性并未发生改变,比如说位移动画,当你把View移动到别的位置的时候,View的点击事件不会跟着移动,还在View原先所在的地方

xml指定动画效果:

res下创建anim文件夹创建translate.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">

    <translate
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:toXDelta="400"
        android:toYDelta="0" />
</set>
书写布局文件,用原生的ImageView就好,我这儿是用了一个自定义的ImageView
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:dragon="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#0000FF">

    <!-- xmlns:dragon="http://schemas.android.com/apk/res-auto" 注意看上面的这句话,是用于引用自定义的属性,不可丢 -->

    <com.picovr.animatordemo.CircleImage
        android:id="@+id/iv_animator"
        android:layout_width="120dp"
        android:layout_height="120dp"
        android:src="@drawable/e"
        dragon:borderColor="#000000"
        dragon:borderWidth="4dp"
        dragon:hasBorder="true" />
</RelativeLayout>
关联ImageView和动画集,并启动动画
private void animation(final View view) {

    Animation animation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.translate);
    animation.setDuration(5 * 1000);
    animation.setFillAfter(true);
    view.startAnimation(animation);
}

Java代码指定动画效果:

书写布局文件,跟xml方式的布局一样,有一个ImageView就行

java代码

iv_animator = ((CircleImage) findViewById(R.id.iv_animator));

WindowManager windowManager = (WindowManager) getSystemService(Service.WINDOW_SERVICE);

Display defaultDisplay = windowManager.getDefaultDisplay();
Point point = new Point();
defaultDisplay.getSize(point);
screenWidth = point.x;
screenHeight = point.y;

TranslateAnimation animation = new TranslateAnimation(0, screenWidth - iv_animator.getWidth(), 0, 0);
animation.setDuration(10 * 1000);
animation.setFillAfter(true);
iv_animator.startAnimation(animation);

另外,可以对图片写个监听,在监听方法中打log,让图片移走之后,点击图片原先所在位置和移动之后的位置,观察log,有礼物。

效果附上

   

2.帧动画(Frame动画),一组图片,以电影集的形式播放出来,这种动画极容易引起OOM,在使用时一定注意,性能的优化。

drawable下创建animation.xml文件,这里指定播放的图片和播放时长

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">


    <item
        android:drawable="@drawable/a"
        android:duration="1500" />
    <item
        android:drawable="@drawable/b"
        android:duration="1500" />
    <item
        android:drawable="@drawable/c"
        android:duration="1500" />
    <item
        android:drawable="@drawable/timg"
        android:duration="1500" />
    <item
        android:drawable="@drawable/timgs"
        android:duration="1500" />
    <item
        android:drawable="@drawable/d"
        android:duration="1500" />
    <item
        android:drawable="@drawable/e"
        android:duration="1500" />
    <item
        android:drawable="@drawable/f"
        android:duration="1500" />
    <item
        android:drawable="@drawable/g"
        android:duration="1500" />


</animation-list>
书写布局文件,这儿来一个ImageView,用原生的ImageView即可,我这儿是用了一个自定义的ImageView
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:dragon="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#0000FF">

    <!-- xmlns:dragon="http://schemas.android.com/apk/res-auto" 注意看上面的这句话,是用于引用自定义的属性,不可丢 -->

    <com.picovr.animatordemo.CircleImage
        android:id="@+id/iv_animator"
        android:layout_width="320dp"
        android:layout_height="320dp"
        android:layout_centerInParent="true"
        dragon:borderColor="#000000"
        dragon:borderWidth="4dp"
        dragon:hasBorder="true" />
</RelativeLayout>
调用API关联上ImageView和动画集,并启动动画
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    iv_animator = ((CircleImage) findViewById(R.id.iv_animator));

    iv_animator.setImageResource(R.drawable.animation_list);
    final AnimationDrawable animation = (AnimationDrawable) iv_animator.getDrawable();
    animation.start();

    iv_animator.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            Log.i("MainActivity", "onClick  :");
            animation.stop();
        }
    });
}

    3.属性动画(Property动画),这种动画跟帧动画在视觉上效果差不多,但是不同的是它直接以View的某一个属性作为对象改变,产生视觉上的改变,并且View的属性会跟着改变属性动画的机制其实就是对值的不断操作,给定一个初始值,一个结束值,过度时长,然后一点点平滑的过度的一个过程。


ValueAnimator详解:

ValueAnimator是直接对值进行操作,比起ObjectAnimator更接近底层,实现简单动画很简单,提供ofFloat方法,和ofInt方法,指定一组数值,动画效果其实就是这一组数值的一个过度过程。代码说话:

/**
 * 本来是一个自由落体运动的动画,重复模式,就变成来回晃荡了
 *
 * @param view
 */
public void verticalRun(final View view) {

    //ofFloat中给定了两个值,起始值为0,结束值为屏幕高度减去视图的高度,这儿其实参数可以不止两个
    ValueAnimator animator = ValueAnimator.ofFloat(0, screenHeight - view.getHeight());
    //设定执行动画的对象
    animator.setTarget(view);
    //过度时长
    animator.setDuration(2000);
    //重复次数
    animator.setRepeatCount(10);
    //重复的模式,这儿反着播放模式
    animator.setRepeatMode(ValueAnimator.REVERSE);

    animator.start();
    //监听动画的改变
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {

            //这个值就是当前动画所在的值
            float values = (float) animation.getAnimatedValue();

            Log.i("MainActivity", "onAnimationUpdate values :" + values);
            view.setTranslationY(values);
        }
    });
}
效果:



ObjectAnimator详解:

ObjectAnimator是平时我们用的比较多的,ObjectAnimator直接针对任意对象的任意属性进行操作。针对对象的某个属性,其实就是通过属性对应的get,set方法直接对属性进行操作。ofFloat,ofInt方法中的第二个参数,就是需要改变的属性。ObjectAnimator其实是继承了ValueAnimation,相当于封装了一层,更能表达面向对象的思想。当然了,既然他继承了ValueAnimation,那他们的用法就及其相似了,但是针对简单动画来说ObjectAnimator用起来会更简单,不一定要想ValueAnimator那样一定要在监听中去操作。

旋转动画

public void rotationY(final View view) {

    //ObjectAnimator提供ofFloat方法可以很快实现动画,Y方向旋转180    ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotationY", 0.0F, 180.0F).setDuration(1000);
    //X方向旋转180    // ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotationY", 0.0F, 180.0F).setDuration(1000);
    animator.start();
}

位移动画

public void translateX(final View view) {

    //ObjectAnimator提供ofFloat方法可以很快实现动画,Y方向旋转180    ObjectAnimator animator = ObjectAnimator.ofFloat(view, "translationX", 0.0F, 360.0F).setDuration(1000);
    //X方向旋转180    // ObjectAnimator animator = ObjectAnimator.ofFloat(view, "translationY", 0.0F, 180.0F).setDuration(1000);
    animator.start();
}
从上面的代码来看就知道,对于一些简单的动画, ObjectAnimator用起来代码明显精简了很多,用起来更简便,更有利于开发,但是很多复杂的动画还是得用ValueAnimation来完成。


效果附上



ObjectAnimator也可以像ValueAnimator那样通过动画监听方法实现动画

public void rotateyAnimRun(final View view) {
    ObjectAnimator anim = ObjectAnimator.ofFloat(view, "dragon", 1.0F, 0.0F, 1.0F).setDuration(500);
    anim.start();
    anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            float cVal = (Float) animation.getAnimatedValue();
            view.setAlpha(cVal);
            view.setScaleX(cVal);
            view.setScaleY(cVal);
        }
    });
}

效果附上


用PropertyValueHolder实现动画集合

public void propertyValuesHolder(View view) {
    PropertyValuesHolder pvhalpha = PropertyValuesHolder.ofFloat("alpha", 1f,
            0f, 1f);
    PropertyValuesHolder pvhscaleX = PropertyValuesHolder.ofFloat("scaleX", 1f,
            0, 1f);
    PropertyValuesHolder pvhscaleY = PropertyValuesHolder.ofFloat("scaleY", 1f,
            0, 1f);
    PropertyValuesHolder pvhTranslate = PropertyValuesHolder.ofFloat("translationX", 0f, 360f);
    ObjectAnimator.ofPropertyValuesHolder(view, pvhalpha, pvhscaleX, pvhscaleY, pvhTranslate).setDuration(3 * 1000).start();
}
效果附上

这种方式作出来的动画组,是所有动画同时进行的。这毕竟很局限,比如说我想要一个动画先执行,然后第二个动画和第三个动画同时在第一个动画执行2秒之后开始执行,那就不行了。其实Android团队也考虑到了,给我们提供了更丰富的API AnimatorSet动画集合。

public void animatorSet(final View view) {

    //制作三个动画
    ObjectAnimator translationX = ObjectAnimator.ofFloat(view, "translationY", 0.0F, screenHeight - view.getHeight());
    ObjectAnimator rotation = ObjectAnimator.ofFloat(view, "rotation", 0f, 360f);
    ObjectAnimator alpha = ObjectAnimator.ofFloat(view, "alpha", 1f, 0.4f, 1f);

    AnimatorSet animatorSet = new AnimatorSet();
    AnimatorSet.Builder builder = animatorSet.play(rotation);

    //alpha动画跟rotation动画同时在translate动画之后执行
    builder.with(alpha).after(translationX);
    animatorSet.setDuration(3 * 1000).start();

}

效果:


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值