前言:
动画在安卓开发中的使用非常普遍,基本上任何带有动效的转换都是基于动画实现的。那么接下来我们就来了解一下安卓中的几大动画。
动画的分类:
安卓中把动画分为三大类:帧动画、补间动画、属性动画。而严格意义上来说这三种动画其实就是Android3.0之前的传统动画和3.0之后的属性动画,传统动画又分为帧动画和补间动画。
1.帧动画:
帧动画要说是三种动画中比较简单的一种了,它是基于一连串的图片完成的,它的原理就是将一张张单独的图片进行连续播放,从而在视觉上产生一种动画的效果;有点类似于某些软件制作gif动画的方式。
上图中的动画就是通过帧动画播放一连贯的图片实现的视觉上的动效,附上drawable的XML和java代码:
<?xml version="1.0" encoding="utf-8"?>
<!--
android:oneshot="true" 表示帧动画是否重复播放,默认为false,true表示只播放一次
-->
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item
android:drawable="@drawable/p00"
android:duration="200"/>
<item
android:drawable="@drawable/p11"
android:duration="200"/>
<item
android:drawable="@drawable/p22"
android:duration="200"/>
<item
android:drawable="@drawable/p33"
android:duration="200"/>
<item
android:drawable="@drawable/p44"
android:duration="200"/>
</animation-list>
Activity代码:
package com.example.administrator.myapplication;
import android.graphics.drawable.AnimationDrawable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
public class FrameActivity extends AppCompatActivity {
private ImageView iv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_zhen);
iv = ((ImageView) findViewById(R.id.frame_iv));
iv.setImageResource(R.drawable.frame);
}
public void playFrameAnim(View view) {
AnimationDrawable ad = (AnimationDrawable) iv.getDrawable();
//判断帧动画是否正在播放
if (ad.isRunning()) {
//停止播放
ad.stop();
}else {
//开始播放
ad.start();
}
}
}
2.补间动画:
补间动画又可以分为四种形式:alpha(淡入淡出)、translate(位移)、scale(缩放)、rotate(旋转)。
补间动画的实现,一般会采用xml 文件的形式;代码会更容易书写和阅读,同时也更容易复用(当然也是可以在java代码中实现)。
补间动画作用的最小元素为View,补间动画的执行并不会真正改变控件的属性值默认情况下,补间动画的执行速率都是先加速后减速,插值器用来控制动画的执行速率,通过插值器可以修改动画的执行速率
XML中实现:
首先在res/anim/ 文件夹下定义如下的动画实现方式:
alpha_anim.xml 动画实现
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fromAlpha="1.0"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:toAlpha="0.0" />
scale_anim.xml 动画实现
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fromXScale="0.0"
android:fromYScale="0.0"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1.0"
android:toYScale="1.0"/>
translate_anim.xml 动画实现
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="200"
android:toYDelta="200" />
rotate_anim.xml 动画实现
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="infinite"
android:repeatMode="restart"
android:toDegrees="359"/>
也可以使用set 标签将多个动画进行组合
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<alpha
android:fromAlpha="float"
android:toAlpha="float" />
<scale
android:fromXScale="float"
android:toXScale="float"
android:fromYScale="float"
android:toYScale="float"
android:pivotX="float"
android:pivotY="float" />
<translate
android:fromXDelta="float"
android:toXDelta="float"
android:fromYDelta="float"
android:toYDelta="float" />
<rotate
android:fromDegrees="float"
android:toDegrees="float"
android:pivotX="float"
android:pivotY="float" />
<set>
...
</set>
</set>
然后在代码中设置给View:
Animation animation = AnimationUtils.loadAnimation(mContext, R.anim.alpha_anim);
img = (ImageView) findViewById(R.id.img);
img.startAnimation(animation);
经过以上步骤就可以给ImageView设置不同的动画啦。
稍稍介绍:
Interpolator 主要作用是可以控制动画的变化速率 ,就是动画进行的快慢节奏。
pivot 决定了当前动画执行的参考位置。
pivot 这个属性主要是在translate 和 scale 动画中,这两种动画都牵扯到view 的“物理位置“发生变化,所以需要一个参考点。而pivotX和pivotY就共同决定了这个点;它的值可以是float或者是百分比数值。
我们以pivotX为例:
pivotX取值 | 含义 |
---|---|
10 | 距离动画所在view自身左边缘10像素 |
10% | 距离动画所在view自身左边缘 的距离是整个view宽度的10% |
10%p | 距离动画所在view父控件左边缘的距离是整个view宽度的10% |
java代码中实现:
有时候,动画的属性值可能需要动态的调整,这个时候使用xml 就不合适了,需要使用java代码实现。不多说,直接上代码即可,注释都在代码中的啦,小伙伴们很容易就能看懂了。
package com.example.administrator.myapplication;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
public class BujianActivity extends AppCompatActivity {
private ImageView iv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bujian);
iv = ((ImageView) findViewById(R.id.iv));
}
/**
* 代码设置透明度动画
* @param view
*/
public void alphaAn(View view) {
//参数1:当前透明度
//参数2:变化之后的透明度
//参数范围为0~1,0表示完全透明,1表示完全不透明
AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0);
//设置动画执行时间
alphaAnimation.setDuration(3000);
//动画执行完毕时是否保留View执行完时的状态
alphaAnimation.setFillAfter(true);
//延迟启动,参数以毫秒为单位
// alphaAnimation.setStartOffset();
iv.startAnimation(alphaAnimation);
}
/**
* 代码设置缩放动画
* @param view
*/
public void scaleAn(View view) {
//参数1:动画开始时控件的宽度(0表示控件的宽度为实际宽度的0倍)
//参数2:动画结束时控件的宽度(1表示控件的宽度为实际宽度的1倍)
//参数3:动画开始时控件的高度(0表示控件的高度为实际高度的0倍)
//参数4:动画结束时控件的高度(2表示控件的高度为实际高度的2倍)
//使用这种构造方式获取的scale对象,在动画缩放过程中,缩放参考点为左上角
// ScaleAnimation scaleAnimation = new ScaleAnimation(0, 1, 0, 2);
//最后两个参数表示控件缩放的中心点,参考点为控件的左上角
// ScaleAnimation scaleAnimation = new ScaleAnimation(0, 2, 0, 2, iv.getWidth() / 2, iv.getHeight() / 2);
//最后四个参数表示缩放的中心点,ScaleAnimation.RELATIVE_TO_SELF表示缩放参考控件自身,0.5f表示中心点X轴坐标为控件宽度的一半
ScaleAnimation scaleAnimation = new ScaleAnimation(0, 2, 0, 2, ScaleAnimation.RELATIVE_TO_SELF, 0.5f, ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setDuration(3 * 1000);
iv.startAnimation(scaleAnimation);
}
/**
* 代码设置平移动画
* @param view
*/
public void translateAn(View view) {
//1.3参数表示平移的起始点坐标
//2.4参数表示平移的终点坐标
// TranslateAnimation translateAnimation = new TranslateAnimation(0, iv.getWidth(), 0, iv.getHeight());
TranslateAnimation translateAnimation = new TranslateAnimation(TranslateAnimation.RELATIVE_TO_SELF, 0,
TranslateAnimation.RELATIVE_TO_SELF, -1, TranslateAnimation.RELATIVE_TO_SELF, 0, TranslateAnimation.RELATIVE_TO_SELF, -1);
translateAnimation.setDuration(3000);
translateAnimation.setFillAfter(true);
iv.startAnimation(translateAnimation);
}
/**
* 代码设置旋转动画
* @param view
*/
public void rotateAn(View view) {
//1.旋转的起始度数
//2.旋转的结束度数
// RotateAnimation rotateAnimation = new RotateAnimation(0, 359);
// RotateAnimation rotateAnimation = new RotateAnimation(0, 359, iv.getWidth() / 2, iv.getHeight() / 2);
RotateAnimation rotateAnimation = new RotateAnimation(0, 359, RotateAnimation.RELATIVE_TO_SELF,
0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setDuration(3000);
//设置旋转重复次数,INFINITE表示旋转次数无限循环
rotateAnimation.setRepeatCount(RotateAnimation.INFINITE);
//设置重复旋转模式
rotateAnimation.setRepeatMode(RotateAnimation.RESTART);
//设置插值器,使动画匀速执行
rotateAnimation.setInterpolator(new LinearInterpolator());
iv.startAnimation(rotateAnimation);
}
/**
* 代码设置组合动画
* @param view
*/
public void setTogetherAn(View view) {
//true表示所有的动画都使用AnimationSet提供的插值器
AnimationSet set = new AnimationSet(true);
RotateAnimation rotateAnimation = new RotateAnimation(0, 359, RotateAnimation.RELATIVE_TO_SELF,
0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setDuration(3000);
rotateAnimation.setRepeatCount(RotateAnimation.INFINITE);
rotateAnimation.setRepeatMode(RotateAnimation.RESTART);
rotateAnimation.setInterpolator(new LinearInterpolator());
TranslateAnimation translateAnimation = new TranslateAnimation(TranslateAnimation.RELATIVE_TO_SELF, 0,
TranslateAnimation.RELATIVE_TO_SELF, -1, TranslateAnimation.RELATIVE_TO_SELF, 0, TranslateAnimation.RELATIVE_TO_SELF, -1);
//延迟3秒启动平移动画
translateAnimation.setStartOffset(3000);
translateAnimation.setDuration(3000);
translateAnimation.setFillAfter(true);
set.addAnimation(rotateAnimation);
set.addAnimation(translateAnimation);
iv.startAnimation(set);
}
}
再附上效果图:
好了,帧动画和补间动画就讲这么多啦。
3.属性动画:
属性动画,顾名思义,它是对于对象属性的动画,因此,所有补间动画的内容,都可以通过属性动画实现。
属性动画所作用的属性必须要有get/set方法才可以生效(后面会加以解释)。
我们先用属性动画来实现上面的补间动画效果:
java实现:
/**
* 代码中用属性动画实现透明度变化
* @param view
*/
public void alphaProperty(View view) {
//1.该动画要作用的控件
//2.要修改的属性名称
//剩余参数表示属性的变化值
ObjectAnimator alpha = ObjectAnimator.ofFloat(iv, "alpha", 1, 0.5f, 1, 0);
alpha.setDuration(5000);
alpha.setRepeatCount(-1);
alpha.setRepeatMode(ObjectAnimator.REVERSE);
alpha.start();
}
/**
* 代码中用属性动画实现缩放变化
* @param view
*/
public void scaleProperty(View view) {
// ObjectAnimator scale = ObjectAnimator.ofFloat(iv, "scaleX", 0, 1, 0, 2);
ObjectAnimator scale = ObjectAnimator.ofFloat(iv, "scaleY", 0, 1, 0, 2);
scale.setDuration(5000);
scale.start();
}
/**
* 代码中用属性动画实现平移变化
* @param view
*/
public void translateProperty(View view) {
// ObjectAnimator translationX = ObjectAnimator.ofFloat(iv, "translationX", 0, 200);
ObjectAnimator translationX = ObjectAnimator.ofFloat(iv, "translationY", 0, 200);
translationX.setDuration(3000);
translationX.start();
}
/**
* 代码中用属性动画实现旋转变化
* @param view
*/
public void rotateProperty(View view) {
// ObjectAnimator rotation = ObjectAnimator.ofFloat(iv, "rotation", 0, 359);
// ObjectAnimator rotation = ObjectAnimator.ofFloat(iv, "rotationX", 0, 359);
ObjectAnimator rotation = ObjectAnimator.ofFloat(iv, "rotationY", 0, 359);
rotation.setDuration(3000);
rotation.start();
}
/**
* 代码中用属性动画实现组合动画
* @param view
*/
public void togetherProperty(View view) {
ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(myView, "alpha", 1.0f, 0.5f, 0.8f, 1.0f);
ObjectAnimator scaleXAnim = ObjectAnimator.ofFloat(myView, "scaleX", 0.0f, 1.0f);
ObjectAnimator scaleYAnim = ObjectAnimator.ofFloat(myView, "scaleY", 0.0f, 2.0f);
ObjectAnimator rotateAnim = ObjectAnimator.ofFloat(myView, "rotation", 0, 360);
ObjectAnimator transXAnim = ObjectAnimator.ofFloat(myView, "translationX", 100, 400);
ObjectAnimator transYAnim = ObjectAnimator.ofFloat(myView, "tranlsationY", 100, 750);
AnimatorSet set = new AnimatorSet();
set.playTogether(alphaAnim, scaleXAnim, scaleYAnim, rotateAnim, transXAnim, transYAnim);
// set.playSequentially(alphaAnim, scaleXAnim, scaleYAnim, rotateAnim, transXAnim, transYAnim);
set.setDuration(3000);
set.start();
}
XML实现:
首先,在res/animator/ 文件夹下定义如下的动画实现方式:
translation.xml 动画实现(平移)
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:propertyName="translationY"
android:valueFrom="0"
android:valueTo="300"
android:valueType="floatType">
</objectAnimator>
set.xml 动画实现(组合动画)
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="3000"
android:propertyName="translationY"
android:valueFrom="0"
android:valueTo="300"
android:valueType="floatType">
</objectAnimator>
<objectAnimator
android:duration="3000"
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="359"
android:valueType="floatType"/>
</set>
然后我们在java代码中做如下设置即可:
/**
* XML中用属性动画实现平移动画
* @param view
*/
public void xmlAnim(View view) {
Animator animator = AnimatorInflater.loadAnimator(this, R.animator.translation);
//动画作用的控件
animator.setTarget(iv);
animator.start();
}
/**
* XML中用属性动画实现组合动画
* @param view
*/
public void xmlAnim2(View view) {
Animator animator = AnimatorInflater.loadAnimator(this, R.animator.set);
//动画作用的控件
animator.setTarget(iv);
animator.start();
}
接下来我们看看自定义的属性动画,前面我们提到过属性动画作用的属性必须要有get/set方法才有作用。比如现在我们想要自定义一个属性动画来实现imageview的宽度长短的变化。系统没有为我们提供这类动画,所以我们就得自己定义一个width属性,然后结合ObjectAnimator实现宽度变化的动画效果,上代码:
先创建一个java对象,里面有一个width属性:
package com.example.administrator.myapplication;
import android.view.ViewGroup;
import android.widget.ImageView;
/**
* Created by Administrator on 2018/4/12.
*/
public class CustomPropertyModel {
private ImageView imageView;
/**
* 将imageview作为参数传进来
* @param imageView
*/
public CustomPropertyModel(ImageView imageView) {
this.imageView = imageView;
}
public int getWidth(){
return imageView.getLayoutParams().width;
}
/**
* 修改imageview的宽度
* @param width
*/
public void setWidth(int width){
ViewGroup.LayoutParams params = imageView.getLayoutParams();
//重新设置imageview的宽度
params.width = width;
//重新测量宽度并显示
imageView.requestLayout();
}
}
然后在Activity里面给它设置动画:
/**
* 设置宽度变化的自定义属性动画
*/
public void customPropertyWidth(){
CustomPropertyModel customPropertyModel = new CustomPropertyModel(iv);
ObjectAnimator widthAnimation = ObjectAnimator.ofInt(customPropertyModel, "width", 100, 300);
widthAnimation.setDuration(3000);
widthAnimation.start();
}
这样就完成了一个自定义的宽度变化的动画啦,效果如下:
结语:
OK,本篇关于安卓三大动画的基本介绍就到jie里啦,希望小伙伴们能看懂(gif图录制的不是特别清晰,望各位大佬不要介意,嘿哈!)。后续我会继续为大家带来关于属性动画的文章,喜欢的话点个关注啦! 我的博客,欢迎关注