Android动画

分类:1.frame (逐帧动画)    2.tween(补间动画)  3.property (属性动画)

一、逐帧动画

逐帧动画的原理就是让一系列的静态图片依次播放,利用人眼“视觉暂留”的原理,实现动画。

实现方式有两种:1.利用 xml 实现逐帧动画      2.利用 Java 代码实现逐帧动画

 

二、补间动画

补间动画就是指开发者指定动画的开始、动画的结束的"关键帧",而动画变化的"中间帧"由系统计算,并补齐。
补间动画有四种:

  • 淡入淡出: alpha
  • 位移:translate
  • 缩放:scale
  • 旋转: rotate

实现方式有:1.利用 XML 形式补间动画     2.java代码实现补间动画   3.自定义补间动画

1.利用 XML 形式补间动画 

示例:
1、定义动画资源:
res\anim\tween_anim.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
 android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    >
    <scale
        android:duration="3000"
        android:fromXScale="0.0"
        android:fromYScale="0.0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="1.0"
        android:toYScale="1.0"/>
    <alpha
        android:duration="3000"
        android:fromAlpha="1.0"
        android:toAlpha="0.5" />
    <rotate
        android:fromDegrees="0"
        android:toDegrees="720"
        android:pivotX = "50%"
        android:pivotY="50%"
        android:duration = "3000"
        />
    <translate
        android:fromXDelta="0"
        android:toXDelta="100"
        android:fromYDelta="0"
        android:toYDelta="100" />
</set>

其中android:interpolator代表拦截器 ,可以控制动画的变化速率。

2、Animation 控制图片播放动画

public class tweenAnimation extends AppCompatActivity {
    // tween_image;
    Button tween_start;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tween_animation);

        final ImageView  tween_image = findViewById(R.id.tween_image);
        tween_start = findViewById(R.id.tween_start);
        
        // 加载动画资源
        final Animation anim = AnimationUtils.loadAnimation(this,R.anim.tween_anim);
        //设置动画结束后保留结束状态
        anim.setFillAfter(true);
        
        tween_start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                tween_image.startAnimation(anim);
            }
        });
        
    }
}

这几个动画可以组合在一起使用,同时完成缩放、透明的、旋转或者位移等的变化。

