Android 动画学习

Android 动画学习

Android 按动画类型划分为两类:
  • View Animation
    • Tween Animation
      又称“补间动画”,较老的动画系统,常用来制作图片的一些特效(渐变、平移、缩放、旋转),适用于View对象
    • Frame 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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值