动画与图形
1、Animations介绍
Android提供了几种动画类型:View Animation、Drawable Animation、Property Animation(属性动画)。ViewAnimation分别是Tween动画和Frame动画。Tween通过场景里的对象不断的进行图片的变换,比如平移、渐变、缩放、旋转等来产生动画效果,Frame动画叫做顺序播放事先做好的图像,和电影类似。
2、Tween动画
有四种:
Alpha:透明渐变动画
Scale:缩放动画,渐变尺寸伸缩动画
Translate:移动动画,画面转换位置移动动画
Rotate:旋转动画
这些动画执行步骤差不多:先定义Animation动画对象,然后设置动画的一些属性,最后通过startAnimation()方法开始动画。
//设置动画显示的时间,durationMills为动画显示时间的长短,以毫秒为单位 setDuration(long durationMills); //播放动画,animation为要播放的动画 startAnimation(Animation animation)
第一种:Alpha
(1)通过XML来创建动画alpha_anim.xml。在res/anim目录下:
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <alpha android:duration="5000" android:fromAlpha="0.1" android:toAlpha="1.0" /> </set>
//加载动画资源文件 Animation scale = AnimationUtils.loadAnimation(MainActivity.this, R.anim.alpha_anim); img.startAnimation(scale);
(2)直接在程序中创建动画
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = (TextView) findViewById(R.id.tv); img = (ImageView) findViewById(R.id.img); //创建Alpha动画 Animation alpha = new AlphaAnimation(0.1f, 1.0f); //设置动画时间为5s alpha.setDuration(5000); //开始播放 img.startAnimation(alpha); } }
第二种:.Scale缩放动画
<scale>标签为缩放节点
android:fromXscale="1.0" 表示开始时X轴缩放比例为1.0(原图大小*1.0为原图大小)
android:toXscale="0.0" 表示结束时X轴缩放比例为0.0(原图大小*0.0为缩小到看不见)
android:fromYscale="1.0" (与X轴类似)
android:toYscale="0.0" (与X轴类似)
android:pivotX="50%" X轴所放的位置为中心点
android:pivotY="50%" Y轴缩放的位置为中心点
android:duration="2000" 动画播放时间,这里是2000毫秒,也就是2秒
这个动画布局设置动画从大到小进行缩小
文件夹anim下
little.xml
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXScale="1.0"
android:toXScale="0.0"
android:fromYScale="1.0"
android:toYScale="0.0"
android:pivotX="50%"
android:pivotY="50%"
android:duration="2000">
</scale>
big.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:fromXScale="1.0"
android:toXScale="2.0"
android:fromYScale="1.0"
android:toYScale="2.0"
android:pivotX="50%"
android:pivotY="50%"
android:duration="2000"
/>
</set>
activity_main.xml
<LinearLayout 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:orientation="vertical"
>
<Button
android:id="@+id/btn0"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="放大"
/>
<Button
android:id="@+id/btn1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="缩小"
/>
<ImageView
android:id="@+id/img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher"
/>
</LinearLayout>
MainActivity.java:
public class MainActivity extends Activity { Button but0; Button but1; ImageView img; Animation liAnimation; Animation bigAnimation; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); img=(ImageView) findViewById(R.id.img); liAnimation=AnimationUtils.loadAnimation(this, R.anim.little); bigAnimation=AnimationUtils.loadAnimation(this, R.anim.big); but0=(Button) findViewById(R.id.btn0); but1=(Button) findViewById(R.id.btn1); but0.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { img.startAnimation(bigAnimation); } }); but1.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { img.startAnimation(liAnimation); } }); } }
第三种:Rotate旋转动画
<rotate>标签为旋转节点
Tween一共为我们提供了3种动画渲染模式
android:interpolator="@android:anim/accelerate_interpolator"
设置动画渲染器为加速动画(播放越来越快)
android:interpolator="@android:anim/decelerate_interpolator"
设置动画渲染器为减速动画(播放越来越慢)
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
设置动画渲染器为先加速再减速(开始速度最快,逐渐变慢)
android:fromDegrees="+360"设置动画开始的角度
android :toDegrees="0" 设置动画结束的角度
这个动画布局设置动画将向左做360度旋转加速运动
android:interpolator="@android:anim/acclerate_interpolator"
android:fromDegrees="+360"
android:toDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:duration="2000"
youx.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<rotate
android:interpolator="@android:anim/accelerate_interpolator"
android:fromDegrees="-360"
android:toDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:duration="2000"
/>
</set>
zuox.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<rotate
android:interpolator="@android:anim/accelerate_interpolator"
android:fromDegrees="+360"
android:toDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:duration="2000"
/>
</set>
zuox=AnimationUtils.loadAnimation(this, R.anim.zuox); youx=AnimationUtils.loadAnimation(this, R.anim.youx); btn2=(Button) findViewById(R.id.btn2); btn3=(Button) findViewById(R.id.btn3); btn2.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { img.startAnimation(zuox); } }); btn3.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { img.startAnimation(youx); } });
第四种:Translate
<translate>标签为移动节点
android:repeatCount="infinite"
设置动画为循环播放,这里可以写具体的int数值,设置动画播放几次,但是他记录的次数是从0开始数的。
整值型:
fromXDelta属性为动画起始时X坐标上的位置
fromYDelta属性为动画起始时Y坐标上的位置
toXDelta属性为动画结束时X坐标上的位置
toYDelta属性为动画结束时Y坐标上的位置
这些属性里还可以加上%和p,例如:
android:toXDelta="80%"表示父层view的80%,shiyitafucengview为参照的。
trany.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromXDelta="0"
android:toXDelta="320"
android:fromYDelta="0"
android:toYDelta="120"
android:duration="2000"
android:repeatCount="infinite"
></translate>
</set>
MainActivity.java
trany=AnimationUtils.loadAnimation(this, R.anim.trany); btn4=(Button) findViewById(R.id.btn4); btn4.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { img.startAnimation(trany); } });
3、用AnimationDrable实现Frame动画
首先在res资源文件夹下新建anim动画文件夹,在这个文件夹中建立一个animation.xml的文件
建立一个<animation-list>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false"> <item android:drawable="@drawable/a" android:duration="100" /> <item android:drawable="@drawable/b" android:duration="100" /> <item android:drawable="@drawable/c" android:duration="100" /> <item android:drawable="@drawable/d" android:duration="100" /> <item android:drawable="@drawable/e" android:duration="100" /> <item android:drawable="@drawable/f" android:duration="100" /> <item android:drawable="@drawable/g" android:duration="100" /> <item android:drawable="@drawable/h" android:duration="100" /> <item android:drawable="@drawable/i" android:duration="100" /> <item android:drawable="@drawable/j" android:duration="100" /> </animation-list>
android:oneshot="false"属性,默认false表示动画循环播放,如果是true则表示只播放一次
<item>标签中记录着每一帧的信息
android:drawable="@drawable/a"表示这一帧的图片为a
android:duration="100"表示这一帧持续100毫秒,可以根据这个来调节动画播放的速度。
AnimationDrawable是来控制帧动画,这个类中提供了很多方法:
animationDrawable.start(); 开始这个动画
animationDrawable.stop(); 结束这个动画
animationDrawable.setAlpha(100); 设置动画的透明度,取值范围(0-255)
animationDrawable.setOneShot(true); 设置单次播放
animationDrawable.setOneShot(false); 设置循环播放
animationDrawable.isRunning(); 判断动画是否正在播放
animationDrawable.getNumberOfFrames(); 得到动画的帧数
animation.xml
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="@drawable/a" android:duration="100"/>
<item android:drawable="@drawable/b" android:duration="100"/>
<item android:drawable="@drawable/c" android:duration="100"/>
<item android:drawable="@drawable/d" android:duration="100"/>
<item android:drawable="@drawable/e" android:duration="100"/>
</animation-list>
activity_main.xml
<LinearLayout 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:orientation="vertical"
>
<Button
android:id="@+id/btn0"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="播放动画"
/>
<Button
android:id="@+id/btn1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="停止动画"
/>
<RadioGroup
android:id="@+id/radio0"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<RadioButton
android:id="@+id/radiobut0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="单次播放"
/>
<RadioButton
android:id="@+id/radiobut1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="循环播放"
/>
</RadioGroup>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="拖动进度条修改透明度(0-255)之间"
/>
<SeekBar
android:id="@+id/seekbar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:max="256"
android:progress="256"
/>
<ImageView
android:id="@+id/img"
android:background="@anim/animation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
/>
</LinearLayout>
最后这个ImageView是用来显示动画的。android:background="@anim/animation"设置这个ImageView显示的背景为一个动画,动画资源的路径为res/anim/animation.xml
MainActivity.java
public class MainActivity extends Activity { Button btn0; Button btn1; RadioGroup radio0; RadioButton rbut0; RadioButton rbut1; SeekBar seekbar; ImageView img; AnimationDrawable animationDrawable; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); img=(ImageView) findViewById(R.id.img); //拿到ImageView对象 animationDrawable=(AnimationDrawable) img.getBackground(); //通过ImageView对象拿到背景显示的AnimationDrawable btn0=(Button) findViewById(R.id.btn0); btn0.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { if(!animationDrawable.isRunning()){ //播放动画 animationDrawable.start(); } } }); btn1=(Button) findViewById(R.id.btn1); btn1.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { //停止动画 if(animationDrawable.isRunning()){ animationDrawable.stop(); } } }); radio0=(RadioGroup) findViewById(R.id.radio0); rbut0=(RadioButton) findViewById(R.id.radiobut0); rbut1=(RadioButton) findViewById(R.id.radiobut1); radio0.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup group, int checkedId) { if(checkedId==rbut0.getId()){ //设置单次播放 animationDrawable.setOneShot(true); }else if(checkedId==rbut1.getId()){ //设置循环播放 animationDrawable.setOneShot(false); } //发生改变后让动画重新播放 animationDrawable.stop(); animationDrawable.start(); } }); seekbar=(SeekBar) findViewById(R.id.seekbar); //监听进度条修改透明度 seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { @Override public void onStopTrackingTouch(SeekBar seekBar) { } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { animationDrawable.setAlpha(progress); //设置动画Alpha值 img.postInvalidate(); //通知img刷新屏幕 } }); } }
拖动进度条设置Alpha值的时候一定要使用img.postInvalidate();方法来通知UI线程重绘屏幕中的img,否则会看不到透明的效果。
5、属性动画
public void ImgClick(View view) { //单个动画效果 // ObjectAnimator.ofFloat(view, "rotationX", 0.0f, 360f).setDuration(500).start(); //组合多个动画 PropertyValuesHolder p1 = PropertyValuesHolder.ofFloat("alpha", 1f, 0f, 1f); PropertyValuesHolder p2 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0f, 1f); PropertyValuesHolder p3 = PropertyValuesHolder.ofFloat("scaleY", 1f, 0f, 1f); ObjectAnimator.ofPropertyValuesHolder(view, p1, p2, p3).setDuration(500).start(); }
//自由落体示例 public void Imgclick(final View view) { DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); //定义一个动画 ValueAnimator va = ValueAnimator.ofFloat(view.getY(), dm.heightPixels).setDuration(500); //监听动画的每一个动作 va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { view.setTranslationY((Float) valueAnimator.getAnimatedValue()); } }); va.start(); }
监听动画的事件:
对于动画,一般都是一些辅助效果,比如要删除某个元素,可能希望十个淡出的效果,但是最终还是要删掉,并不是透明度没了,还站着位置,所以我们需要知道动画如何结束。