目录
帧动画简介
帧动画非常容易理解,其实就是简单的由N张静态图片收集起来,然后我们通过控制依次显示 这些图片,因为人眼"视觉残留"的原因,会让我们造成动画的"错觉",跟放电影的原理一样!
而Android中实现帧动画,一般我们会用到前面讲解到的一个Drawable:AnimationDrawable先编写好Drawable,然后代码中调用start()以及stop()开始或停止播放动画
当然我们也可以在Java代码中创建逐帧动画,创建AnimationDrawable对象,然后调用 addFrame(Drawable frame,int duration)向动画中添加帧,接着调用start()和stop()而已
帧动画的使用效果
帧动画 帧动画的资源文件,放在drawable文件夹下
代码实现:
接下来编写我们的动画文件,非常简单,先在drawable目录下,接着开始撸我们的 动画文件:miao_gif.xml: 这里的android:oneshot是设置动画是否只是播放一次,true只播放一次,false循环播放!
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item
android:drawable="@mipmap/img_miao1"
android:duration="80" />
<item
android:drawable="@mipmap/img_miao2"
android:duration="80" />
<item
android:drawable="@mipmap/img_miao3"
android:duration="80" />
</animation-list>
动画文件有了,接着到我们的布局文件:activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/btn_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="开始" />
<Button
android:id="@+id/btn_stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="停止" />
<ImageView
android:id="@+id/img_show"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_gravity="center"
android:background="@anim/miao_gif" />
</LinearLayout>
最后是我们的MainActivity.java,这里在这里控制动画的开始以及暂停:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btn_start;
private Button btn_stop;
private ImageView img_show;
private AnimationDrawable anim;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindViews();
anim = (AnimationDrawable) img_show.getBackground();
}
private void bindViews() {
btn_start = (Button) findViewById(R.id.btn_start);
btn_stop = (Button) findViewById(R.id.btn_stop);
img_show = (ImageView) findViewById(R.id.img_show);
btn_start.setOnClickListener(this);
btn_stop.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_start:
anim.start();
break;
case R.id.btn_stop:
anim.stop();
break;
}
}
}
帧动画的使用效果(二)
在点击的地方播放帧动画
代码实现:
activity_main2.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
<TextView android:text="@string/hello_world"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
动画文件:anim_zhuan.xml:
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="true">
<item
android:drawable="@mipmap/img_zhuan1"
android:duration="80" />
<item
android:drawable="@mipmap/img_zhuan2"
android:duration="80" />
<item
android:drawable="@mipmap/img_zhuan3"
android:duration="80" />
</animation-list>
写一个自定义的ImageView:FrameView.java,这里通过反射获得当前播放的帧, 然后是否为最后一帧,然后隐藏控件
public class FrameView extends ImageView {
private AnimationDrawable anim;
public FrameView(Context context) {
super(context);
}
public FrameView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FrameView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setAnim(AnimationDrawable anim){
this.anim = anim;
}
public void setLocation(int top,int left){
this.setFrame(left,top,left + 200,top + 200);
}
@Override
protected void onDraw(Canvas canvas) {
try{
//反射调用AnimationDrawable里的mCurFrame值
Field field = AnimationDrawable.class
.getDeclaredField("mCurFrame");
field.setAccessible(true);
int curFrame = field.getInt(anim);// 获取anim动画的当前帧
if (curFrame == anim.getNumberOfFrames() - 1)// 如果已经到了最后一帧
{
//让该View隐藏
setVisibility(View.INVISIBLE);
}
}catch (Exception e){e.printStackTrace();}
super.onDraw(canvas);
}
}
最后是我们的MainActivity.java,创建一个FrameLayout,添加View,对触摸事件中按下的 事件做处理,显示控件以及开启
public class MainActivity extends AppCompatActivity {
private FrameView fView;
private AnimationDrawable anim = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FrameLayout fly = new FrameLayout(this);
setContentView(fly);
fView = new FrameView(this);
fView.setBackgroundResource(R.anim.anim_zhuan);
fView.setVisibility(View.INVISIBLE);
anim = (AnimationDrawable) fView.getBackground();
fView.setAnim(anim);
fly.addView(fView);
fly.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
//设置按下时才产生动画效果
if(event.getAction() == MotionEvent.ACTION_DOWN){
anim.stop();
float x = event.getX();
float y = event.getY();
fView.setLocation((int) y - 40,(int)x-20); //View显示的位置
fView.setVisibility(View.VISIBLE);
anim.start(); //开启动画
}
return false;
}
});
}
}
补间动画
与前面学的帧动画不同,帧动画是通过连续播放图片来模拟动画效果,而补间动画开发者只需指定动画开始,以及动画结束"关键帧", 而动画变化的"中间帧"则由系统计算并补齐!
补间动画的分类和Interpolator
Andoird所支持的补间动画效果有如下这五种,或者说四种吧,第五种是前面几种的组合而已
-
AlphaAnimation:透明度渐变效果,创建时许指定开始以及结束透明度,还有动画的持续 时间,透明度的变化范围(0,1),0是完全透明,1是完全不透明;对应<alpha/>标签!
-
ScaleAnimation:缩放渐变效果,创建时需指定开始以及结束的缩放比,以及缩放参考点, 还有动画的持续时间;对应<scale/>标签!
-
TranslateAnimation:位移渐变效果,创建时指定起始以及结束位置,并指定动画的持续 时间即可;对应<translate/>标签!
-
RotateAnimation:旋转渐变效果,创建时指定动画起始以及结束的旋转角度,以及动画 持续时间和旋转的轴心;对应<rotate/>标签
-
AnimationSet:组合渐变,就是前面多种渐变的组合,对应<set/>标签
Interpolator
用来控制动画的变化速度,可以理解成动画渲染器,当然我们也可以自己实现Interpolator 接口,自行来控制动画的变化速度,而Android中已经为我们提供了可供选择的实现类:
渲染器 | 说明 |
---|---|
LinearInterpolator | 动画以均匀的速度改变 |
AccelerateInterpolator | 在动画开始的地方改变速度较慢,然后开始加速 |
AccelerateDecelerateInterpolator | 在动画开始、结束的地方改变速度较慢,中间时加速 |
CycleInterpolator | 动画循环播放特定次数,变化速度按正弦曲线改变: Math.sin(2 * mCycles * Math.PI * input) |
DecelerateInterpolator | 在动画开始的地方改变速度较快,然后开始减速 |
AnticipateInterpolator | 反向,先向相反方向改变一段再加速播放 |
AnticipateOvershootInterpolator | 开始的时候向后然后向前甩一定值后返回最后的值 |
BounceInterpolator | 跳跃,快到目的值时值会跳跃,如目的值100,后面的值可能依次为85,77,70,80,90,100 |
OvershottInterpolator | 回弹,最后超出目的值然后缓慢改变到目的值 |
而这个Interpolator 我们一般是在写动画xml文件时会用到,属性是:android:interpolator, 而上面对应的值是:@android:anim/linear_interpolator,其实就是驼峰命名法变下划线而已 AccelerateDecelerateInterpolator对应:@android:anim/accelerate_decelerate_interpolator!
各种补间动画的详细讲解
这里的android:duration都是动画的持续时间,单位是毫秒
AlphaAnimation(透明度渐变)
anim_alpha.xml:
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromAlpha="1.0"
android:toAlpha="0.1"
android:duration="2000"/>
属性解释:
fromAlpha :起始透明度
toAlpha:结束透明度
透明度的范围为:0-1,完全透明-完全不透明
ScaleAnimation(缩放渐变)
anim_scale.xml:
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator"
android:fromXScale="0.2"
android:toXScale="1.5"
android:fromYScale="0.2"
android:toYScale="1.5"
android:pivotX="50%"
android:pivotY="50%"
android:duration="2000"/>
属性解释:
fromXScale/fromYScale:沿着X轴/Y轴缩放的起始比例
toXScale/toYScale:沿着X轴/Y轴缩放的结束比例
pivotX/pivotY:缩放的中轴点X/Y坐标,即距离自身左边缘的位置,比如50%就是以图像的 中心为中轴点
4.2.3 TranslateAnimation(位移渐变)
anim_translate.xml:
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromXDelta="0"
android:toXDelta="320"
android:fromYDelta="0"
android:toYDelta="0"
android:duration="2000"/>
属性解释:
fromXDelta/fromYDelta:动画起始位置的X/Y坐标
toXDelta/toYDelta:动画结束位置的X/Y坐标
RotateAnimation(旋转渐变)
anim_rotate.xml:
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromDegrees="0"
android:toDegrees="360"
android:duration="1000"
android:repeatCount="1"
android:repeatMode="reverse"/>
属性解释:
fromDegrees/toDegrees:旋转的起始/结束角度
repeatCount:旋转的次数,默认值为0,代表一次,假如是其他值,比如3,则旋转4次 另外,值为-1或者infinite时,表示动画永不停止
repeatMode:设置重复模式,默认restart,但只有当repeatCount大于0或者infinite或-1时 才有效。还可以设置成reverse,表示偶数次显示动画时会做方向相反的运动!
AnimationSet(组合渐变)
就是前面几个动画组合到一起
anim_set.xml:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/decelerate_interpolator"
android:shareInterpolator="true" >
<scale
android:duration="2000"
android:fromXScale="0.2"
android:fromYScale="0.2"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1.5"
android:toYScale="1.5" />
<rotate
android:duration="1000"
android:fromDegrees="0"
android:repeatCount="1"
android:repeatMode="reverse"
android:toDegrees="360" />
<translate
android:duration="2000"
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="320"
android:toYDelta="0" />
<alpha
android:duration="2000"
android:fromAlpha="1.0"
android:toAlpha="0.1" />
</set>
4.4 为Activity设置过场动画
Activty设置过场动画非常简单,调用的方法是:overridePendingTransition(int enterAnim, int exitAnim)
用法很简单:在startActivity(intent)或者finish()后添加
参数依次是:新Activity进场时的动画,以及旧Activity退场时的动画
Intent intent = new Intent(MainActivity3.this, MainActivity4.class);
startActivity(intent);
overridePendingTransition(R.anim.anim_alpha, R.anim.anim_scale);