【题外话】先容我卖个萌装个B自我介绍一分钟哈,本猿自诩Android小白,天然呆谷粉米粉,爱开源,更爱漂亮妹纸(\(^o^)/~来跟我一起唱:原谅我一生放荡不羁爱自由~~~请自行脑补掌声三分钟^O^);好了好了说人话:本猿中南大学大三狗一个,每天最快乐的时光都与14寸的DeskTop为伴,曾经我是一个热爱并略懂Java和Android的小白,现在我是一个热爱并熟悉Java和Android的小白,就这样!聊技术谈梦想欢迎私信 @哈皮小猿_wondertwo
【1】 Android动画的基本概念
提起 Android
动画很多初学者就会一脸懵逼二阶茫然,想当初小猿我翻遍图书馆的一大堆入门书籍都找到有一个在讲 Android
动画机制,好在一颗痴迷技术的心让我自备燃料有始有终,最后总算弄明白了 Android
动画到底是个什么鬼。其实我们有木有经常用手机拍了很多漂亮照片以后,打开相册,点击更多,点击自动播放,这些静态的照片就会像幻灯片一样播放起来了有木有?这其实就是 Android
动画之一帧动画,把一组图片按顺序播放出来。是不是很简单呢? Android
动画分三类,下面我们简要的介绍一下:
- 视图动画,即我们常说的
View
动画,View
动画有四种效果:透明度变化(AlphaAnimation
),位移(TranslateAnimation
),缩放(ScaleAnimation
),旋转(RotateAnimation
); - 帧动画,即
FrameAnimation
,可以简单的理解为放电影,又或者是手机相册的自动播放功能,把一组预先准备好的图片按顺序播放出来,就是一个帧动画; - 属性动画,即
PropertyAnimation
,我们知道动画都有很多属性,比如透明度的变化,比如位置的移动,比如旋转一定的角度,比如变化的速度、加速度等等这些,所谓属性动画就是通过设置透明度、位移、旋转角度、变化的加速度这些动画的属性,从而达到动画的效果;
视图动画 Added in API level 1
,算是 Android
动画家族中的老腊肉了。那我们就从最基本的视图动画着手,由于篇幅的关系,帧动画和属性动画会放在下一篇文章中详细介绍,请大家继续关注哦。大家可能要吐槽说好的特效大爆炸呢?别急嘛!请往下看!下面就是狂炫酷帅的QQ客户端抖一抖动画和3D旋转&电视关闭画面的自定义动画哦!
【2】 View动画的基本用法
哈哈,上面的自定义动画有木有惊艳到你呢?“每一个宅男心中都藏着一个女神”,我当然也不例外啦,你看的没错!画面中就是我的女神——张钧甯。告诉你上面的动画特效就是用自定义视图动画实现的哦,他们都是在四种最基本的视图动画的基础上稍加改进出来的,来我们看看四种基本的视图动画效果如何?
分别对应着透明度变化(AlphaAnimation
),缩放(ScaleAnimation
),旋转(RotateAnimation
),位移(TranslateAnimation
),第五个是融合了前四种 View
动画的一个动画集合哦(AnimationSet
);那到底是怎么实现的呢?定义动画既可以在代码中动态的定义,也可以在 xml
文件中定义。
先来看最简单的 View
动画。 View
动画的四种变换效果对应着 AlphaAnimation , ScaleAnimation , RotateAnimation , TranslateAnimation
这4个动画类,在 xml
文件中定义View动画,透明度动画对应的标签是 <alpha>
,缩放动画对应的标签是 <scale>
,旋转动画对应的标签是 <rotate>
,位移动画对应的标签是 <translate>
。下面我们来看代码,在 res
文件夹下新建文件夹 anim
,在 anim
目录新建 xml
文件 anim_view.xml
,根标签 <set>
就表示一个动画集合 AnimationSet
;shareInterpolator="true"
表示共享插值器,插值器会在后面详细解释;接着是4个View
动画效果;代码如下:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="true" >
<!--透明度-->
<alpha
android:fromAlpha="0"
android:toAlpha="1" />
<!--缩放-->
<scale
android:fromXScale="0.5f"
android:fromYScale="1.5f"
android:toXScale="0.5f"
android:toYScale="1.5f"
android:pivotX="100"
android:pivotY="100" />
<!--位移-->
<translate
android:fromXDelta="0"
android:toXDelta="0"
android:fromYDelta="200"
android:toYDelta="200" />
<!--旋转-->
<rotate
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="200"
android:pivotY="200" />
</set>
4个View
动画效果标签中的属性值,分别对应着代码动态定义View
动方法中接收的参数,这里做一下详细的解释:
- alpha
- fromAlpha —- 透明度起始值,0表示完全透明
- toAlpha —- 透明度最终值,1表示不透明
- scale
- fromXScale —- 水平方向缩放的起始值,比如0
- fromYScale —- 竖直方向缩放的起始值,比如0
- toXScale —- 水平方向缩放的结束值,比如2
- toYScale —- 竖直方向缩放的结束值,比如2
- pivotX —- 缩放支点的x坐标
- pivotY —- 缩放支点的y坐标(支点可以理解为缩放的中心点,缩放过程中这点的坐标是不变的;支点默认在中心位置)
- translate
- fromXDelta —- x起始值
- toXDelta —- x结束值
- fromYDelta —- y起始值
- toYDelta —- y结束值
- rotate
- fromDegrees —- 旋转起始角度
- toDegrees —- 旋转结束角度
除此之外,View
动画还有一些常见的属性值,如下:
- android:duration —- 动画的持续时间
- android:fillAfter —- true表示保持动画结束时的状态,false表示不保持
上面就是通过 xml
文件定义的 View
动画,那怎么应用上面的动画呢?也很简单,通过 View
对象在代码中调用即可,值得注意的是,AnimationUtils.loadAnimation(this, R.anim.ani_view)
方法接收两个参数,第一个是当前的上下文环境,第二个就是我们通过 xml
定义的动画啦。代码如下:
ImageView ivAni = (ImageView) findViewById(R.id.iv_ani);
Animation ani = AnimationUtils.loadAnimation(this, R.anim.ani_view);
ivAni.startAnimation(ani);
上面介绍的是通过 xml
文件定义 View
动画,那怎样通过代码动态的定义 View
动画呢?也很简单,先上代码。
AlphaAni
—-透明度动画代码如下,相信你经过前面的部分已经能很容易就看懂这些代码了,在 beginAnimation()
方法中,我们在3000ms的时间内把一个 LinearLayout
对象 llAlpha
的透明度从0到1,即从完全透明渐变到完全不透明,然后在 onCreate()
方法中调用 beginAnimation()
方法就能以透明度渐变动画的方式跳转到 AlphaAni
:
package com.wondertwo.viewani;
import android.app.Activity;
import android.os.Bundle;
import android.view.animation.AlphaAnimation;
import android.widget.LinearLayout;
import com.wondertwo.R;
/**
* AlphaAni----透明度动画
* Created by wondertwo on 2016/3/11.
*/
public class AlphaAni extends Activity {
private LinearLayout llAlpha;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_alpha);
llAlpha = (LinearLayout) findViewById(R.id.ll_alpha);
beginAnimation();
}
// 启动动画
private void beginAnimation() {
AlphaAnimation alpha = new AlphaAnimation(0, 1);// 0---->1从透明到不透明
alpha.setDuration(3000);// 设置动画持续时间
llAlpha.startAnimation(alpha);// 启动动画
}
}
ScaleAni
—-缩放动画代码如下,与上面的透明度渐变动画类似,通过 ctrl+左键
查看源码可以知道,在创建 ScaleAnimation
缩放动画的对象的时候, ScaleAnimation(0, 2, 0, 2)
接受的四个参数分别是 ScaleAnimation(float fromX, float toX, float fromY, float toY)
:
package com.wondertwo.viewani;
import android.app.Activity;
import android.os.Bundle;
import android.view.animation.ScaleAnimation;
import android.widget.LinearLayout;
import com.wondertwo.R;
/**
* ScaleAni----缩放动画
* Created by wondertwo on 2016/3/11.
*/
public class ScaleAni extends Activity {
private LinearLayout llScale;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scale);
llScale = (LinearLayout) findViewById(R.id.ll_scale);
beginAnimation();
}
// 启动动画
private void beginAnimation() {
ScaleAnimation scale = new ScaleAnimation(0, 2, 0, 2);
scale.setDuration(3000);
llScale.startAnimation(scale);
}
}
RotateAni
—-旋转动画代码如下,表示把一个 View
对象从起始角度0旋转到360度,后面的四个参数 RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f
表示以中心位置为旋转支点:
package com.wondertwo.viewani;
import android.app.Activity;
import android.os.Bundle;
import android.view.animation.RotateAnimation;
import android.widget.LinearLayout;
import com.wondertwo.R;
/**
* RotateAni----旋转动画
* Created by wondertwo on 2016/3/11.
*/
public class RotateAni extends Activity {
private LinearLayout llRotate;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rotate);
llRotate = (LinearLayout) findViewById(R.id.ll_rotate);
beginAnimation();
}
// 启动动画
private void beginAnimation() {
RotateAnimation rotate = new RotateAnimation(0, 360,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
rotate.setDuration(3000);
llRotate.startAnimation(rotate);
}
}
TranslateAni
—-位移动画代码如下,表示把 View
对象从起始坐标 (0, 0)
位移到 (200, 300)
,是不是很简单呢:
package com.wondertwo.viewani;
import android.app.Activity;
import android.os.Bundle;
import android.view.animation.TranslateAnimation;
import android.widget.LinearLayout;
import com.wondertwo.R;
/**
* TranslateAni----位移动画
* Created by wondertwo on 2016/3/11.
*/
public class TranslateAni extends Activity {
private LinearLayout llTranslate;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_translate);
llTranslate = (LinearLayout) findViewById(R.id.ll_translate);
beginAnimation();
}
// 启动动画
private void beginAnimation() {
TranslateAnimation translate = new TranslateAnimation(0, 200, 0, 300);
translate.setDuration(3000);
llTranslate.startAnimation(translate);
}
}
【3】 View动画的高级用法
接下来我们趁热打铁,掌握 View
动画高级用法的好时机啦,所谓高级用法,其实也很简单,就是把上面的四种基本效果进行任意的排列组合,然后同时启动。为了更直观的感受,还是直接上动图吧请往下看,一种很酷炫的图片旋转飞入效果!
直接上代码如下,你看过肯定会觉得不能再简单啦,不就是把上面介绍的四种动画组合到一起了嘛,事实上就是这么简单。
package com.wondertwo.viewani;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.RotateAnimation;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.LinearLayout;
import com.wondertwo.MainActivity;
import com.wondertwo.R;
/**
* AlphaAnimation、RotateAnimation、ScaleAnimation、TranslateAnimation四种视图动画的组合动画
* Created by wondertwo on 2016/3/11.
*/
public class GroupAni extends Activity {
private LinearLayout llGroup;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_group);
llGroup = (LinearLayout) findViewById(R.id.ll_group);
beginAnimation();
}
// 启动组合动画
private void beginAnimation() {
// 创建动画集合
AnimationSet aniSet = new AnimationSet(false);
// 透明度动画
AlphaAnimation alpha = new AlphaAnimation(0, 1);
alpha.setDuration(4000);
aniSet.addAnimation(alpha);
// 旋转动画
RotateAnimation rotate = new RotateAnimation(0, 360,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
rotate.setDuration(4000);
aniSet.addAnimation(rotate);
// 缩放动画
ScaleAnimation scale = new ScaleAnimation(1.5f, 0.5f, 1.5f, 0.5f);
scale.setDuration(4000);
aniSet.addAnimation(scale);
// 位移动画
TranslateAnimation translate = new TranslateAnimation(0, 160, 0, 240);
translate.setDuration(4000);
aniSet.addAnimation(translate);
// 动画监听
aniSet.setAnimationListener(new Animation.AnimationListener() {
// 动画开始
@Override
public void onAnimationStart(Animation animation) {
}
// 动画结束,一般在这里实现页面跳转逻辑
@Override
public void onAnimationEnd(Animation animation) {
// 动画结束后,跳转到主页面
startActivity(new Intent(GroupAni.this, MainActivity.class));
}
// 动画重复
@Override
public void onAnimationRepeat(Animation animation) {
}
});
// 把动画设置给llGroup
llGroup.startAnimation(aniSet);
}
}
唯一不同的是,我们这次是把四个 View
动画装进了一个动画集合(AnimationSet
)中,至于动画集合,你就把他当做普通的 Set
集合使用就好,创建动画集合时传入的参数 false
表示动画集合中装入的和四个 View
动画不共享插值器。这肯定难不倒 Java
烂熟于心的你,对吧哈哈。到这里你已经学会 View
动画了,但是后面还有更高级用法呢!
还是一样先把代码贴出来,我们主要看动画的实现类代码,至于布局文件很简单这里就不讨论了。
package com.wondertwo.effect;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.animation.BounceInterpolator;
import android.widget.ImageView;
import android.widget.Toast;
import com.wondertwo.R;
import java.util.ArrayList;
/**
*
* 常用动画的属性值有:
* - translationX、translationY----控制view对象相对其左上角坐标在X、Y轴上偏移的距离
* - rotation、rotationX、rotationY----控制view对象绕支点进行2D和3D旋转
* - scaleX、scaleY----控制view对象绕支点进行2D缩放
* - pivotX、pivotY----控制view对象的支点位置,这个位置一般就是view对象的中心点。围绕这个支点可以进行旋转和缩放处理
* - x、y----描述view对象在容器中的最终位置,是最初的左上角坐标和translationX、translationY值的累计和
* - alpha----表示view对象的透明度。默认值是1(完全透明)、0(不透明)
*
* Created by wondertwo on 2016/3/11.
*/
public class EffectAni extends AppCompatActivity implements View.OnClickListener {
// ImageView组件id数组
private int[] mRes = new int[]{R.id.iv_a, R.id.iv_b, R.id.iv_c, R.id.iv_d, R.id.iv_e};
// ImageView对象集合
private ArrayList<ImageView> mImViews = new ArrayList<>();
private boolean flag = true;// 启动动画、关闭动画的标记位
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_effect);
// for循环创建ImageView对象,并添加到集合中
for (int i = 0; i < mRes.length; i++) {
ImageView iv_a = (ImageView) findViewById(mRes[i]);
iv_a.setOnClickListener(this);
mImViews.add(iv_a);
}
}
// 按钮点击事件
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.iv_a:
if (flag) {
startAnim();
} else {
closeAnim();
}
break;
default:
Toast.makeText(EffectAni.this, "" + v.getId(), Toast.LENGTH_SHORT).show();
break;
}
}
// 关闭动画
private void closeAnim() {
// 创建ObjectAnimator对象,参数分别是动画要设置的View对象、动画属性、属性值
ObjectAnimator animator0 = ObjectAnimator.ofFloat(mImViews.get(0),
"alpha",
0.5F,
1F);
ObjectAnimator animator1 = ObjectAnimator.ofFloat(mImViews.get(1),
"translationY",
200F,
0);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(mImViews.get(2),
"translationX",
200F,
0);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(mImViews.get(3),
"translationY",
-200F,
0);
ObjectAnimator animator4 = ObjectAnimator.ofFloat(mImViews.get(4),
"translationX",
-200F,
0);
AnimatorSet aniSet = new AnimatorSet();
aniSet.setDuration(4000);
aniSet.setInterpolator(new BounceInterpolator());// 弹跳效果的插值器
aniSet.playTogether(animator0,
animator1,
animator2,
animator3,
animator4);// 同时启动5个动画
aniSet.start();
// 重置标记位
flag = true;
}
// 启动动画
private void startAnim() {
// 创建ObjectAnimator对象,参数分别是动画要设置的View对象、动画属性、属性值
ObjectAnimator animator0 = ObjectAnimator.ofFloat(
mImViews.get(0),
"alpha",
1f,
0.5f);
ObjectAnimator animator1 = ObjectAnimator.ofFloat(
mImViews.get(1),
"translationY",
200f);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(
mImViews.get(2),
"translationX",
200f);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(
mImViews.get(3),
"translationY",
-200f);
ObjectAnimator animator4 = ObjectAnimator.ofFloat(
mImViews.get(4),
"translationX",
-200f);
AnimatorSet aniSet = new AnimatorSet();
aniSet.setDuration(4000);
aniSet.setInterpolator(new BounceInterpolator());// 弹跳效果的插值器
aniSet.playTogether(animator0,
animator1,
animator2,
animator3,
animator4);// 同时启动5个动画
aniSet.start();
// 重置标记位
flag = false;
}
}
上面的代码逻辑很简单,在 Activity
的 onCreate()
方法中拿到五张一样的 ImageView
对象,其实你看到的元神分身效果就是这五张图片向不同方向做位移动画的结果啦,先用 int[] mRes
数组存放5个 ImageView
的 id
,然后在 Activity
的 onCreate()
方法中拿到五张一样的 ImageView
对象,在 closeAnim()
方法和 startAnim()
方法中分别对每张图片进行不同的 TranslateAnimation
处理。这里我们通过设置标记位 flag
,实现分身、归位两个效果的切换。
【4】 自定义View动画
当你看完上面的 View
动画,自定义 View
动画对你来说已经不在话下,我准备的两个 demo
你肯定很期待,分别是:模仿QQ客户端的抖一抖特效,和电视画面关闭&3D旋转,效果如下:
上图就是模仿QQ客户端的抖一抖特效,可能由于Gif图片的录制的效果太差,显示的效果比我电脑上真实情况慢了好多,但是也基本能把这个效果显示出来了。先上代码!
package com.wondertwo.qqTremble;
import android.view.animation.Animation;
import android.view.animation.Transformation;
/**
* QQ抖一抖特效的自定义View动画实现
* Created by wondertwo on 2016/3/17.
*/
public class QQTrembleAni extends Animation {
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
t.getMatrix().setTranslate(
(float) Math.sin(interpolatedTime * 50) * 8,
(float) Math.sin(interpolatedTime * 50) * 8
);// 50越大频率越高,8越小振幅越小
super.applyTransformation(interpolatedTime, t);
}
}
上面这段代码就是我们自定义的QQ抖一抖动画了,所有的自定义动画都需要继承 android.view.animation.Animation
抽象类,然后重写 initialize()
和 applyTransformation()
这两个方法,在 initialize()
方法中对一些变量进行初始化,在 applyTransformation()
方法中通过矩阵修改动画数值,从而控制动画的实现过程,这也是自定义动画的核心。 applyTransformation(float interpolatedTime, Transformation t)
方法在动画的执行过程中会不断地调用,可以看到接收的两个参数分别是 float interpolatedTime
表示当前动画进行的时间与动画总时间(一般在 setDuration()
方法中设置)的比值,从0逐渐增大到1; Transformation t
传递当前动画对象,一般可以通过代码 android.graphics.Matrix matrix = t.getMatrix()
获得 Matrix
矩阵对象,再设置 Matrix
对象,一般要用到 interpolatedTime
参数,以此达到控制动画实现的结果。可以看到在上面的代码中 t.getMatrix().setTranslate((float) Math.sin(interpolatedTime * 50) * 8, (float) Math.sin(interpolatedTime * 50) * 8)
设置了 Matrix
对象的 Translate
,传入的参数是一个正弦函数值,这个值是通过 interpolatedTime
参数计算出来的,这样就实现了动画在x,y轴两个方向上的来回抖动效果。
下面是QQ抖一抖动画的测试类 Activity
,代码如下:
package com.wondertwo.qqTremble;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.RelativeLayout;
import com.wondertwo.R;
/**
* 模仿QQ抖一抖效果的测试类
* Created by wondertwo on 2016/3/17.
*/
public class QQTrembleTest extends Activity {
private RelativeLayout rlTremble;
private Button btnTremble;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_qq_tremble);
rlTremble = (RelativeLayout) findViewById(R.id.rl_tremble);
btnTremble = (Button) findViewById(R.id.btn_tremble);
// 创建抖一抖动画对象
final QQTrembleAni tremble = new QQTrembleAni();
tremble.setDuration(800);// 持续时间800ms,持续时间越短频率越高
tremble.setRepeatCount(2);// 重复次数,不包含第一次
// 设置按钮点击监听
btnTremble.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 启动抖一抖效果
rlTremble.startAnimation(tremble);
}
});
}
}
接着我们再看一个酷炫的自定义动画,类似电视机关机画面和图片3D旋转,效果如下!
直接上代码,电视关机画面效果动画 TVCloseAni
如下:
package com.wondertwo.custom;
import android.graphics.Matrix;
import android.view.animation.Animation;
import android.view.animation.Transformation;
/**
* 通过矩阵变换模拟电视关闭效果,使图片的纵向比例不断缩小
* Created by wondertwo on 2016/3/13.
*/
public class TVCloseAni extends Animation {
private int mCenterWidth, mCenterHeight;
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
// 设置默认时长
setDuration(4000);
// 保持动画的结束状态
setFillAfter(true);
// 设置默认插值器
// setInterpolator(new BounceInterpolator());// 回弹效果的插值器
mCenterWidth = width / 2;
mCenterHeight = height /2;
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
final Matrix matrix = t.getMatrix();
matrix.preScale(1,
1 - interpolatedTime,
mCenterWidth,
mCenterHeight);
}
}
图片3D旋转效果动画代码如下:
package com.wondertwo.custom;
import android.graphics.Camera;
import android.graphics.Matrix;
import android.view.animation.Animation;
import android.view.animation.BounceInterpolator;
import android.view.animation.Transformation;
/**
*
* Created by wondertwo on 2016/3/13.
*/
public class CustomAni extends Animation {
private int mCenterWidth, mCenterHeight;
private Camera mCamera = new Camera();
private float mRotateY = 0.0f;
// 一般在此方法初始化一些动画相关的变量和值
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
// 设置默认时长
setDuration(4000);
// 保持动画的结束状态
setFillAfter(true);
// 设置默认插值器
setInterpolator(new BounceInterpolator());// 回弹效果的插值器
mCenterWidth = width / 2;
mCenterHeight = height /2;
}
// 暴露接口设置旋转角度
public void setRotateY(float rotateY) {
mRotateY = rotateY;
}
// 自定义动画的核心,在动画的执行过程中会不断回调此方法,并且每次回调interpolatedTime值都在不断变化(0----1)
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
final Matrix matrix = t.getMatrix();
mCamera.save();
// 使用Camera设置Y轴方向的旋转角度
mCamera.rotateY(mRotateY * interpolatedTime);
// 将旋转变化作用到matrix上
mCamera.getMatrix(matrix);
mCamera.restore();
// 通过pre方法设置矩阵作用前的偏移量来改变旋转中心
matrix.preTranslate(mCenterWidth, mCenterHeight);// 在旋转之前开始位移动画
matrix.postTranslate(-mCenterWidth, -mCenterHeight);// 在旋转之后开始位移动画
}
}
下面是电视机关机画面和图片3D旋转动画的测试类, CustomAniTest
代码如下!
package com.wondertwo.custom;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import com.wondertwo.R;
/**
* 自定义动画测试类
* Created by wondertwo on 2016/3/13.
*/
public class CustomAniTest extends Activity {
private boolean flag = true;// 标记位,轮换展示两种自定义动画
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_custom_ani);
}
/**
* 设置按钮点击事件
*/
public void startCustomAni(View view) {
if (flag) {
TVCloseAni tvAni = new TVCloseAni();
view.startAnimation(tvAni);
// 重置标记位
flag = false;
} else {
CustomAni customAni = new CustomAni();
customAni.setRotateY(30);
view.startAnimation(customAni);
// 重置标记位
flag = true;
}
}
}
唯一不同的是在上面3D旋转自定义动画中,我们引入了 Camera
的概念, android.graphics.Camera
中的 Camera
类封装了 openGL
的3D动画,因此可以通过 Camera
类实现很多酷炫的3D动画效果。
【总结】本文主要介绍了下列内容:
- Android动画的基本概念
- 视图动画的基本用法
- 视图动画的组合用法
- 自定义View动画
如果觉得不错,请继续关注哦!下一篇将继续介绍Android属性动画哈!