在Android中,动画一直是交互的一个很好手段,在平时的项目开发中,经常要用到一些动画的交互,每次拿着一个gif跑过来说,这个动画可以实现吗?每次都硬着头皮说,可以。然而对于我这种Android小白来说,确实是有一点难度,所以就有了今天这篇关于Android动画的一些理解,希望对大家有帮助!!!
本文知识点:
- Android动画的分类:
- 视图动画的使用:
- 帧动画的使用:
- 属性动画的使用:
1. Android动画的分类:
Android 中动画可以分为:
- 位移动画
- 平移 TranslateAnimation
- 旋转 RotateAnimation
- 缩放 ScaleAnimation
- 透明度 AlphaAnimation
- 帧动画
- 属性动画
2.视图动画的使用
首先,我真的不知道是不是叫这个名字,网上叫什么名字的都有,就先这么叫吧!管他呢?反正你知道是什么东西就好了!这里先说一下缺点,所有视图动画改变View的操作都是改变的显示位置,而并非改变的实际位置,下面是视图动画里面用到的一些公共属性!
- android:duration 动画执行时间
- android:fillAfter 动画结束后View是否停留在结束位置
- android:interpolator 插值器默认为(加速减速插值器)
- android:shareInterpolator 是否共享插值器
一张图让你理解视图动画的位置实际并没有改变!
这里强烈说明一点,就是动画存放的位置,一开始我总是分不清具体的存放位置,其实现在也分不清!!!一定是在res下面创建anim文件夹 : res/anim/XXX.xml,并且内部的标签一定是set标签!!!这里唠叨一句,当你新创建的项目是没有anim文件夹的,这个时候是需要你自己创建的!
###2.1 平移动画 (TranslateAnimation)
平移动画的效果就不去结束了。这里简单介绍一下里面用到的属性!
- fromXDelta 表示x的起始值,比如0,0%p
- fromYDelta 表示y的起始值,比如100,100%p
- toXDelta 表示x的结束值
- toYDelta 表示y的结束值
这里如果直接设置距离的话,是从控件的原始位置开始计算的距离,如果设置百分比0%和100%都是相当于父控件而言的,其实位置设置的是控件开始的位置开始计算!这两点记住就可以了,剩下的看一下效果就可以了!
上面用到的XML设置为:
<?xml version="1.0" encoding="utf-8"?><!--平移动画的显示-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:fillAfter="true">
<translate
android:fromXDelta="0"
android:toXDelta="100%" />
</set>
其实这里我只设置了X轴的位移,感兴趣的童鞋可以设置一下Y轴的距离看下效果!当然上面的代码也是可以通过代码进行设置的!像这个样子。。。
//代码设置
TranslateAnimation translateAnimation = new TranslateAnimation(0,1000,0,0);
translateAnimation.setDuration(500);
translateAnimation.setFillAfter(true);
mIvIcon.startAnimation(translateAnimation);
2.2 旋转动画(RotateAnimation)
“旋转跳跃,我闭上眼”就是这种效果了,旋转动画只要你注意好中心点位置的确定就可以了。先看一下常用的属性!!!
- android:fromDegrees 旋转的开始角度
- android:toDegrees 旋转的结束角度
- android:pivotX 旋转的x轴点
- android:pivotY 旋转的y轴点
上面用到的XML设置为:
<?xml version="1.0" encoding="utf-8"?><!--平移动画的显示-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:fillAfter="true">
<rotate
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="360" />
</set>
上面效果代码设置为:
RotateAnimation rotateAnimation = new RotateAnimation(0, 360, mIvIcon.getWidth() / 2, mIvIcon.getHeight() / 2);
rotateAnimation.setDuration(1000);
mIvIcon.startAnimation(rotateAnimation);
2.3 缩放动画(ScaleAnimation)
缩放动画的缩放位置的确定对于整个动画是至关重要的一个点,如果你位置选择的不对,那么效果会差很远,所以选择位置是最为重要的!!!先介绍一下相应的属性
- android:fromXScale x水平方向缩放起始值,比如:0
- android:fromYScale y水平方向缩放起始值,比如:0
- android:toXScale x竖直方向缩放起始值
- android:toYScale y竖直方向缩放起始值
- android:toXScale 缩放轴点的X坐标
- android:toYScale 缩放轴点的Y坐标
上面用到的XML设置为:
<?xml version="1.0" encoding="utf-8"?><!--平移动画的显示-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:fillAfter="true">
<scale
android:fromXScale="100%"
android:fromYScale="100%"
android:pivotX="0"
android:pivotY="0"
android:toXScale="50%"
android:toYScale="50%" />
</set>
上面效果代码设置为:
ScaleAnimation scaleAnimation = new ScaleAnimation(mIvIcon.getWidth(), mIvIcon.getWidth() / 2, mIvIcon.getHeight(), mIvIcon.getHeight() / 2, 0, 0);
scaleAnimation.setDuration(1000);
mIvIcon.startAnimation(scaleAnimation);
这里其实你知道只要一个东西,缩放点和缩放的距离,只要计算好这个就可以了!
2.4 渐变动画 (AlphaAnimation)
这个动画就比较好理解了!就是透明度的变化而已!!!属性如下:
- android:fromAlpha 透明度的起始值
- android:toAlpha 透明度的结束值
上面用到的XML设置为:
<?xml version="1.0" encoding="utf-8"?><!--平移动画的显示-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:fillAfter="true">
<alpha
android:fromAlpha="1"
android:toAlpha="0.5" />
</set>
上面效果代码设置为:
AlphaAnimation scaleAnimation = new AlphaAnimation(1, 0);
scaleAnimation.setDuration(1000);
mIvIcon.startAnimation(scaleAnimation);
上面所有XML的加载的代码如下:
Animation translateAnimation = AnimationUtils.loadAnimation(this,R.anim.XXX);
mIvAnimation.startAnimation(translateAnimation);
当然你也可以直接把上面所有的动画加以组合,写在一个XML中,像这样
<?xml version="1.0" encoding="utf-8"?><!--平移动画的显示-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="5000"
android:fillAfter="true">
<translate
android:fromXDelta="0"
android:toXDelta="100%" />
<rotate
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="360" />
<scale
android:fromXScale="100%"
android:fromYScale="100%"
android:pivotX="0"
android:pivotY="0"
android:toXScale="50%"
android:toYScale="50%" />
<alpha
android:fromAlpha="1"
android:toAlpha="0.5" />
</set>
其实有的人很纠结,视图动画是用代码写还是用XML去写,其实我个人觉得,动画还是写在xml中,因为这样,复用的可能性很大,如果你用代码写,除非写个工具类。这个就看你们的需求了,不要去纠结这个东西,喜欢就好!
2.5 设置相应的监听
有些特殊需要,在动画执行完成的时候做一些相应的操做,所有就要监听动画的执行的一些状态,如:开始、结束、再次执行!相应的监听方法如下:
animaton.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
//动画开始时回调
}
@Override
public void onAnimationEnd(Animation animation) {
//动画结束时回调
}
@Override
public void onAnimationRepeat(Animation animation) {
//对话重复执行的时候回调
}
});
基本上平时的项目中关于视图动画就能用到这么多,有什么总结不到位的还请个位大神指教!!!
2.6 一些项目中的使用案例
2.6.1 ViewGroup上面使用视图动画
关于这个内容来说的话,可就厉害了。怎么厉害呢?其实这种动画效果时很好的!先看一张实现的效果图!
上面的图片时视图动画配合layoutAnimation实现的,还是比较好看的吧!这里就有一个相应的layoutAnimation的概念了!它是操作整个ViewGroup的动画(可以是任何的ViewGroup的控件),可以实现延时的效果!先介绍一下相应的属性吧!
- android:delay 表示动画的时间延迟,比如子元素入场动画的时间周期为300ms,那么0.5表示每个子元素都需要延迟150ms才能播放入场动画
- android:animationOrder 表示动画元素的顺序,有三种顺序选项:normal,reverse,random在其中normal表示顺序显示;reverse表示逆向显示;random则表示随机显示
- android:animation 为元素指定具体的入场的动画
上面就是一些相应的属性标签了。下面我们来看看怎么使用!其实也很简单, 当你创建这个动画的使用像这样创建
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:animation="@anim/translate_animation"//这里设置的是内部子View的动画样式!!!
android:animationOrder="normal"
android:delay="0.5"/>
你可以将这个xml使用在需要的控件中
,像这样android:layoutAnimation="@anim/item_layoutanimation"
也可以使用代码设置像这样
Animation animation = AnimationUtils.loadAnimation(this, R.anim.XXX);
LayoutAnimationController controller = new LayoutAnimationController(animation);
controller.setDelay(0.5f);
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
View.setLayoutAnimation(controller);
View.startAnimation(animation);//这句是开始动画用的
这里注意一点就是XXX代表的是普通的动画,而不是layoutAnimation为根节点的动画哦!!!动画的XML别弄错了!这个让我想起了当时写MD的时候用到的相应的动画,感觉和这个一样!嘻嘻...
- Activity切换的动画
关于这个问题我之前在MD的文章中说到过,所以这里就不说了!感兴趣的童鞋可以看看MaterialDesign系列文章(三)过渡动画的实现这里就不说明了!哈哈,其实我发现我真的很懒,不是吗?
3.帧动画的使用:
关于帧动画的使用方案,基本上都大同小异,美工丢过来一套图,然后你设置一下。最后展示就可以了,基本上流程都是一样的!但是对于帧动画的缺点就是,当你使用的图片多了的时候,很容易OOM。所以动画不多的情况下建议使用帧动画,否则不建议使用!!!使用帧动画的大体流程是这样的!
共有属性介绍:
- android:oneshot="false" false 无限循环
使用步骤介绍:
- 创建相应的帧动画文件:(注意啊!这个文件的位置是drawable,而不是anim了)
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="true">
<item
android:drawable="@mipmap/icon1"
android:duration="500"/>
<item
android:drawable="@mipmap/icon2"
android:duration="500"/>
<item
android:drawable="@mipmap/icon3"
android:duration="500"/>
<item
android:drawable="@mipmap/icon4"
android:duration="500"/>
<item
android:drawable="@mipmap/icon5"
android:duration="500"/>
<item
android:drawable="@mipmap/icon6"
android:duration="500"/>
</animation-list>
- 加载相应的动画
imageView.setBackgroundResource(R.drawable.animation_list);
AnimationDrawable drawable = (AnimationDrawable)view.getBackground();
drawable.start();
4.属性动画的使用
属性动画时在Android3.0中引用的,相对有视图动画来说。可以改变控件的位置!内部实现时是通过改变控件的属性值进行作用的!因为这个原因,所以可以改变View相应的具体大小和位置等一系列相应的属性!其实关于属性动画包含的内容包含:
- ValueAnimator
- ObjectAnimator 继承ValueAnimator
- TimeAnimator 继承ValueAnimator
- AnimatorSet 动画集合
- 属性动画的XML设置
- 遇到的问题
我们就一个一个来说吧!ValueAnimator这个是3.0属性动画的父类,提供了一些常用的方法,供子类实现!所以这里就直接跳过这段,直接讲解相应的子类,所谓的子承父业,子类明白了!父类就明白了!
4.1 ValueAnimator的使用
你说这个是显现动画的吧!其实还不算,他只是改变相应的属性而已!因为是父类,没有什么好说明的,但是它有一个常用的场景,就是动态改变对象的某些属性!像下面这样!!!
ValueAnimator animator = ValueAnimator.ofInt(0,400);
animator.setDuration(1000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int curValue = (int)animation.getAnimatedValue();
//这里你可以动态的改变一些属性
}
});
animator.start();
4.2 ObjectAnimator的使用
这个类可就厉害了,是通过改变相应的属性,来实现动画的,那么问题来了,所谓的属性都有哪些呢?最开始的时候我接触这个动画,说是属性动画,但是具体都包含哪些属性我怎么知道呢?后来我知道了,但凡有get/set方法的属性都可以设置,先给你们来到开胃菜!!!先看看下面这个效果!
ValueAnimator colorAnim = ObjectAnimator.ofInt(mRvBg, "backgroundColor", 0xffff8080, 0xff8080ff);
colorAnim.setDuration(3000);
colorAnim.setEvaluator(new ArgbEvaluator());/*设置估值器*/
colorAnim.setInterpolator(new AccelerateDecelerateInterpolator());/*设置插值器*/
colorAnim.setRepeatCount(ValueAnimator.INFINITE);/*设置循环次数,这里是无限循环的*/
colorAnim.setRepeatMode(ValueAnimator.REVERSE);/*设置循环模式-这里设置的是逆向模式*/
colorAnim.start();
这个是通过改变背景,实现的效果。那么问题来了,我怎么知道有什么属性可以设置!你只要明白属性这个概念就行,你平时用json接受数据的时候,里面的参数就是属性!怕你不懂,这里还是来张图大概看看就可以了!
常用的API:
- setDuration 设置时间
- setEvaluator 设置估值器
- IntEvaluator (针对帧数属性)
- FloatEvaluator (针对浮点数属性)
- ArgbEvaluator (针对Color属性)
- setInterpolator 设置插值器
- TimeInterpolator 时间插值器
- LinearInterpolator 线性插值器(匀速动画)
- AccelerateDecelerateInterpolator 加速减速插值器(动画两头慢中间快)
- DecelerateInterpolator 减速插值器(动画越来越慢)
- setRepeatCount 设置循环次数
- setRepeatMode 设置模式
还有很多的API没有实际用到,也不太好意思和大家说!怕我自己理解错了,误导大家!嘻嘻。。。
其实关于属性动画,只要你记住它改变的属性就好了,变化后就会实实在在的显示在那里了(或者位置实实在在的发生变化)!所以并不会存在视图动画那种只改变显示的问题!一般在项目中用到最多的写法像下面这样!
ObjectAnimator.ofFloat(mIvAnimation, "rotationX", 0, 360),//X轴旋转
ObjectAnimator.ofFloat(mIvAnimation, "rotationY", 0, 180),//Y轴旋转
ObjectAnimator.ofFloat(mIvAnimation, "rotation", 0, -90),//旋转
ObjectAnimator.ofFloat(mIvAnimation, "translationX", 0, 90),//x轴平移
ObjectAnimator.ofFloat(mIvAnimation, "translationY", 0, 90),//y轴平移
ObjectAnimator.ofFloat(mIvAnimation, "scaleX", 1, 1.5f),//X轴缩放
ObjectAnimator.ofFloat(mIvAnimation, "scaleY", 1, 0.5f),//Y轴缩放
ObjectAnimator.ofFloat(mIvAnimation, "alpha", 1, 0.25f, 1)//渐变
这里面引号里面的都是相应的属性值,直接写属性名称就好了!其实ObjectAnimator还有ofInt()等的一些API这些API和他的区别主要是操作的属性类型有关,因为怕丢失精度吧!!!还有一些ofMultiFloat()等一些API是可以同时操作多个属性值的API,这里面大家自己尝试一下就可以了!和上面的写法都大同小异。对了不知道你们在赋值参数的时候,看不看提示,其实ofFloat最后一个参数传入的是一个可变数组,说明最后可以传入无限个参数(只要你想!!!)。
这里面还差一个监听的问题:关于监听
public static interface AnimatorListener {
//动画开始的监听,初始化一些资源
void onAnimationStart(Animator animation);
//动画结束的监听,释放一些资源
void onAnimationEnd(Animator animation);
//动画取消的监听,释放一些资源
void onAnimationCancel(Animator animation);
//动画重复执行的监听,重置一些参数
void onAnimationRepeat(Animator animation);
}
4.3 TimeAnimator使用
这个是根据时间变化来设置一些属性的,提供了一个简单的回调机制,通过 TimeAnimator.TimeListener,在动画的每一帧处通知你。这个动画器没有时间,插值或是对象值设定。回调监听器为每一帧动画接受信息,包括总运行时间和从前一帧到现在的运行时间。里面的方法很少,就一个监听然后返回给你总时间和当前一帧的时间!具体的监听如下:
public static interface TimeListener {
void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime);
}
4.4 AnimatorSet 动画集合
把你需要的动画集合整合到一起执行!也可以按照一定的顺序去执行!
AnimatorSet set = new AnimatorSet();
set.playTogether(
ObjectAnimator.ofFloat(mIvAnimation, "rotationX", 0, 360),//X轴旋转
ObjectAnimator.ofFloat(mIvAnimation, "rotationY", 0, 180),//Y轴旋转
ObjectAnimator.ofFloat(mIvAnimation, "rotation", 0, -90),//旋转
ObjectAnimator.ofFloat(mIvAnimation, "translationX", 0, 90),//x轴平移
ObjectAnimator.ofFloat(mIvAnimation, "translationY", 0, 90),//y轴平移
ObjectAnimator.ofFloat(mIvAnimation, "scaleX", 1, 1.5f),//X轴缩放
ObjectAnimator.ofFloat(mIvAnimation, "scaleY", 1, 0.5f),//Y轴缩放
ObjectAnimator.ofFloat(mIvAnimation, "alpha", 1, 0.25f, 1)//渐变
);
set.setDuration(500).start();
代码没有什么好说的,只是看一下写法就可以了!playTogether()这一个API!如果你像让动画一个一个的执行,换一个API (playSequentially(Animator... items)) 就可以了!代码在这里就不贴了!!!里面还有一些方法,什么是否开始,是否正在运行的!大家去看一下就可以了!
4.5 属性动画的XML设置
属性动画的各个参数都比较好理解,在XML中可以定义ValueAnimation,ObjectAnimator以及AnimatorSet,其中AnimatorSet对应标签,ValueAnimator对应标签,ObjectAnimator对应标签,惯例先说名一下可以使用的标签
-
<Set>标签的详细属性
- android:ordering动画的播放顺序,有两个参数可选;
- 1.together代表所有子动画同时执行;
- 2.sequentially代表所有子动画按照先后顺序执行.默认是together
- android:ordering动画的播放顺序,有两个参数可选;
-
<objectAnimator> 和 <animator>标签的详细属性
- android:propertyName 表示属性动画的作用对象的属性名称
- android:duration 表示动画的时长
- android:valueFrom 表示属性动画的初始值
- android:valueTo 表示属性的结束值
- android:startOffset 表示动画的延迟时间,当动画开始后,需要延迟多少毫秒才能真正播放动画
- android:repeatCount 表示动画的重复次数
- android:repeatMode 表示动画的重复模式
- android:valueType 表示Android:propertyName所制定的属性的类型,有"intType"和"floatType"两个选项,分别代表整型和浮点型,如果android:propertyName所指定的属性表示的是颜色的话,那么就不需要指定android:valueType系统会自动对颜色类型进行属性处理
ps:这做下说明:
- android:repeatCount 表示动画循环的次数 默认是0 当为-1的时候表示无线循环
- android:repeatMode 表示动画的循环模式 逆向重复的时候是指当第一次播放完成的时候,第二次会倒着播放动画,第三次在从头开始播放动画,第四次在倒着播放,以此循环
XML实例
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="together">
<objectAnimator
android:duration="300"
android:propertyName="x"
android:valueTo="200"
android:valueType="intType"/>
<objectAnimator
android:duration="300"
android:propertyName="y"
android:valueTo="200"
android:valueType="intType"/>
</set>
代码中使用
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.animator_anim);
set.setTarget(mIvAnimation);
set.start();
还是强烈建议使用动画的时候最好使用XML去写,因为这样可以更好的复用!相信我,要么你每次写动画的时候都会写一堆代码!
4.5 遇到的问题
任意对象使用属性动画必要条件:
- 要有相应的get/set方法,否则会报异常
- 相应的get/set方法要能直观的从UI层面上反应出来,否则看不见效果
- 还有一点要注意的是这个属性动画是作用在View的对象上,所以应该是View有的属性,而不是继承它的对象重新生成的属性
针对于继承的View要使用属性动画的情况,官方给出了相应的解决方案:
- 给对象加上相应的get/set方法(如果你有权限的话)
- 用一个类来包装原始对象,间接的提供get/set方法
/**
* author : 贺金龙
* create time : 2017/10/29 14:21
* description : 包装类,为了向外面提供相应的get/set方法
* instructions : 因为没有相应改变宽度和高度的方法,所以这里自己包装一个相应的get/set方法
* version :
*/
public class ViewWrapper {
private View mTargetView;
/**
* author : 贺金龙
* create time : 2017/10/29 14:28
* description : 传入相应的View,进行设置一些内容
* instructions :
* version :
*/
public void setTargetView(View targetView) {
mTargetView = targetView;
}
/**
* author : 贺金龙
* create time : 2017/10/29 14:30
* description : 获取宽度的方法
* instructions :
* version :
*/
public int getWidth() {
return mTargetView.getLayoutParams().width;
}
/**
* author : 贺金龙
* create time : 2017/10/29 14:31
* description : 设置宽度的方法
* instructions : 设置相应的宽度
* version :
*
* @param width 宽度
*/
public void setWidth(int width) {
mTargetView.getLayoutParams().width = width;
/*重新绘制View的方法*/
mTargetView.requestLayout();
}
}
代码中的使用
//使用的代码
ViewWrapper wrapper = new ViewWrapper();
wrapper.setTargetView(view);
ObjectAnimator.ofInt(wrapper, "width", 0, 500).setDuration(1000).start();
上面注释已经写的很详细了,说下大体的思路,传入一个View并通过LayoutParams设置相应的宽高,这样就相当于变相的设置了View的宽高了
关于动画的内容平时开发的时候就总结这么多,还有很多细节没有讲解到,文章写的也比较乱,希望大家不要介意,毕竟我不是文科毕业!我语文分数也不高!!!不好意思了,如果你遇到什么不理解的,可以给我留言。我看到的一定帮你解决!哈哈 ,今天就到这里吧!拜拜。。。