2.java代码实现补间动画

        // 组合动画设置
        AnimationSet setAnimation = new AnimationSet(true);

        // 特别说明以下情况
        // 因为在下面的旋转动画设置了无限循环(RepeatCount = INFINITE)
        // 所以动画不会结束,而是无限循环
        // 所以组合动画的下面两行设置是无效的
        setAnimation.setRepeatMode(Animation.RESTART);
        setAnimation.setRepeatCount(1);// 设置了循环一次,但无效

        // 旋转动画
        Animation rotate = new RotateAnimation(0,360,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
        rotate.setDuration(1000);
        rotate.setRepeatMode(Animation.RESTART);
        rotate.setRepeatCount(Animation.INFINITE);

        // 平移动画
        Animation translate = new TranslateAnimation(TranslateAnimation.RELATIVE_TO_PARENT,-0.5f,
                TranslateAnimation.RELATIVE_TO_PARENT,0.5f,
                TranslateAnimation.RELATIVE_TO_SELF,0
                ,TranslateAnimation.RELATIVE_TO_SELF,0);
        translate.setDuration(10000);

        // 透明度动画
        Animation alpha = new AlphaAnimation(1,0);
        alpha.setDuration(3000);
        alpha.setStartOffset(7000);

        // 缩放动画
        Animation scale1 = new ScaleAnimation(1,0.5f,1,0.5f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
        scale1.setDuration(1000);
        scale1.setStartOffset(4000);

        // 将创建的子动画添加到组合动画里
        setAnimation.addAnimation(alpha);
        setAnimation.addAnimation(rotate);
        setAnimation.addAnimation(translate);
        setAnimation.addAnimation(scale1);
        // 使用
        mButton.startAnimation(setAnimation);

 动画监听

为了实现一些需求,如动画结束后开始另一个动画或者页面跳转,这时候就需要监听动画。

 Animation.addListener(new AnimatorListener() {
          @Override
          public void onAnimationStart(Animation animation) {
              //动画开始时执行
          }

           @Override
          public void onAnimationRepeat(Animation animation) {
              //动画重复时执行
          }

         @Override
          public void onAnimationCancel()(Animation animation) {
              //动画取消时执行
          }

          @Override
          public void onAnimationEnd(Animation animation) {
              //动画结束时执行
          }
      });

3.自定义补间动画

Android 提供了 Animation 作为补间动画抽象基类,而且为该抽象基类提供了 AlphaAnimation、RotationAnimation、ScaleAnimation、TranslateAnimation 四个实现类,这四个实现类只是补间动画的基本形式:透明度、旋转、缩放、位移。但是要实现复杂的动画,就需要继承 Animation。继承 Animation 类关键是要重写一个方法:

  • applyTransformation(float interpolatedTime,Transformation t)
    interploatedTime: 代表了动画的时间进行比。不管动画实际的持续时间如何,当动画播放时,该参数总是从 0 到 1。

Transformation t:该参数代表了补间动画在不同时刻对图形或组件的变形程度。

下面示例利用 Camera 自定义三维空间动画。
自定义 Animation

public class CustomAnimation extends Animation {
    private float centerX;
    private float centerY;
    // 定义动画的持续事件
    private int duration;
    private Camera camera = new Camera();
    public CustomAnimation(float x,float y,int duration)
    {
        this.centerX = x;
        this.centerY = y;
        this.duration = duration;
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        //设置动画的持续时间
        setDuration(duration);
        //设置动画结束后保留效果
        setFillAfter(true);
        setInterpolator(new LinearInterpolator());
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        //super.applyTransformation(interpolatedTime, t);
        camera.save();
        // 根据 interpolatedTime 时间来控制X,Y,Z 上偏移
        camera.translate(100.0f - 100.f * interpolatedTime,150.0f * interpolatedTime - 150,80.0f - 80.0f * interpolatedTime);
        // 根据 interploatedTime 设置在 X 轴 和 Y 轴旋转
        camera.rotateX(360 * interpolatedTime);
        camera.rotateY(360 * interpolatedTime);
        // 获取 Transformation 参数的 Matrix 对象
        Matrix matrix = t.getMatrix();
        camera.getMatrix(matrix);
        matrix.preTranslate(-centerX,-centerY);
        matrix.postTranslate(centerX,centerY);
        camera.restore();
    }
}

上面自定义了动画,主要是设置了旋转。
使用:

  linearLayout.startAnimation(new CustomAnimation(metrics.xdpi/2,metrics.ydpi/2,3500));

   

三、属性动画

属性动画可以看作是增强版的补间动画,与补间动画的不同之处体现在:

  • 补间动画只能定义两个关键帧在透明、旋转、位移和倾斜这四个属性的变换,但是属性动画可以定义任何属性的变化。
  • 补间动画只能对 UI 组件执行动画,但属性动画可以对任何对象执行动画。

与补间动画类似的是,属性动画也需要定义几个方面的属性:

  • 动画持续时间。默认为 300ms,可以通过 android:duration 属性指定。
  • 动画插值方式。通过 android:interploator 指定。
  • 动画重复次数。通过 android:repeatCount 指定。
  • 重复行为。通过 android:repeatMode 指定。
  • 动画集。在属性资源文件中通过 <set .../> 来组合。
  • 帧刷新率。指定多长时间播放一帧。默认为 10 ms。

实现方式:1.使用 ValueAnimator 或者 ObjectAnimator 的静态工厂方法创建动画。    2.使用资源文件来定义动画。

属性动画示例:
1、布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:id="@+id/imageView_b"
        android:src="@drawable/img"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true" />
    <ImageView
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:id="@+id/imageView_c"
        android:src="@drawable/img"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true" />
    <ImageView
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:id="@+id/imageView_d"
        android:src="@drawable/img"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true" />
    <ImageView
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:id="@+id/imageView_e"
        android:src="@drawable/img"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true" />
    <ImageView
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:id="@+id/imageView_a"
        android:src="@drawable/img"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true" />
</RelativeLayout>

2、使用

public class PropertyAnimator  extends Activity implements View.OnClickListener {

    private int[] mRes = {R.id.imageView_a, R.id.imageView_b, R.id.imageView_c,
            R.id.imageView_d, R.id.imageView_e};
    private List<ImageView> mImageViews = new ArrayList<>();
    private boolean mFlag = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.property_animator);

        int sum = mRes.length;
        for (int i = 0; i < sum; i++) {
            ImageView imageView = (ImageView) findViewById(mRes[i]);
            imageView.setOnClickListener(this);
            mImageViews.add(imageView);
        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.imageView_a:
                if (mFlag) {
                    startAnim();
                } else {
                    closeAnim();
                }
                break;
            case R.id.imageView_b:
                Toast.makeText(PropertyAnimator.this, "b", Toast.LENGTH_SHORT).show();
                break;
            case R.id.imageView_c:
                Toast.makeText(PropertyAnimator.this, "c", Toast.LENGTH_SHORT).show();
                break;
            case R.id.imageView_d:
                Toast.makeText(PropertyAnimator.this, "d", Toast.LENGTH_SHORT).show();
                break;
            case R.id.imageView_e:
                Toast.makeText(PropertyAnimator.this, "e", Toast.LENGTH_SHORT).show();
                break;
        }
    }

    private void closeAnim() {
        ObjectAnimator animator0 = ObjectAnimator.ofFloat(mImageViews.get(0),
                "alpha", 0.5F, 1F);
        ObjectAnimator animator1 = ObjectAnimator.ofFloat(mImageViews.get(1),
                "translationY", 200F, 0);
        ObjectAnimator animator2 = ObjectAnimator.ofFloat(mImageViews.get(2),
                "translationX", 200F, 0);
        ObjectAnimator animator3 = ObjectAnimator.ofFloat(mImageViews.get(3),
                "translationY", -200F, 0);
        ObjectAnimator animator4 = ObjectAnimator.ofFloat(mImageViews.get(4),
                "translationX", -200F, 0);
        AnimatorSet set = new AnimatorSet();
        set.setDuration(500);
        set.setInterpolator(new BounceInterpolator());
        set.playTogether(animator0, animator1, animator2, animator3, animator4);
        set.start();
        mFlag = true;
    }

    private void startAnim() {
        ObjectAnimator animator0 = ObjectAnimator.ofFloat(
                mImageViews.get(0),
                "alpha",
                1F,
                0.5F);
        ObjectAnimator animator1 = ObjectAnimator.ofFloat(
                mImageViews.get(1),
                "translationY",
                200F);
        ObjectAnimator animator2 = ObjectAnimator.ofFloat(
                mImageViews.get(2),
                "translationX",
                200F);
        ObjectAnimator animator3 = ObjectAnimator.ofFloat(
                mImageViews.get(3),
                "translationY",
                -200F);
        ObjectAnimator animator4 = ObjectAnimator.ofFloat(
                mImageViews.get(4),
                "translationX",
                -200F);
        AnimatorSet set = new AnimatorSet();
        set.setDuration(500);
        set.setInterpolator(new BounceInterpolator());
        set.playTogether(
                animator0,
                animator1,
                animator2,
                animator3,
                animator4);
        set.start();
        mFlag = false;
    }
}

效果:

 

四、使用 SurfaceView 实现动画

实现动画还可以通过自定义 View 的方式,但是自定义 View 有如下缺陷:

  • View 缺乏双缓冲机制。
  • 当程序需要更新 View 上的图像时,程序必须重绘 View 上显示的整张图片。
  • 新线程无法直接更新 View 组件。

因此,自定义 View 实现绘图不是很好的选择,尤其是游戏绘图时,性能不是很好。因此,Android 提供了一个 SurfaceView 来代替 View。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值