逐帧动画Frame Animation :其实也可以规划到视图动画的类别,用来一个一个的显示drawable的resources。
视图动画Tween Animation:也叫补间动画,可以在一个视图容器内执行一系列简单变换(位置,大小,旋转,透明度)实现的原理是每次绘制视图时view所在的viewgroup中的drawchild函数获取该viewanimation的transformation值。然后调用canvas.concat()通过矩阵运算完成动画zhen动画帧。如果动画没有完成,就继续调用invalidate函数启动下次绘制来驱动动画,从而完成整个动画的绘制。它有一个缺点,不具备交互性,当某个元素发生视图动画后,其响应事件的位置还依然在动画前的地方,(例如,将一个按钮向右平移10个单位,但是它的点击事件还是在平移之前的那个位置,而不是平移后显示的位置)所以视图动画只能做普通的动画效果,避免交互的发生。但是它的效率高,使用方便。
属性动画Propety Animation:只对android3.0以上的版本才有效,这种动画可以设置给任何object,包括那些还没有渲染到屏幕上的对象,这种动画是可以扩展的,可以让自定义任何类型和属性的动画。
视图动画示例:
public class AnimationActivity extends AppCompatActivity implements View.OnClickListener { private ImageView ainmationImg; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_animation); initView(); } private void initView() { ainmationImg = ((ImageView) findViewById(R.id.animationImg)); findViewById(R.id.touming).setOnClickListener(this); findViewById(R.id.xuanzhuan).setOnClickListener(this); findViewById(R.id.weiyi).setOnClickListener(this); findViewById(R.id.suofang).setOnClickListener(this); findViewById(R.id.jihe).setOnClickListener(this); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.touming: toumingAnimation(); break; case R.id.xuanzhuan: xuanzhuanAnimation(); break; case R.id.weiyi: weiyiAnimation(); break; case R.id.suofang: soufangAnimation(); break; case R.id.jihe: jiheAnimation(); break; } } /** * 透明动画 */ private void toumingAnimation() { AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1); alphaAnimation.setDuration(1000); ainmationImg.startAnimation(alphaAnimation); } /** * 集合动画,添加多种动画效果 */ private void jiheAnimation() { AnimationSet as = new AnimationSet(true); as.setDuration(1000); AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1); alphaAnimation.setDuration(1000); as.addAnimation(alphaAnimation); ScaleAnimation anmation = new ScaleAnimation(0, 2, 0, 2); anmation.setDuration(1000); as.addAnimation(anmation); RotateAnimation animation = new RotateAnimation(0, 360, 100, 100); animation.setDuration(1000); as.addAnimation(animation); ainmationImg.startAnimation(as); } /** * 缩放动画 */ private void soufangAnimation() { ScaleAnimation anmation = new ScaleAnimation(0, 2, 0, 2); anmation.setDuration(1000); ainmationImg.startAnimation(anmation); } /** * 位移动画 */ private void weiyiAnimation() { TranslateAnimation animation = new TranslateAnimation(0, 200, 0, 300); animation.setDuration(1000); ainmationImg.startAnimation(animation); } /** * 旋转动画 */ private void xuanzhuanAnimation() { // 参数:1旋转的起始角度和旋转中心点的坐标 RotateAnimation animation = new RotateAnimation(0, 360, 100, 100); animation.setDuration(1000); ainmationImg.startAnimation(animation); } private void animationListener(Animation animation) { //动画的监听 animation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { } @Override public void onAnimationRepeat(Animation animation) { } }); } }xml布局
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_animation" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.lvqueen.qunyinzhuan.day07.AnimationActivity"> <ImageView android:id="@+id/animationImg" android:layout_width="100dp" android:layout_height="100dp" android:layout_centerInParent="true" android:scaleType="fitXY" android:src="@mipmap/shoukuan" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:orientation="horizontal"> <Button android:id="@+id/touming" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="透明" /> <Button android:id="@+id/xuanzhuan" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="旋转" /> <Button android:id="@+id/weiyi" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="位移" /> <Button android:id="@+id/suofang" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="缩放" /> </LinearLayout> <Button android:id="@+id/jihe" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="集合" /> </LinearLayout> </RelativeLayout>
属性动画示例
public class AnimatorActivity extends AppCompatActivity { private ImageView imgView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_animator); initView(); } private void initView() { imgView = ((ImageView) findViewById(R.id.animatorImg)); // pingyiAnimator(); // jiheAnimator(); // orderManyAnimator(); useXmlAnimator(); } /** * 在使用ObjectAnimator的时候,操纵的属性必须具有get和set方法,不然ObjectAnimator就无效。 * 如果没有,可以通过自定义一个属性类或者包装类,来间接的给这个属性增加get,set方法,活着通过ValueAnimator * 可以直接使用属性动画的属性值 * translationX,translationY:为一种增量来控制view对象从它的布局容器的左上角坐标偏移的位置。 * rotation,rotationX,rotationY:控制view对象围绕它的支点进行2D,3D旋转 * scaleX,scaleY:控制view围绕它的支点进行2D缩放。 * pivotX,pivotY:控制view围绕支点进行旋转和缩放变换处理。默认情况下,支点位置就是view对象的中心点 * x,y:描述了view对象在他的容器中的最终位置,它是最初的左上角坐标和translationX,translationY值的累计和 * alpha:表示view的透明度,默认值为1不透明,0为完全透明。 */ private void pingyiAnimator() { // 参数1:要操纵的view。参数2:操纵的属性。参数三:可变的数组参数 ObjectAnimator animator = ObjectAnimator.ofFloat(imgView, "translationX", 300); // ObjectAnimator animator = ObjectAnimator.ofFloat(imgView, "translationX", 300); animator.setDuration(1000); animator.start(); } /** * 添加多种动效PropertyValuesHolder */ private void jiheAnimator() { PropertyValuesHolder translationX = PropertyValuesHolder.ofFloat("translationX", 300f); PropertyValuesHolder translationY = PropertyValuesHolder.ofFloat("translationY", 300f); PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f); ObjectAnimator.ofPropertyValuesHolder(imgView, translationX, scaleX, translationY).setDuration(1000).start(); } /** * 顺序添加多种动效 */ private void orderManyAnimator() { ObjectAnimator animator = ObjectAnimator.ofFloat(imgView, "translationX", 100); ObjectAnimator animator1 = ObjectAnimator.ofFloat(imgView, "translationY", 100); AnimatorSet animatorSet = new AnimatorSet(); animatorSet.setDuration(1000); animatorSet.playTogether(animator, animator1); animatorSet.start(); } private void useXmlAnimator(){ // Animator animator = AnimatorInflater.loadAnimator(this, R.anim.animator_test); // animator.setTarget(imgView); // animator.start(); } // view 的animate方法添加动画 private void animateUse(){ imgView.animate().alpha(0).y(300).setDuration(1000).withStartAction(new Runnable() { @Override public void run() { } }).withEndAction(new Runnable() { @Override public void run() { runOnUiThread(new Runnable() { @Override public void run() { } }); } }).start(); } private void valueAnimatorFactory() { ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 100); valueAnimator.setTarget(imgView); valueAnimator.setDuration(1000).start(); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { Float value = (Float) valueAnimator.getAnimatedValue(); // TODO use the value // 在这里监听数值的变换,从而完成动画的变换。 } }); } /** * 动效的监听 * * @param animator */ private void animationListener(ObjectAnimator animator) { animator.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animator) { } @Override public void onAnimationEnd(Animator animator) { } @Override public void onAnimationCancel(Animator animator) { } @Override public void onAnimationRepeat(Animator animator) { } }); // 通常情况下我们只关心动画结束时,所以还提供了一个,来选择必要的事件进行监听 animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); } }); } }示例三:布局动画,给子视图出现添加动画
public class BujuActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_buju); addAnimation(); } /** * 给子视图出现添加动画 * 参数1:需要作用的动画,参数2:子view现实的delay时间 * LayoutAnimationController.ORDER_NORMAL:顺序依次出现 * LayoutAnimationController.ORDER_RANDOM :随机出现 * LayoutAnimationController.ORDER_REVERSE:倒序出现 */ private void addAnimation() { LinearLayout linearLayout = (LinearLayout) findViewById(R.id.activity_buju); ScaleAnimation scaleAnimation = new ScaleAnimation(0, 1, 0, 1); scaleAnimation.setDuration(1000); LayoutAnimationController controller = new LayoutAnimationController(scaleAnimation, 0.5f); controller.setOrder(LayoutAnimationController.ORDER_REVERSE); linearLayout.setLayoutAnimation(controller); } }
插值器Interpolators
插值器可以定义动画变换速率,类似于物理中的加速度,主要控制目标变量的变化值进行对应的变化。同样的,一个动画变换起始值,在不同的插值器作用下,每个单位时间内所达到的变化值也是不一样的。
自定义动画
示例1:模拟电视机关闭的图像
public class CustomTv extends Animation{ // 缩放的中心点 private int mCenterWidth; private int mCenterHeight; private Camera mcamera = new Camera(); private float mRotateY = 0.0f; @Override public void initialize(int width, int height, int parentWidth, int parentHeight) { super.initialize(width, height, parentWidth, parentHeight); // 设置默认时常 setDuration(1000); // 动画结束后保留状态 setFillAfter(true); // 设置默认插值器 setInterpolator(new AccelerateInterpolator()); mCenterWidth = width/2; mCenterHeight = height/2; } public void setRotateY(float rorateY){ mRotateY = rorateY; } @Override protected void applyTransformation(float interpolatedTime, Transformation t) { // 获得矩阵对象 final Matrix matrix = t.getMatrix(); // 通过对矩阵的各种操作来实现动效 matrix.preScale(1,1-interpolatedTime,mCenterWidth,mCenterHeight); } }使用:
CustomTv customTv = new CustomTv(); customTv.setRotateY(30); imgView.startAnimation(customTv);
android5.x SVG(可伸缩矢量图形)矢量动画机制
可伸缩矢量图形(scalable vector graphics)
定义用于网络的基于矢量的图形
使用XML格式定义图形
图像在放大或者改变尺寸的情况下其图形质量不会有所损失
万维网联盟的标准
与诸如dom 和xsl之类的问c标准是一个整体
与传统bitmap相比,svg是一个绘图标准,它放大不会失真,而bitmap需要为不同分辨率设计多套图标,矢量图不需要。
它是通过<path>标签创建svg,这些指令一时没看懂,没信心看下去了。
动画特效
一个点击一个按钮,发散出四个按钮的动画,类似于菜单demo
public class SupriseAnimationActivity extends AppCompatActivity 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> imageViews = new ArrayList<>(); private boolean mFlag = true; private ImageView imgview; private TextView text; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_suprise_animation); initView(); } private void initView() { text = ((TextView) findViewById(R.id.tv_texts)); for (int i = 0; i < mRes.length; i++) { imgview = ((ImageView) findViewById(mRes[i])); imgview.setOnClickListener(this); imageViews.add(imgview); } } private void startAnim() { ObjectAnimator animator = ObjectAnimator.ofFloat(imageViews.get(0), "alpha", 0.5F, 1F); ObjectAnimator animator1 = ObjectAnimator.ofFloat(imageViews.get(1), "translationY", -100F); ObjectAnimator animator2 = ObjectAnimator.ofFloat(imageViews.get(2), "translationX", -100F); ObjectAnimator animator3 = ObjectAnimator.ofFloat(imageViews.get(3), "translationY", 100F); ObjectAnimator animator4 = ObjectAnimator.ofFloat(imageViews.get(4), "translationX", 100F); AnimatorSet animatorSet = new AnimatorSet(); animatorSet.setDuration(1000); animatorSet.setInterpolator(new BounceInterpolator()); animatorSet.playTogether(animator,animator1,animator2,animator3,animator4); animatorSet.start(); mFlag=false; } private void stopAnim() { ObjectAnimator animator = ObjectAnimator.ofFloat(imageViews.get(0), "alpha", 0.5F, 1F); ObjectAnimator animator1 = ObjectAnimator.ofFloat(imageViews.get(1), "translationY", 100F, 0); ObjectAnimator animator2 = ObjectAnimator.ofFloat(imageViews.get(2), "translationX", 100F, 0); ObjectAnimator animator3 = ObjectAnimator.ofFloat(imageViews.get(3), "translationY", -100F, 0); ObjectAnimator animator4 = ObjectAnimator.ofFloat(imageViews.get(4), "translationX", -100F, 0); AnimatorSet animatorSet = new AnimatorSet(); animatorSet.setDuration(1000); animatorSet.setInterpolator(new BounceInterpolator()); animatorSet.playTogether(animator,animator1,animator2,animator3,animator4); animatorSet.start(); mFlag=true; } @Override public void onClick(View view) { switch (view.getId()) { case R.id.imageView_a: if (mFlag) { startAnim(); } else { stopAnim(); } break; default: Toast.makeText(getApplicationContext(), view.getId() + "", Toast.LENGTH_LONG).show(); tvTimer(text); break; } } private void tvTimer(final TextView view){ final ValueAnimator animator = ValueAnimator.ofInt(0,100); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { view.setText("$"+(Integer)animator.getAnimatedValue()); } }); animator.setDuration(3000); animator.start(); } }布局文件
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_suprise_animation" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.lvqueen.qunyinzhuan.day08.SupriseAnimationActivity"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageView_b" android:src="@mipmap/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="@mipmap/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="@mipmap/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="@mipmap/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="@mipmap/a" android:layout_centerVertical="true" android:layout_centerHorizontal="true" /> <TextView android:id="@+id/tv_texts" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="test"/> </RelativeLayout>