安卓入门-动画(Animation)(由简单的单一动画到复杂的时间顺序叠加动画)(XML实现方式+JAVA实现方式)

三个要做的动画

  1. 正确转向和转向过度(由于都是一个圆周运动的一部分,所以放在一起)

这个比较简单,作为一个单一动画的例子

在这里插入图片描述

在这里插入图片描述

  1. 转向过度,甩尾(多个运动的叠加)

多个动画叠加,作为一个进阶的例子

在这里插入图片描述

理论知识

安卓动画分为三类:

  • View Animation (视图动画)
  • Drawable Animation (帧动画)
  • Property Animation(属性动画)

这里我将用 View Animation作为例子来讲解如何实现

视图动画的作用对象是View,支持四种动画效果,分别是平移动画,缩放动画,旋转动画,透明度动画。譬如,我们可以对安卓组件设置其的移动,旋转,缩放,透明。

动画调用
平移动画translation
缩放动画scale
旋转rotate
透明度动画Alpha

每一个动画都可以由两种方式进行设置

1. XML文件设置

首先在res文件夹下建立anim文件夹
在这里插入图片描述
然后在其中加入xml文件来编写动画文本
在这里插入图片描述
xml代码:
其中包括了4种动画的定义,这里大家可以任意选择使用某几种动画,并且设置其中的参数来达到自己想要的效果

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:fromXDelta="0"
        android:toXDelta="20"
        android:fromYDelta="0"
        android:toYDelta="20"
        android:duration="4000"/>
    <scale
        android:fromXScale="1.0"
        android:toXScale="0.2"
        android:fromYScale="1.0"
        android:toYScale="0.2"
        android:pivotX="50%"
        android:pivotY="50%"
        android:duration="4000"/>
    <rotate
        android:fromDegrees="0"
        android:toDegrees="360"
        android:pivotX="50%"
        android:pivotY="50%"
        android:duration="4000"/>
    <alpha
        android:fromAlpha="1.0"
        android:toAlpha="0.2"
        android:duration="4000"/>
</set>

xml文件编写完毕之后,需要在java代码中调用一下才能使动画运行

Animation animation = AnimationUtils.loadAnimation(MainActivity.this,R.anim.test);
raceCar.startAnimation(animation);

2.JAVA代码设置

这里为了让大家看看清楚最基本的一个动画如何建立,我就直接截了Android studio上的图,这样可以方便大家能看清楚每一个参数是干什么的(其实自己打代码的话也是能看到的)
在这里插入图片描述
可以选择设置一个持续时间,调用.setDuration(long time)方法
然后调用.start()即可

相对来说JAVA代码设置会简单一些

这里再提供一个类的方法:

我这里用的是ObjectAnimator,因为这个进行动画集合的AnimatorSet比较好用,并且可以无限套娃

在这里插入图片描述
在这里插入图片描述
AnimatorSet()不仅可以使用playTogether()(同时播放动画),还可以让动画顺序播放,调用playSequentially():
在这里插入图片描述
同样的,还可以设置延时播放(不过这样不太好用,我用另外一种实现方式做出来了)
下面的第一个语句就是backX这个动画在backY之后1000毫秒后播放

backAnimatorSet.play(backX).after(backY).after(1000);
backAnimatorSet.play(backX).before(backY);
backAnimatorSet.play(backX).with(backY);

具体实例实现(JAVA代码方式)

这里我要做在博文开始提到的3个动画

动画一(赛车的外内外走线)

首先,让赛车的转向圆与赛道完美切合,我们可以先话一个圆,然后在圆上画赛道
在这里插入图片描述
这样子圆运动就比较好规划了,让赛车的起点在赛道左下角,然后圆心定在图片右下角,转90度即可
如果大家不知道如何确定圆心位置,Android Studio上有一个叫做GuidLine的东西,可以用来找到位置
在这里插入图片描述

在这里插入图片描述
然后就可以编写一个完美过弯的代码了

在这里插入图片描述
这里重点在于new RotateAnimation()里面的几个参数,前两个为从0°顺时针旋转到90°,后面两个为圆心的X,Y坐标,这里坐标是以动画主体(我的是一个图片)的左上角为原点的。

//编写动画
final Animation perfectTurning = new RotateAnimation(0,90,1100,488-432);
        perfectTurning.setDuration(2000);
//编写按钮触发该动画
perfectBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                backAnimatorSet.start();
                yuanli.setVisibility(View.INVISIBLE);
                raceCar.startAnimation(perfectTurning);
                desc.setText("正确的入弯时机\n正确的外内外走线\n正确的出弯时机");

            }
        });

动画二(转向不足的动画)

这个跟上面的大同小异,只是不再是完美走线,而是一个半径更大的圆,所以我更改了pivotX的数值,其他保持不变,就完成了这个动画

