Android 属性动画特效
来源:互联网 发布:阿迪达斯童鞋淘宝官网 编辑:程序博客网 时间:2024/05/16 18:13
在 Android 3.0 之前已有的动画框架 Animation 存在一些局限性—— 动画改变的只是显示,并不能响应事件(相比属性动画,视图动画的一个非常大的缺陷就是不具备交互性,当某个元素发生视图动画后,其响应事件的位置依然在动画前的地方,所以视图动画只能做普通的动画效果,避免交互的发生。它的优点是效率比较高使用方便)。
本文要实现的效果如下:
在这之前先简单的介绍一下属性动画。
1. 属性动画涉及的 API :
(1)Animator :它提供了创建属性动画的基类,基本上不会直接使用该类。通常该类只用于被继承并重写它的相关方法。
(2) ValueAnimator :属性动画主要的时间引擎,它负责计算各个帧的属性值。属性动画主要有两方面组成:
——> 1)计算各帧的相关属性值;
——> 2)为指定对象设置这些计算后的值;
ValueAnimator 只负责第一方面内容,因此程序员必须根据 ValueAnimator 计算并监听值更新来更新对象的相关属性值。使用 ValueAnimator 需要注册 AnimatorUpdateListener 监听器。
(3)ObjectAnimator :它是 ValueAnimator 的子类,允许程序员对指定对象的属性执行动画。在实际应用中,它比 ValueAnimator 使用起来更加简单。使用 ObjectAnimator 就不需要注册 AnimatorUpdateListener 监听器了。
(4) AnimatorSet :它是 Animator 的子类,组合多个 Animator ,并指定多个 Animator 是按次序播放,还是同时播放。
在 Animator 框架中使用最多的就是 AnimatorSet 和 ObjectAnimator ,使用 ObjectAnimator 进行更精细化的控制,只控制一个对象的一个属性值,而使用多个 ObjectAnimator 组合到 AnimatorSet 形成一个动画。属性动画通过调用属性的 get 、set 方法来真实地控制一个 View 的属性值,因此强大的动画框架,基本可以实现所有的动画效果。
2. 使用属性动画的步骤如下:
(1)创建 ObjectAnimator 或 ValueAnimator 对象——即可从 XML 资源文件加载该动画资源,也可以直接调用 ObjectAnimator 或 ValueAnimator 的静态工厂方法来创建动画。
——> 静态方法 ofInt() 、ofFloat() 或者 ofObject();
——> 注意使用 ObjectAnimator 的静态方法创建 ObjectAnimator 对象时,需要指定具体的对象,以及对象的属性名。如: ObjectAnimator animator0 = ObjectAnimator.ofFloat(foo, "alpha", 0.5F, 1F);
(2)根据需要为 Animator 对象设置属性。
(3)如果需要监听 Animator 的动画开始事件、动画结束事件、动画重复事件、动画值改变事件,并根据事件提供相应的处理代码,则应该为 Animator 对象设置事件监听器。
(4)如果有多个动画需要按次序或者同时播放,则应使用 AnimatorSet 组合这些动画。
(5)调用 Animator 对象的 start() 方法启动动画。
ObjectAnimator
ObjectAnimator 参数包括一个对象和对象的属性名,但这个属性必须有 get() 和 set() 函数,内部会通过 Java 反射机制来调用 set 函数修改对象属性。
前文的使用 ObjectAnimator animator0 = ObjectAnimator.ofFloat(foo, "alpha", 0.5F, 1F); 创建一个 ObjectAnimator 对象。其中第一个参数时需要操纵的 View;第二个参数则是操纵的属性;而最后一个参数是一个可变数组参数,需要传进去该属性变化的一个取值过程。
第二个参数的属性值如下:
(1)translationX 和 translationY:这两个属性作为一种增量来控制着 View 对象从它布局容器的左上角坐标偏移的位置。
(2)rotation 、rotationX 和 rotationY:这三个属性控制着 View 对象围绕支点进行 2D 和 3D 旋转。
(3)scaleX 和 scaleY:这两个属性控制着 View 对象围绕它的支点进行 2D 缩放。
(4)pivotX 和 pivotY:这两个属性控制着 View 对象的支点位置,围绕这个支点进行旋转和缩放变换处理。默认情况下,该支点的位置就是 View 对象的中心点。
(5)x 和 y:它描述了 View 对象在它的容器中的最终位置,它是最初的左上角坐标和 translationX 、 translationY 值得累计和。
(6)alpha:它表示 View 对象的 alpha 透明度。默认值为 1 (不透明),0 代表完全透明(不可见)。
属性的 get() 和 set() 方法也可以从如下两个方案来解决:
——> 通过自定义一个属性或者包装类,来间接地给这个属性增加 get() 、set() 方法。
——> 通过 ValueAnimator 来实现。
AnimatorSet
对于一个属性同时作用多个属性动画效果,可以使用 PropertyValuesHolder 实现这样的效果,但是通过 AnimatorSet 不仅能实现这样的效果,同行也能实现更为精确的顺序控制。代码如下:
ObjectAnimator animator1 = ObjectAnimator.ofFloat(foo, "translationY", -200F, 0); ObjectAnimator animator1 = ObjectAnimator.ofFloat(foo, "translationX", -200F, 0); AnimatorSet set = new AnimatorSet(); set.setDuration(500); set.setInterpolator(new BounceInterpolator()); set.playTogether(animator1, animator2); set.start();
在属性动画中,AnimatorSet 正是通过 playTogether()、playSequentially()、animSet.play().with()、before()、after()这些方法来控制多个动画的协同工作方式。
第一个效果代码:
forclick_layout.xml :
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageView_b" android:src="@drawable/b" android:layout_centerVertical="true" android:layout_centerHorizontal="true" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageView_c" android:src="@drawable/c" android:layout_centerVertical="true" android:layout_centerHorizontal="true" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageView_d" android:src="@drawable/d" android:layout_centerVertical="true" android:layout_centerHorizontal="true" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageView_e" android:src="@drawable/e" android:layout_centerVertical="true" android:layout_centerHorizontal="true" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageView_a" android:src="@drawable/a" android:layout_centerVertical="true" android:layout_centerHorizontal="true" /></RelativeLayout>
PropertyTest.java :
package com.imooc.anim;import android.animation.AnimatorSet;import android.animation.ObjectAnimator;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.view.animation.BounceInterpolator;import android.widget.ImageView;import android.widget.Toast;import java.util.ArrayList;import java.util.List;public class PropertyTest extends Activity implements View.OnClickListener { private int[] mRes = {R.id.imageView_a, R.id.imageView_b, R.id.imageView_c, R.id.imageView_d, R.id.imageView_e}; private List<ImageView> mImageViews = new ArrayList<>(); private boolean mFlag = true; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.forclick_layout); int sum = mRes.length; for (int i = 0; i < sum; i++) { ImageView imageView = (ImageView) findViewById(mRes[i]); imageView.setOnClickListener(this); mImageViews.add(imageView); } } @Override public void onClick(View v) { switch (v.getId()) { case R.id.imageView_a: if (mFlag) { startAnim(); } else { closeAnim(); } break; case R.id.imageView_b: Toast.makeText(PropertyTest.this, "相机", Toast.LENGTH_SHORT).show(); break; case R.id.imageView_c: Toast.makeText(PropertyTest.this, "音乐", Toast.LENGTH_SHORT).show(); break; case R.id.imageView_d: Toast.makeText(PropertyTest.this, "定位", Toast.LENGTH_SHORT).show(); break; case R.id.imageView_e: Toast.makeText(PropertyTest.this, "夜晚", Toast.LENGTH_SHORT).show(); break; } } private void closeAnim() { ObjectAnimator animator0 = ObjectAnimator.ofFloat(mImageViews.get(0), "alpha", 0.5F, 1F); ObjectAnimator animator1 = ObjectAnimator.ofFloat(mImageViews.get(1), "translationY", 200F, 0); ObjectAnimator animator2 = ObjectAnimator.ofFloat(mImageViews.get(2), "translationX", 200F, 0); ObjectAnimator animator3 = ObjectAnimator.ofFloat(mImageViews.get(3), "translationY", -200F, 0); ObjectAnimator animator4 = ObjectAnimator.ofFloat(mImageViews.get(4), "translationX", -200F, 0); AnimatorSet set = new AnimatorSet(); set.setDuration(500); set.setInterpolator(new BounceInterpolator()); set.playTogether(animator0, animator1, animator2, animator3, animator4); set.start(); mFlag = true; } private void startAnim() { ObjectAnimator animator0 = ObjectAnimator.ofFloat( mImageViews.get(0), "alpha", 1F, 0.5F); ObjectAnimator animator1 = ObjectAnimator.ofFloat( mImageViews.get(1), "translationY", 200F); ObjectAnimator animator2 = ObjectAnimator.ofFloat( mImageViews.get(2), "translationX", 200F); ObjectAnimator animator3 = ObjectAnimator.ofFloat( mImageViews.get(3), "translationY", -200F); ObjectAnimator animator4 = ObjectAnimator.ofFloat( mImageViews.get(4), "translationX", -200F); AnimatorSet set = new AnimatorSet(); set.setDuration(500); set.setInterpolator(new BounceInterpolator()); set.playTogether( animator0, animator1, animator2, animator3, animator4); set.start(); mFlag = false; }}
第二个效果的实现:
drop.xml :
<?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="wrap_content" android:orientation="vertical"> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:onClick="llClick" android:background="@android:color/holo_blue_bright" android:orientation="horizontal"> <ImageView android:id="@+id/app_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:src="@drawable/ic_launcher" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:gravity="left" android:text="Click Me" android:textSize="30sp" /> </LinearLayout> <LinearLayout android:id="@+id/hidden_view" android:layout_width="match_parent" android:layout_height="40dp" android:background="@android:color/holo_orange_light" android:gravity="center_vertical" android:orientation="horizontal" android:visibility="gone"> <ImageView android:src="@drawable/ic_launcher" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" /> <TextView android:id="@+id/tv_hidden" android:layout_width="wrap_content" android:layout_height="match_parent" android:gravity="center" android:textSize="20sp" android:text="我是隐藏着的!" /> </LinearLayout></LinearLayout>
点击上面的 LinearLayout 时,需要获取到隐藏的 LinearLayout 最终需要达到的一个高度,即是目标值,通过将布局文件文件中的 dp 值转化为像素值即可。
// 获取像素密度 mDensity = getResources().getDisplayMetrics().density; // 获取布局的高度 mHiddenViewMeasuredHeight = (int) (mDensity * 40 + 0.5);40 就是在 XML 文件中定义的布局高度。
需要使用 ValueAnimator 来创建一个从 0 到目标值的数值发生器,并由此来改变 View 的布局属性。
ValueAnimator animator = ValueAnimator.ofInt(start, end); animator.addUpdateListener( new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { int value = (Integer) valueAnimator.getAnimatedValue(); ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); layoutParams.height = value; view.setLayoutParams(layoutParams); } });
DropTest.java :
package com.imooc.anim;import android.animation.Animator;import android.animation.AnimatorListenerAdapter;import android.animation.ValueAnimator;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.view.ViewGroup;import android.widget.LinearLayout;public class DropTest extends Activity { private LinearLayout mHiddenView; private float mDensity; private int mHiddenViewMeasuredHeight; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.drop); mHiddenView = (LinearLayout) findViewById(R.id.hidden_view); // 获取像素密度 mDensity = getResources().getDisplayMetrics().density; // 获取布局的高度 mHiddenViewMeasuredHeight = (int) (mDensity * 40 + 0.5); } public void llClick(View view) { if (mHiddenView.getVisibility() == View.GONE) { // 打开动画 animateOpen(mHiddenView); } else { // 关闭动画 animateClose(mHiddenView); } } private void animateOpen(final View view) { view.setVisibility(View.VISIBLE); ValueAnimator animator = createDropAnimator( view, 0, mHiddenViewMeasuredHeight); animator.start(); } private void animateClose(final View view) { int origHeight = view.getHeight(); ValueAnimator animator = createDropAnimator(view, origHeight, 0); animator.addListener(new AnimatorListenerAdapter() { public void onAnimationEnd(Animator animation) { view.setVisibility(View.GONE); } }); animator.start(); } private ValueAnimator createDropAnimator( final View view, int start, int end) { ValueAnimator animator = ValueAnimator.ofInt(start, end); animator.addUpdateListener( new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { int value = (Integer) valueAnimator.getAnimatedValue(); ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); layoutParams.height = value; view.setLayoutParams(layoutParams); } }); return animator; }}
其中:AnimatorUpdateListener 中监听的是数值变换,从而完成动画的变换;一个完整的动画具有 Start、Repeat、End 、Cancel 四个过程,通过 AnimatorListener 接口可以很方便地监听到这四个事件。AnimatorListener 接口的源码如下:
public interface AnimatorListener { void onAnimationStart(Animator var1); void onAnimationEnd(Animator var1); void onAnimationCancel(Animator var1); void onAnimationRepeat(Animator var1); }
但是,大部分的时候,我们都只关心 onAnimationEnd 事件,所以 Android 也提供了一个 AnimatorListenerAdapter 来让我们选择必要的事件进行监听,如文中的代码:
animator.addListener(new AnimatorListenerAdapter() { public void onAnimationEnd(Animator animation) { view.setVisibility(View.GONE); } });
- Android 属性动画特效
- 用属性动画简简单单实现android导航栏特效
- Android 动画特效集合
- android动画特效
- Android 动画特效集合
- Android Animation动画特效
- Android 动画特效集合
- Android动画特效实例
- Android动画--属性动画
- android动画 -- 属性动画
- Android动画-属性动画
- Android动画【属性动画】
- Android动画--属性动画
- Android特效专辑(七)——飞机升空特效,一键清理缓存,灵活运用属性动画
- android popupwindow 动画 特效 案例
- Android动画特效的实现
- 【代码】Android Animation 动画特效
- Android 动画特效的运用
- swift简单学习之getter setter方法
- 【游戏客户端开发】Unity3D 学习笔记2——了解U3D引擎的操作面板和各种工具
- poj1088 滑雪
- The best resources for learning exploit development
- Android图片海报制作-MVP的使用
- Android 属性动画特效
- 【游戏客户端开发】Unity3D 学习笔记3——Unity3D资源目录及资源读取
- kali linux 2.0 无法安装vmware tools
- 学习笔记
- expdp/impdp区别
- lqb
- App Framework $.ui.loadContent 参数解释
- 0000eclipse关键快捷键
- 转载的一篇ER模型的小文章