Android 动画学习
Android 动画学习
Android 按动画类型划分为两类:
- View Animation
- Tween Animation
又称“补间动画”,较老的动画系统,常用来制作图片的一些特效(渐变、平移、缩放、旋转),适用于View对象 - Frame Animation
又称“帧动画”,就是一系列图片按照顺序播放形成动画
- Tween Animation
- Property Animation
属性动画,Android 3.0(api 11)之后引入,与前两者不同是改变对象属性值赖达到动画效果
Property Animation与Tween Animation 之间的区别
Property Animation:更改的是对象的实际属性
Tween Animation:更改的是View的绘制效果,对象的属性值是不会改变的
Property Animation 主要类图
Property Animation 工作方式
要启动动画,首先创建一个 ValueAnimator或其子类并指定要动画显示的属性的初始值、结束值以及显示时间,然后调用 start() 启动动画。在整个动画过程中, ValueAnimator 根据动画总时间和已进行的时间自动计算出一个时间比例因子(elapsed fraction),大小介于0和1之间。 时间比例因子代表动画已完成时间的百分比,0 表示 0%,1 表示 100%。ValueAnimator 算完时间比例因子后,将调用已设置好的 TimeInterpolator 计算出一个插值因子(interpolated fraction)。插值因子是一个由时间比例因子换算出来的图像显示状态因子。算完插值因子, ValueAnimator 就会调用合适的 TypeEvaluator ,根据插值因子、初始值、结束值计算出需要动画显示的属性值。计算出属性值后,最后为需要执行动画的对象设置对应属性的属性值。动画在持续的整个过程中,会根据我们当初设置的TimeInterpolator 和TypeEvaluator的计算方式计算出的不同的属性值,从而不断地改变对象属性值的大小,进而产生各式各样的动画效果。
转自:Android 动画学习(二)之Property Animation初步介绍
Property Animation 使用方法
ValueAnimator是Property Animation系统的核心类,它包含了配置Property Animation属性的大部分方法,那要实现一个Property Animation,都需要直接或间接使用ValueAnimator类。
那一般使用ValueAnimator实现动画分为以下七个步骤:
1. 调用ValueAnimation类中的ofInt(int…values)、ofFloat(String propertyName,float…values)等静态方法实例化ValueAnimator对象,并设置目标属性的属性名、初始值或结束值等值;
2.调用addUpdateListener(AnimatorUpdateListener mListener)方法为ValueAnimator对象设置属性变化的监听器;
3.创建自定义的Interpolator,调用setInterpolator(TimeInterpolator value)为ValueAniamtor设置自定义的Interpolator;(可选,不设置默认为缺省值)
4.创建自定义的TypeEvaluator,调用setEvaluator(TypeEvaluator value)为ValueAnimator设置自定义的TypeEvaluator;(可选,不设置默认为缺省值)
5.在AnimatorUpdateListener 中的实现方法为目标对象的属性设置计算好的属性值。
6.设置动画的持续时间、是否重复及重复次数等属性;
7.为ValueAnimator设置目标对象并开始执行动画。
/** * 使用ValueAnimator改变Imageview的margin的值 */ public void marginValueAnimator(){ //1.调用ofInt(int...values)方法创建ValueAnimator对象 ValueAnimator mAnimator = ValueAnimator.ofInt(0,screenWidth - mImageViewTest.getWidth()); //2.为目标对象的属性变化设置监听器 mAnimator.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { // 3.为目标对象的属性设置计算好的属性值 int animatorValue = (int)animation.getAnimatedValue(); MarginLayoutParams marginLayoutParams = (MarginLayoutParams) mImageViewTest.getLayoutParams(); marginLayoutParams.leftMargin = animatorValue; mImageViewTest.setLayoutParams(marginLayoutParams); } }); //4.设置动画的持续时间、是否重复及重复次数等属性 mAnimator.setDuration(2000); mAnimator.setRepeatCount(3); mAnimator.setRepeatMode(ValueAnimator.REVERSE); //5.为ValueAnimator设置目标对象并开始执行动画 mAnimator.setTarget(mImageViewTest); mAnimator.start(); }
使用ObjectAnimator实现动画
我们接着学习一个比较重要的动画实现类–ObjectAnimator。该类作为ValueAnimator的子类不仅继承了ValueAnimator的所有方法和特性,并且还封装很多实用的方法,方便开发人员快速实现动画。同时,由于属性值会自动更新,使用ObjectAnimator实现动画不需要像ValueAnimator那样必须实现 ValueAnimator.AnimatorUpdateListener ,因此实现任意对象的动画显示就更加容易了。我们在大部分的开发工作中,都会使用ObjectAnimator而非ValueAnimator实现我们所需的动画效果。
前几篇博文我们都介绍了View Animation,我们了解了其实现View对象动画的特点,即View Animation本身是通过改变View的绘制方式来实现动画的,View对象本身的属性值并没有改变,对象仍然停留在原始位置。那Android为了消除这一弊病,在 Android 3.0 中给 View 增加了一些新的属性以及相应的 getter、setter 方法。Property Animation系统可以通过修改 View 对象实际的属性值来实现屏幕上的动画效果。此外,当属性值发生变化时,Views 也会自动调用 invalidate() 方法来刷新屏幕。 View 类中新增的便于实现 property 动画的属性包括:
(1) translationX 和 translationY:这两个属性控制着 View 的屏幕位置坐标变化量,以 layout 容器的左上角为坐标原点;
(2) rotation、rotationX 和 rotationY:这三个属性控制着 2D 旋转角度(rotation属性)和围绕某枢轴点的 3D 旋转角度;
(3) scaleX、scaleY:这两个属性控制着 View 围绕某枢轴点的 2D 缩放比例;
(4) pivotX 和 pivotY: 这两个属性控制着枢轴点的位置,前述的旋转和缩放都是以此点为中心展开的,缺省的枢轴点是 View 对象的中心点;
(5) x 和 y:这是指 View 在容器内的最终位置,等于 View 左上角相对于容器的坐标加上 translationX 和 translationY 后的值;
(6)alpha:表示 View 的 alpha 透明度。缺省值为 1 (不透明),为 0 则表示完全透明(看不见);
要动画显示 View 对象的某个属性,比如颜色或旋转值,我们所有要做的事情就是创建一个 Property animation,并设定对应的 View 属性。那接下来我们就用ObjectAnimator类来分别实现View的透明度渐变、收缩、移动和旋转等动画效果,那在此之前我们也来总结下使用ObjectAnimator实现动画的几个步骤,如下:
1.通过调用ofFloat()、ofInt()等方法创建ObjectAnimator对象,并设置目标对象、需要改变的目标属性名、初始值和结束值;
2.设置动画的持续时间、是否重复及重复次数等属性;
3.启动动画。
转自:Android动画学习(三)之使用ValueAnimator和ObjectAnimator实现动画实例
public class ObjectAnimatorFragment extends Fragment implements OnClickListener{ private ListView mListViewFront; private ListView mListViewReverse; private Button mButtonFlip; private Button mButtonAlpha; private Button mButtonScale; private Button mButtonTranslate; private Button mButtonRotate; private Button mButtonSet; private ImageView mImageView; private int screenWidth = 0; private int screenHeight = 0; String[] frontStrs = { "Front Page 1", "Front Page 2", "Front Page 3", "Front Page 4", "Front Page 5", "Front Page 6", }; String[] reverseStrs = { "Reverse Page 1", "Reverse Page 2", "Reverse Page 3", "Reverse Page 4", "Reverse Page 5", "Reverse Page 6", }; @Override public void onActivityCreated(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onActivityCreated(savedInstanceState); DisplayMetrics metrics = new DisplayMetrics(); getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics); float density = metrics.density; //screenWidth = (int)(metrics.widthPixels * density + 0.5f); //screenHeight = (int)(metrics.heightPixels * density + 0.5f); screenWidth = metrics.widthPixels; screenHeight = metrics.heightPixels; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // TODO Auto-generated method stub View rootView = inflater.inflate(R.layout.fragment_objectanimator, container, false); mListViewFront = (ListView) rootView.findViewById(R.id.front_page_listview); mListViewReverse = (ListView) rootView.findViewById(R.id.reverse_page_listview); mButtonFlip = (Button)rootView.findViewById(R.id.button_flip); mButtonFlip.setOnClickListener(this); mButtonAlpha = (Button)rootView.findViewById(R.id.button_alpha); mButtonAlpha.setOnClickListener(this); mButtonScale = (Button)rootView.findViewById(R.id.button_scale); mButtonScale.setOnClickListener(this); mButtonTranslate = (Button)rootView.findViewById(R.id.button_translate); mButtonTranslate.setOnClickListener(this); mButtonRotate = (Button)rootView.findViewById(R.id.button_rotate); mButtonRotate.setOnClickListener(this); mButtonSet = (Button)rootView.findViewById(R.id.button_set); mButtonSet.setOnClickListener(this); mImageView = (ImageView)rootView.findViewById(R.id.objectanimator_imageview); mImageView.setOnClickListener(this); initData(); return rootView; } public void initData(){ ArrayAdapter<String> frontListData = new ArrayAdapter<String>(getActivity(), R.layout.layout_objectanimator_item,R.id.objectanimtor_item_textview, frontStrs); ArrayAdapter<String> reverseListData = new ArrayAdapter<String>(getActivity(), R.layout.layout_objectanimator_item,R.id.objectanimtor_item_textview, reverseStrs); mListViewFront.setAdapter(frontListData); mListViewReverse.setAdapter(reverseListData); mListViewReverse.setRotationX(-90.0f); } @Override public void onPause() { // TODO Auto-generated method stub super.onPause(); } @Override public void onClick(View v) { // TODO Auto-generated method stub switch (v.getId()) { case R.id.button_flip: flip(); break; case R.id.button_alpha: alphaAnimator(); break; case R.id.button_scale: scaleAnimator(); break; case R.id.button_translate: translateAniamtor(); break; case R.id.button_rotate: rotateAniamtor(); break; case R.id.button_set: setAnimator(); break; case R.id.objectanimator_imageview: mListViewFront.setVisibility(View.VISIBLE); mImageView.setVisibility(View.GONE); break; default: break; } } /** * 翻转动画效果 */ public void flip(){ final ListView visibleView; final ListView invisibleView; if(mListViewFront.getVisibility() == View.GONE){ visibleView = mListViewReverse; invisibleView = mListViewFront; }else{ visibleView = mListViewFront; invisibleView = mListViewReverse; } //创建ListView从Visible到Gone的动画 ObjectAnimator visibleToInVisable = ObjectAnimator.ofFloat(visibleView, "rotationX", 0.0f,90.0f); //设置插值器 visibleToInVisable.setInterpolator(new AccelerateInterpolator()); visibleToInVisable.setDuration(500); //创建ListView从Gone到Visible的动画 final ObjectAnimator invisibleToVisible = ObjectAnimator.ofFloat(invisibleView, "rotationX", -90.0f,0.0f); //设置插值器 invisibleToVisible.setInterpolator(new DecelerateInterpolator()); invisibleToVisible.setDuration(500); visibleToInVisable.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { // TODO Auto-generated method stub super.onAnimationEnd(animation); visibleView.setVisibility(View.GONE); invisibleToVisible.start(); invisibleView.setVisibility(View.VISIBLE); } }); visibleToInVisable.start(); } /** * 渐变动画效果 */ public void alphaAnimator(){ ListView alphaListView = null; if(mListViewFront.getVisibility() == View.GONE){ alphaListView = mListViewReverse; }else{ alphaListView = mListViewFront; } //1、通过调用ofFloat()方法创建ObjectAnimator对象,并设置目标对象、需要改变的目标属性名、初始值和结束值; ObjectAnimator mAnimatorAlpha = ObjectAnimator.ofFloat(alphaListView, "alpha", 1.0f,0.0f); //2、设置动画的持续时间、是否重复及重复次数属性; mAnimatorAlpha.setRepeatMode(Animation.REVERSE); mAnimatorAlpha.setRepeatCount(3); mAnimatorAlpha.setDuration(1000); //3、启动动画 mAnimatorAlpha.start(); } /** * 伸缩动画效果 */ public void scaleAnimator(){ ListView scaleListView = null; if(mListViewFront.getVisibility() == View.GONE){ scaleListView = mListViewReverse; }else{ scaleListView = mListViewFront; } ObjectAnimator mAnimatorScaleX = ObjectAnimator.ofFloat(scaleListView, "scaleX", 1.0f,0.0f); mAnimatorScaleX.setRepeatMode(Animation.REVERSE); mAnimatorScaleX.setRepeatCount(3); mAnimatorScaleX.setDuration(1000); ObjectAnimator mAnimatorScaleY = ObjectAnimator.ofFloat(scaleListView, "scaleY", 1.0f,0.0f); mAnimatorScaleY.setRepeatMode(Animation.REVERSE); mAnimatorScaleY.setRepeatCount(3); mAnimatorScaleY.setDuration(1000); mAnimatorScaleX.start(); mAnimatorScaleY.start(); } /** * 位移动画效果 */ public void translateAniamtor(){ ListView translateListView = null; if(mListViewFront.getVisibility() == View.GONE){ translateListView = mListViewReverse; }else{ translateListView = mListViewFront; } ObjectAnimator mAnimatorTranslateX = ObjectAnimator.ofFloat(translateListView, "translationX", 0.0f,screenWidth/2); mAnimatorTranslateX.setRepeatMode(Animation.REVERSE); mAnimatorTranslateX.setRepeatCount(3); mAnimatorTranslateX.setDuration(1000); ObjectAnimator mAnimatorTranslateY = ObjectAnimator.ofFloat(translateListView, "translationY", 0.0f,screenHeight/2); mAnimatorTranslateY.setRepeatMode(Animation.REVERSE); mAnimatorTranslateY.setRepeatCount(3); mAnimatorTranslateY.setDuration(1000); mAnimatorTranslateX.start(); mAnimatorTranslateY.start(); } /** * 旋转动画效果 */ public void rotateAniamtor(){ ListView rotateListView = null; if(mListViewFront.getVisibility() == View.GONE){ rotateListView = mListViewReverse; }else{ rotateListView = mListViewFront; } ObjectAnimator mAnimatorRotate = ObjectAnimator.ofFloat(rotateListView, "rotation", 0.0f,360.0f); mAnimatorRotate.setRepeatMode(Animation.REVERSE); mAnimatorRotate.setRepeatCount(2); mAnimatorRotate.setDuration(2000); mAnimatorRotate.start(); } /** * 动画集合 */ public void setAnimator(){ ListView setListView = null; if(mListViewFront.getVisibility() == View.GONE){ setListView = mListViewReverse; }else{ setListView = mListViewFront; } setListView.setVisibility(View.GONE); if(mImageView.getVisibility() == View.GONE){ mImageView.setVisibility(View.VISIBLE); } //代码方式设置动画 codeAnimatorSet(mImageView); //用ViewPropertyAnimator实现动画 //viewPropertyAnimator(setListView); //加载XML文件中的动画 /*AnimatorSet mAnimatorSet = (AnimatorSet) AnimatorInflater.loadAnimator(getActivity(), R.animator.property_animation_animatorset); mAnimatorSet.setTarget(mImageView); mAnimatorSet.start();*/ } /** * 使用编码方式实现动画效果 * @param mImageView */ public void codeAnimatorSet(ImageView mImageView){ AnimatorSet mAnimatorSet = new AnimatorSet(); ObjectAnimator mAnimatorSetRotateX = ObjectAnimator.ofFloat(mImageView, "rotationX", 0.0f,360.0f); mAnimatorSetRotateX.setDuration(3000); ObjectAnimator mAnimatorSetRotateY = ObjectAnimator.ofFloat(mImageView, "rotationY", 0.0f,360.0f); mAnimatorSetRotateY.setDuration(3000); ObjectAnimator mAnimatorScaleX = ObjectAnimator.ofFloat(mImageView, "scaleX", 1.0f,0.5f); mAnimatorScaleX.setRepeatCount(1); mAnimatorScaleX.setRepeatMode(Animation.REVERSE); mAnimatorScaleX.setDuration(1500); ObjectAnimator mAnimatorScaleY = ObjectAnimator.ofFloat(mImageView, "scaleY", 1.0f,0.5f); mAnimatorScaleY.setRepeatCount(1); mAnimatorScaleY.setRepeatMode(Animation.REVERSE); mAnimatorScaleY.setDuration(1500); mAnimatorSet.play(mAnimatorSetRotateY).with(mAnimatorScaleX); mAnimatorSet.play(mAnimatorScaleX).with(mAnimatorScaleY); mAnimatorSet.play(mAnimatorSetRotateY).before(mAnimatorSetRotateX); mAnimatorSet.start(); } public void viewPropertyAnimator(ListView mListViewHolder){ mListViewHolder.animate().cancel(); mListViewHolder.animate().rotationX(360.0f).setDuration(3000).start(); }}
作为记录学习,多数内容转自:yegongheng的blog
更多相关文章
- Android 布局文件属性讲解
- Android工作学习笔记之图片自适应imageview属性android:scaleTyp
- Android 复习笔记之图解View类的XML属性、相关方法及说明
- Android 开发者 for Flutter (3) flutter中动画是如何实现的 及 如
- android过渡动画之makeSceneTransitionAnimation学习笔记