为了更加清楚的解释赛车的动态,我还加了一个轮胎来解释这个动画
在这里插入图片描述

		final Animation notEnough = new RotateAnimation(0,75,1600,488-432);
        notEnough.setDuration(1500);
		notEnoughBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                backAnimatorSet.start();
                clickTime++;
                if (clickTime % 2 == 1) {
                    raceCar.setVisibility(View.VISIBLE);
                    yuanli.setVisibility(View.VISIBLE);
                    raceCar.startAnimation(notEnough);
                    desc.setText("车速过快,\n导致前轮胎摩擦力无法提供向心力\n而出现推头现象");
                }

                if (clickTime % 2 == 0) {
                    raceCar.setVisibility(View.INVISIBLE);
                    yuanli.setVisibility(View.VISIBLE);
                    tier.setVisibility(View.VISIBLE);

                    tier.startAnimation(notEnough);
                    tier.setVisibility(View.INVISIBLE);
                    desc.setText("车速过快,\n导致前轮胎摩擦力无法提供向心力\n而出现推头现象");
                }
            }
        });

动画三(转向过度的动画)(复杂的叠加动画)

这里写的每一个单一动画我都用了另外一个实现方式(ObjectAnimator)

情景说明

这个相对来讲比较复杂,我的想的场景是这样的,赛车转向动作开始晚了一些(这里需要一个向前的动画),然后突然进行转弯(叠加一个向右的动画,此时的向前动画是还没停止的)。这里转弯不能只有平移,还要有旋转才能让这个转向更加逼真。由于这里是一个转向过度造成甩尾的情景,所以在平移结束后我的旋转动画实际上还没有结束(这里延时多设置了100毫秒)

动画代码编写

首先先把上述几个动画写好:

		goStraight = ObjectAnimator.ofFloat(raceCar,"translationY",-980);
        goStraight.setDuration(1600);

        turningX = ObjectAnimator.ofFloat(raceCar,"translationX",500);
        turningX.setDuration(1200);

        turningStep2 = ObjectAnimator.ofFloat(raceCar,"rotation",0,175);
        turningStep2.setDuration(1300);

由于这种动画方式不会自动恢复动画物体位置,我自己只好手写了一个恢复位置动画(其实是一个持续时间为0的动画,也就是一瞬间完成),正好也用到了AnimationSet这个东西:

		final ObjectAnimator backX = ObjectAnimator.ofFloat(raceCar,"translationX",0);
        final ObjectAnimator backY = ObjectAnimator.ofFloat(raceCar,"translationY",0);
        final ObjectAnimator backRotate = ObjectAnimator.ofFloat(raceCar,"rotation",0,0);
        backAnimatorSet = new AnimatorSet();
        backAnimatorSet.playTogether(backX,backY,backRotate);
        backAnimatorSet.setDuration(0);

加入时间线来执行这些动画

这几个动画执行的顺序是这样的:
在这里插入图片描述
本来可以使用上面讲到的after来执行,但是我觉得是在不太好控制
我这里又建了一个专门用来计时的线程,还有一个相应的Handler。
到了某个时间我就发message给Handler,然后在Handler中执行动画即可。

class MyTimer extends Thread{
        @Override
        public void run() {
            time=0;
                while(true) {
                    time+=10;
                    try {
                        Thread.currentThread().sleep(10);
                    } catch (InterruptedException e) {

                    }
                    if (time == 10 ){
                        Message message = handler.obtainMessage();
                        message.what=3;
                        handler.sendMessage(message);
                    }
                    if (time == 700){
                        Message message = handler.obtainMessage();
                        message.what=1;
                        handler.sendMessage(message);
                    }

                    if (time >=2000){
                        break;
                    }
                }
        }
    }

上面的time是以毫秒为单位,每10ms过去time就更新一次
(严格山来说不是严格的10ms,因为执行这些其他的语句还要时间)

private Handler handler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            if (msg.what == 1){
                turningX.start();
                turningStep2.start();
            }
            else if (msg.what==3){
                goStraight.start();
            }

        }
    };

然后就是动画的执行了,我在一开始就执行了前进,然后在一定时间之后同时开始了转向动画的平移和旋转动画。由于前面设置的持续时间不一样,视觉上看起来就是车辆不再平移后还旋转了一小段。

最后开启一下Thread即可

tooMuchBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                backAnimatorSet.start();
                time = 0;
                MyTimer timer = new MyTimer();
                timer.start();
                yuanli.setVisibility(View.INVISIBLE);


                desc.setText("入弯过晚->转向过快\n导致后轮胎摩擦力无法提供向心力\n从而出现甩尾现象");
            }
        });

工程文件:
AndroidAnimation

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值