一.概述
Android中的动画有:帧动画,View动画(补间),属性动画;本文主要介绍前两种,后者单独拿出来写。
1.1本文解决的问题
- 帧动画的基本用法
- View动画的基本用法
- LayoutAnimation的用法(给列表用的layoutAnimation;给网格表用的gridLayoutAnimation)
1.2帧动画的特点
在View中播放一张张的图。
2.2补间动画
2.2.1只能对View进行操作
2.2.2四种动画写死,不具备扩展性
2.2.3只是改变了视觉感,属性没变(例如位置,一个View从a到b点,点击b位置没有反应)
二.帧动画
帧动画就像是早期的胶片电影,一张张连续播放图片,使眼睛产生动画效果。给View都可以设置,包括他的子类VIewGroup。
2.1先从ViewGroup开始。
Activity中代码
public class FrameAniActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_frame_ani);
LinearLayout ll = (LinearLayout) findViewById(R.id.show_ll);
ll.setBackgroundResource(R.drawable.frame_animation_loading);
AnimationDrawable ani = (AnimationDrawable) ll.getBackground();
//动画是否只是执行一次
ani.setOneShot(false);
ani.start();
}
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">
<LinearLayout
android:id="@+id/show_ll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"/>
</LinearLayout>
动画drawable文件,ani_1等是三张不同的图,这里不贴出来了就。每隔0.5s播放一次。
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ani_1" android:duration="500"/>
<item android:drawable="@drawable/ani_2" android:duration="500"/>
<item android:drawable="@drawable/ani_3" android:duration="500"/>
</animation-list>
当然也可以将drawable动画文件直接写在布局文件中,如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">
<LinearLayout
android:id="@+id/show_ll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/frame_animation_loading"
android:orientation="vertical"/>
</LinearLayout>
2.2所有View都可以用backGround的方式添加帧动画,并且Imageview等可以用src来添加如下:
布局文件中background改为src,Activity中改为使用getDrawable取
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">
<ImageView
android:id="@+id/show_ll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/frame_animation_loading"
android:orientation="vertical"/>
</LinearLayout>
Activity中
public class FrameAniActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_frame_ani);
ImageView im = (ImageView) findViewById(R.id.show_ll);
AnimationDrawable ani = (AnimationDrawable) im.getDrawable();
ani.setOneShot(false);
ani.start();
}
}
看图如下
还有几个常用方法
//停止播放,停止在正在播放的那一帧;调用start后继续播放
ani.stop();
//显示第i帧图
ani.selectDrawable(i);
//动画是否只是执行一次
ani.setOneShot();
三.补间动画(View动画)(sdk的版本是26的)
从构造方法看每个动画的特点
有下面四种,下面是他们的构造方法,思路都是有起点,有终点
//透明度动画
//fromAlpha透明度起点;toAlpha透明度终点
public AlphaAnimation(float fromAlpha, float toAlpha)
//平移动画
//参数为:平面上x,y轴方向上的起点和终点(单位是px)
public TranslateAnimation(float fromXDelta, float toXDelta, float fromYDelta, float toYDelta)
//缩放动画
//参数:x,y轴方向上的缩放(单位是倍数)
public ScaleAnimation(float fromX, float toX, float fromY, float toY)
//含有缩放原点的构造方法(多了缩放原点坐标),默认是0,0
public ScaleAnimation(float fromX, float toX, float fromY, float toY,float pivotX, float pivotY)
//旋转动画
//参数是:起始的旋转度数
public RotateAnimation(float fromDegrees, float toDegrees)
//含有旋转原点的构造方法(默认是0,0)
public RotateAnimation(float fromDegrees, float toDegrees, float pivotX, float pivotY)
上面的默认原点都是(0,0),这个坐标的含义是:这个view的左上角的点为原点(0,0);
当然除了使用java代码来完成动画的加载还可以使用加载 动画xml文件的方式,系统为我们提供了AnimationUtils类来简化我们的工作。下面是四种动画通过java代码方式和加载xml文件方式实现View动画;
注意:sdk的版本是26的,在xml文件中不能定义duration和interpolator属性,只能在java代码中设置动画时间和差值器分别使用setDuration和setInterpolator。
3.1AlphaAnimation (透明度动画),里面的im指的是Imageview,只要是View其实都可以;
java中实现
AlphaAnimation alphaAnimation = new AlphaAnimation(0,1);
alphaAnimation.setDuration(3000);
im.setAnimation(alphaAnimation);
alphaAnimation.start();
xml文件中加载
java代码
Animation animation = AnimationUtils.loadAnimation(this,R.anim.alpha_anim);
animation.setDuration(3000);
im.startAnimation(animation);
xml动画文件
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:fromAlpha="0"
android:toAlpha="1" />
3.2TranslateAnimation (平移动画)
只是用java
TranslateAnimation translateAnimation = new TranslateAnimation(0,100,0,100);
translateAnimation.setDuration(3000);
im.setAnimation(translateAnimation);
translateAnimation.start();
translateAnimation.setFillAfter(true);//设置为true,动画完了之后停留在最后状态;false的话会返回view的初始状态
使用xml文件
Animation animation = AnimationUtils.loadAnimation(this,R.anim.translate_ani);
animation.setDuration(3000);
im.startAnimation(animation);
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="0"
android:toXDelta="100"
android:fromYDelta="0"
android:toYDelta="100" />
3.3ScaleAnimation (缩放动画)
只是用java
ScaleAnimation scaleAnimation = new ScaleAnimation(1,2,1,2);
scaleAnimation.setDuration(3000);
im.setAnimation(scaleAnimation);
scaleAnimation.start();
从xml中加载
Animation animation = AnimationUtils.loadAnimation(this,R.anim.scale_ani);
animation.setDuration(3000);
im.setAnimation(animation);
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXScale="1"
android:toXScale="3"
android:fromYScale="1"
android:toYScale="3"
android:pivotX="100"
android:pivotY="100"/>
3.4RotateAnimation (旋转动画)
只使用java
RotateAnimation rotateAnimation = new RotateAnimation(0,180);
rotateAnimation.setDuration(3000);
im.setAnimation(rotateAnimation);
rotateAnimation.start();
使用xml文件
Animation animation = AnimationUtils.loadAnimation(this,R.anim.rotate_ani);
animation.setDuration(3000);
im.startAnimation(animation);
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="90"
android:toDegrees="270" />
3.5应该注意的点
3.5.1缩放和旋转中涉及的原点
在xml文件中含有android:pivotX和android:pivotY两个属性的,注意这两个的单位这里可以是
1.确切的float数值如10,单位是px;
2.View自身尺寸百分比如50%;
3.父控件尺寸的百分比如20%p;
3.5.2.动画的重复执行
setRepeatCount:在动画结束之后,动画重复执行的次数;
setRepeatMode:在动画结束之后,动画重复执行,执行是从开始重新执行还是从后往前倒退执行;(参数:RESTART和REVERSE两个int常量来标识)
3.5.3.动画执行完后,停留在什么状态
setFillEnabled:true,使setFillBefore中属性生效;false,相反不生效;(默认false)
setFillBefore:true,动画结束时还原到开始动画前的状态;false,不还原;(默认true)
setFillAfter:true,动画结束停留在结束状态;false,还原到动画开始状态;(默认false)
3.5.4.动画的监听,从字面意思也可以理解监听的是什么状态,如下
setAnimationListener(new Animation.AnimationListener() {
public void onAnimationStart(Animation animation)
public void onAnimationEnd(Animation animation)
public void onAnimationRepeat(Animation animation) }
3.6当然除了可以单独使用之外,各个动画还可以组合使用,这涉及到AnimationSet
例如下面的,给imageview添加了一个透明度和一个旋转动画,同时执行
ImageView im = (ImageView) findViewById(R.id.show_im);
AnimationSet animationSet = new AnimationSet(true);
AlphaAnimation alphaAnimation = new AlphaAnimation(0,1);
alphaAnimation.setDuration(2000);
RotateAnimation rotateAnimation = new RotateAnimation(0,360);
rotateAnimation.setDuration(2000);
animationSet.addAnimation(alphaAnimation);
animationSet.addAnimation(rotateAnimation);
im.setAnimation(animationSet);
animationSet.start();
当然也可以加载xml文件中的方式如下,实现的效果和上面是一样的
ImageView im = (ImageView) findViewById(R.id.show_im);
Animation animation = AnimationUtils.loadAnimation(this,R.anim.set_ani1);
im.startAnimation(animation);
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:shareInterpolator="true">
<alpha android:fromAlpha="0" android:toAlpha="1"/>
<rotate android:fromDegrees="0" android:toDegrees="360"/>
</set>
这里注意,补间动画没有实现像属性动画中那样可以将动画分前后顺序执行的方法,若想那样只能在一个动画中设置监听,等完成后再执行另一个动画。
如下面先一个透明度和旋转动画,然后接着一个缩放动画
Activity中代码
ImageView im;
Animation animation1;
Animation animation2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_frame_ani);
im = (ImageView) findViewById(R.id.show_im);
animation1= AnimationUtils.loadAnimation(this,R.anim.set_ani1);
im.startAnimation(animation1);
animation1.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
startSecondAnimotion();
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
private void startSecondAnimotion() {
animation2 = AnimationUtils.loadAnimation(this,R.anim.scale_ani);
animation2.setDuration(3000);
animation2.setFillAfter(true);
im.startAnimation(animation2);
}
透明度和旋转动画
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:shareInterpolator="true">
<alpha android:fromAlpha="0" android:toAlpha="1"/>
<rotate android:fromDegrees="0" android:toDegrees="360" android:pivotX="50%" android:pivotY="50%"/>
</set>
缩放动画的xml
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXScale="1"
android:toXScale="3"
android:fromYScale="1"
android:toYScale="3"
android:pivotX="50%"
android:pivotY="50%" />
3.7自定义View动画
实际开发中很少用自定义View动画,因为我们可以使用属性动画,更灵活。若想自定义View动画的画,那么关键两个方法:initialize和applyTransformation,前者进行初始化工作,后者中进行相应的矩阵变换;但是因为自定义View动画中进行的是矩阵变换的过程,这需要数学基础,所以就显得复杂了。
四.LayoutAnimation
LayoutAnimation也是View动画,只是作用于ViewGroup,使ViewGroup的子View拥有设计的动画效果。LayoutAnimation相当于在四种View动画的外面增加了一层,实质也是View动画。
4.1首先,看给普通列表添加初始化时候动画(使用layoutAnimation)
下面我们以RecyclerView为例,先看效果,这是其初始加载的效果:
顺序播放
逆序播放
随机播放
下面是代码,很简单,给RecyclerView添加了layoutAnimation属性(也就是上面说的ViewGroup的动画),其他和使用普通RecyclerView没什么不同。只贴出布局文件和动画文件。
布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.gong.recyclerview.LayoutAnimationActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/show_rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
//关键点
android:layoutAnimation="@anim/layout_animation_rv"/>
</LinearLayout>
layoutAnimation动画文件;其中字段的含义如下:
- delay:延迟加载因子,如动画中时间为1000ms那么延迟时间为500ms;
- interpolator:插值器,控制的是播放的“速度”;(系统有几种供选择)
- animation:动画资源;
- animationOrder:ViewGroup中子View播放动画顺序normal(顺序播放),reverse(逆序播放),random(随机播放);依次对应上面的三张gif图;
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:delay="0.5"
android:interpolator="@android:anim/accelerate_interpolator"
android:animation="@anim/set_ani1"
//决定播放顺序
android:animationOrder="normal"/>
动画文件
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:shareInterpolator="true">
<alpha android:fromAlpha="0" android:toAlpha="1"/>
<rotate android:fromDegrees="0" android:toDegrees="360" android:pivotX="50%" android:pivotY="50%"/>
</set>
4.2同时还有一个gridLayoutAnimation用来给GridView添加加载动画的
我们平时最常用RecyclerView来做网格布局,但是它是用不了这个动画的。所以我们用GridView,他的的使用很简单和ListView一样。
动画的关键点在给GridView添加的layoutAnimation为gridLayoutAnimation和4.1中的略有不同。
先看效果
Activity,这里没做其他处理,只是正常使用GridView。
public class LayoutAnimationActivity extends AppCompatActivity {
private RecyclerView showRv;
private List<String> mList = new ArrayList<>();
private LayoutAnimationAdapter mAdapter;
private GridView gridView;
private GridAdapter gridAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layout_animation);
initData();
initView();
}
private void initView() {
gridView = (GridView) findViewById(R.id.show_rv);
gridAdapter = new GridAdapter(this,mList);
gridView.setAdapter(gridAdapter);
}
private void initData() {
for (int i = 'A';i<'z';i++){
mList.add(""+(char)i);
}
}
}
GridAdapter,也是正常使用
public class GridAdapter extends BaseAdapter{
private List<String> mList = new ArrayList<>();
private Context mContext;
public GridAdapter(Context context,List<String> list){
mContext = context;
mList = list;
}
@Override
public int getCount() {
return mList.size();
}
@Override
public Object getItem(int position) {
return mList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null){
convertView = LayoutInflater.from(mContext).inflate(R.layout.item_layout_animation,parent,false);
viewHolder = new ViewHolder();
viewHolder.textView = convertView.findViewById(R.id.show_tv);
convertView.setTag(viewHolder);
}{
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.textView.setText(mList.get(position));
return convertView;
}
class ViewHolder{
TextView textView;
}
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.gong.recyclerview.LayoutAnimationActivity">
<GridView
android:id="@+id/show_rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:numColumns="4"
//添加layoutAnimation属性
android:layoutAnimation="@anim/grid_layout_animation_rv"/>
</LinearLayout>
关键:grid_layout_animation_rv(ViewGroup的文件)
<?xml version="1.0" encoding="utf-8"?>
<gridLayoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:columnDelay="0.5"
android:rowDelay="0"
android:direction="left_to_right|top_to_bottom"
android:directionPriority="row"
android:animation="@anim/set_ani1"/>
解释:
- animation:动画资源
- directionPriority:动画进行的优先级,是先行还是先列row(先行),column(先列),none(行列一起进行)
- direction:动画进行的方向left_to_right,right_to_left,top_to_bottom,bottom_to_top,从字面意思很好理解
- rowDelay:行方向上延迟时间因子
- columnDelay:列方向上延迟时间因子
- 注意:上面几个参数搭配使用可以产生不同的效果
动画文件
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="400"
android:shareInterpolator="true">
<alpha android:fromAlpha="0" android:toAlpha="1"/>
<rotate android:fromDegrees="0" android:toDegrees="360" android:pivotX="50%" android:pivotY="50%"/>
</set>