转载请注明出处:http://blog.csdn.net/wei_chong_chong/article/details/50820558
这次我们来学习一下属性动画
这里你可以学到:
实现Animation框架的功能
属性动画常用属性
动画的监听事件
这里我采用逐步优化的方式学习使用属性动画的各种操作(你可以对比各种方法的优缺点)
属性动画改变的是对象的属性,只要对象某个的属性有get和setf方法就可以对这个属性进行属性动画
先看一个简单的例子吧:
这里我在布局文件中添加了一个ImageView的控件和一个Button控件
我对ImageView添加动画效果
点击Button按钮显示动画效果
public class MainActivity extends Activity {
private Button mbutton ;
private ImageView mImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mbutton = (Button) findViewById(R.id.start);
mImageView = (ImageView) findViewById(R.id.mImageView);
mbutton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
//参数含义1.操作的对象 2.Y轴平移的偏离量属性3.初始位置 4.移动后的位置
//setDuration(1000)是移动的时间
ObjectAnimator.ofFloat(mImageView, "translationY", 0F,500F).setDuration(3000).start();
//X轴平移
ObjectAnimator.ofFloat(mImageView,"translationX",0,500F).setDuration(3000).start();
//旋转360度
ObjectAnimator.ofFloat(mImageView,"rotation",0,360F).setDuration(3000).start();
}
});
}
}
ObjectAnimator.ofFloat(mImageView, "translationY", 100F,500F).setDuration(1000).start();
//参数含义1.操作的对象 2.Y轴平移的属性 3.初始位置 4.移动后的位置
属性动画的移动是异步进行的,
//setDuration(1000)是移动的时间
多种属性动画效果同时进行:
方法一:
ObjectAnimator.ofFloat(mImageView, "translationY", 0F,500F).setDuration(3000).start();
//X轴平移
ObjectAnimator.ofFloat(mImageView,"translationX",0,500F).setDuration(3000).start();
//旋转360度
ObjectAnimator.ofFloat(mImageView,"rotation",0,360F).setDuration(3000).start();
优化:谷歌对多个属性动画同时运行进行了性能上的优化,即使用PropertyValuesHolder类控制,使占用更少的系统资源,如下所示
方法二
PropertyValuesHolder p1 = PropertyValuesHolder.ofFloat("rotation",0,360F);
PropertyValuesHolder p2 = PropertyValuesHolder.ofFloat("translationX",0,500F);
PropertyValuesHolder p3 = PropertyValuesHolder.ofFloat( "translationY", 0F,500F);
ObjectAnimator.ofPropertyValuesHolder(mImageView,p1,p2,p3).setDuration(3000).start();
为了使动画有更丰富的效果可以使用动画集合
方法三
ObjectAnimator animator1 = ObjectAnimator.ofFloat(mImageView, "translationY", 0F,500F);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(mImageView,"translationX",0,500F);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(mImageView,"rotation",0,360F);
AnimatorSet set = new AnimatorSet();
set.playTogether(animator1,animator2,animator3);
set.setDuration(3000);
set.start();
更丰富的效果:
效果一:按顺序执行动画先Y轴平移,然后X轴平移,最后旋转
使用集合的set.playSequentially(animator1,animator2,animator3);方法就行了
set.playTogether(animator1,animator2,animator3);//同时进行
set.playSequentially(animator1,animator2,animator3);//依次进行
效果二:X,Y轴平移同时进行,执行完之后再旋转
set.play(animator1).with(animator2);
set.play(animator3).after(animator2);//或者<span style="white-space:pre"> </span>set.play(animator3).with(animator1);
<span style="white-space:pre"> </span>
今天先写这么多吧。不知道为啥在我的真机(魅蓝note)上模拟不出来效果,单是在其他真机上可以,可能魅族手机对动画做了处理吧
继续学习,动画的监听事件
在布局文件中添加一个按钮Button
在主函数中添加点击事件
public void click(View view){
// TODO Auto-generated method stub
Toast.makeText(this, view.getId(), 1);
//透敏度变化
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "alpha", 0F,1F);
animator.setDuration(1000);//动画时长
//给动画添加监听事件
animator.start();
}
这里闹了个笑话,我开始把click方法设置成private的了,点击一直报错,后来发现,必须声明成public 的,大家注意一下!!
//给动画添加监听事件
animator.addListener(new AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationRepeat(Animator animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animator animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationCancel(Animator animation) {
// TODO Auto-generated method stub
}
});
因为不需要实现所有的方法,一般只使用实现动画完成后的方法所以,这里Android有一个适配器帮我们解决了这个问题
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// TODO Auto-generated method stub
super.onAnimationEnd(animation);
}
});
下面实现一个按钮弹出的效果:
里面是重叠的大小相同的几个圆形按钮
主界面布局文件xml代码:
<FrameLayout 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"
tools:context="com.example.objectanimatortext1.MainActivity" >
<ImageView
android:id="@+id/image_h"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:paddingTop="5dp"
android:src="@drawable/h" />
<ImageView
android:id="@+id/image_g"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:paddingTop="5dp"
android:src="@drawable/g" />
<ImageView
android:id="@+id/image_f"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:paddingTop="5dp"
android:src="@drawable/f" />
<ImageView
android:id="@+id/image_e"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:paddingTop="5dp"
android:src="@drawable/e" />
<ImageView
android:id="@+id/image_d"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:paddingTop="5dp"
android:src="@drawable/d" />
<ImageView
android:id="@+id/image_c"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:paddingTop="5dp"
android:src="@drawable/c" />
<ImageView
android:id="@+id/image_b"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:paddingTop="5dp"
android:src="@drawable/b" />
<ImageView
android:id="@+id/image_a"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:paddingTop="5dp"
android:src="@drawable/a" />
</FrameLayout>
在MainActivity:
public class MainActivity extends Activity implements OnClickListener{
private int[] resid = {R.id.image_a,R.id.image_b,R.id.image_c,R.id.image_d,R.id.image_e,R.id.image_f,R.id.image_g,R.id.image_h};
private List<ImageView> imageViewList = new ArrayList<ImageView>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
for (int i = 0; i < resid.length; i++) {
ImageView imageView = (ImageView) findViewById(resid[i]);
imageView.setOnClickListener(this);
imageViewList.add(imageView);
}
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
int myid = v.getId();
if(myid == R.id.image_a){
startAnim();
}else {
}
}
private void startAnim(){
for(int i = 0;i < resid.length;i++){
ObjectAnimator animator = ObjectAnimator.ofFloat(imageViewList.get(i),
"translationY", 0F,i*100);
<span style="white-space:pre"> </span>animator.setDuration(500);
animator.start();
}
}
}
代码中是设置Y轴动画平移:
ObjectAnimator animator = ObjectAnimator.ofFloat(imageViewList.get(i),
"translationY", 0F,i*100);
<span style="white-space:pre"> </span>animator.setDuration(500);
animator.start();
继续优化:
达到依次弹出的效果:
实现方法:加入动画启动延迟效果
animator.setStartDelay(i * 300);
修改startAnim()方法
private void startAnim(){
for(int i = 0;i < resid.length;i++){
ObjectAnimator animator = ObjectAnimator.ofFloat(imageViewList.get(i),
"translationY", 0F,i*100);
animator.setDuration(500);
animator.setStartDelay(i * 300);
animator.start();
}
}
下面添加回收事件,实现点击一下打开,再点击一下关闭菜单的效果
private void closeMenu(){
for(int i = 0;i < resid.length;i++){
ObjectAnimator animator = ObjectAnimator.ofFloat(imageViewList.get(i),
"translationY", i*100,0F);
animator.setDuration(500);
animator.setStartDelay(i * 300);
animator.start();
isOpen = false;
}
}
完整代码:
public class MainActivity extends Activity implements OnClickListener{
private boolean isOpen;
private int[] resid = {R.id.image_a,R.id.image_b,R.id.image_c,R.id.image_d,R.id.image_e,R.id.image_f,R.id.image_g,R.id.image_h};
private List<ImageView> imageViewList = new ArrayList<ImageView>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
for (int i = 0; i < resid.length; i++) {
ImageView imageView = (ImageView) findViewById(resid[i]);
imageView.setOnClickListener(this);
imageViewList.add(imageView);
}
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
int myid = v.getId();
if(myid == R.id.image_a){
toogle();
}else {
}
}
private void openMenu(){
for(int i = 0;i < resid.length;i++){
ObjectAnimator animator = ObjectAnimator.ofFloat(imageViewList.get(i),
"translationY", 0F,i*100);
animator.setDuration(500);
animator.setStartDelay(i * 300);
animator.start();
isOpen = true;
}
}
private void closeMenu(){
for(int i = 0;i < resid.length;i++){
ObjectAnimator animator = ObjectAnimator.ofFloat(imageViewList.get(i),
"translationY", i*100,0F);
animator.setDuration(500);
animator.setStartDelay(i * 300);
animator.start();
isOpen = false;
}
}
private void toogle(){
if(isOpen){
closeMenu();
}else {
openMenu();
}
}
}
下面继续优化:
让菜单动画弹出时轨迹不是线性的,更灵活
这里用到一个术语:插值器
android内置9中插值器
下面加入自由落体插值器
使用方法就是在animator.start()之前调用
animator.setInterpolator(new BounceInterpolator());//自由落体插值器
下面学习ValueAnimator来实现更炫酷的动画效果
ValueAnimator是一个数值发生器,提供各种数值的计算方法,它本身作用于任何属性不能设置任何动画
ValueAnimator是ObjectAnimator的父类
下面使用ValueAnimator实现一个计时器效果
:有一个Button,点击之后,button中的内容由100依次减小到0
常规做法是使用线程,加for循环
这里我们使用动画来实现同样的效果
给按钮添加点击事件
public void onClick(View view){
final Button button = (Button) view;
ValueAnimator animator = ValueAnimator.ofInt(0,100);//线性产生0到100的整数
animator.setDuration(5000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
//通过添加这个监听事件可以获取到ValueAnimator每一步产生的值
@Override
public void onAnimationUpdate(ValueAnimator animation) {
// TODO Auto-generated method stub
Integer value = (Integer) animation.getAnimatedValue();
button.setText(""+value);
}
});
}
下面来实现自定义的数值数值生成器
这一点我学的也不好,这里就不再说了。
总结:
常用属性:
translationX/translationY X,Y轴平移
rotainon,rotationX,rotationY 3D旋转动画
scaleX,scaleY缩放动画
X,Y移动到某个具体的点
alpha透明度