美文网首页
三、Android 动画机制

三、Android 动画机制

作者: 锦文豪武 | 来源:发表于2018-09-21 17:25 被阅读0次

    A、逐帧动画(Frame Animation)

    逐帧动画也叫Drawable Animation,最直观最简单的动画类型,他利用人眼的视觉暂留效应。指定动画中每一帧对应的图片和持续的时间。两种方式定义逐帧动画,分别是采用XML文件和代码实现。

    (1)xml资源文件方式

    这种方法最常用:首先将每一帧的图片放到res/drawable目录中,然后drawable目录中新建一个XML文件,在这个文件中使用<animation-list> 标签定义动画帧序列,使用<item>标签来定义动画的每一帧,并在其中指定的储蓄时间等属性。例子如下:

    drawable目录中新建一个XML文件

     <?xml version="1.0" encoding="utf-8"?>
     <animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">
    
    <item android:drawable="@drawable/t1"
        android:duration="120"/>
    <item android:drawable="@drawable/t2"
        android:duration="120"/>
    <item android:drawable="@drawable/t3"
        android:duration="120"/>
    <item android:drawable="@drawable/t4"
        android:duration="120"/>
    <item android:drawable="@drawable/t5"
        android:duration="120"/>
    <item android:drawable="@drawable/t6"
        android:duration="120"/>
    <item android:drawable="@drawable/t7"
        android:duration="120"/>
    <item android:drawable="@drawable/t8"
        android:duration="120"/>
    
     </animation-list>
    

    然后在XML布局中引用

     <ImageView
    android:id="@+id/iv"
    android:layout_centerInParent="true"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/frame_animation"
    />
    

    Activity引用

     AnimationDrawable drawable;
     CustomTextView custom_text;
    
     iv=findViewById(R.id.iv);
     drawable = (AnimationDrawable) iv.getBackground();
     if (drawable != null && !drawable.isRunning()) {
        drawable.start();
     }
     //停止
     if (drawable != null && !drawable.isRunning()) {
         drawable.stop();
     }
    

    (2)代码的方式添加逐帧动画

     ImageView iv;
     AnimationDrawable  drawable;
     @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_animation);
         iv = findViewById(R.id.iv);
         drawable = new AnimationDrawable();
         drawable.addFrame(getResources().getDrawable(R.drawable.t1),120);
         drawable.addFrame(getResources().getDrawable(R.drawable.t2),120);
         drawable.addFrame(getResources().getDrawable(R.drawable.t3),120);
         drawable.addFrame(getResources().getDrawable(R.drawable.t4),120);
         drawable.addFrame(getResources().getDrawable(R.drawable.t5),120);
         drawable.addFrame(getResources().getDrawable(R.drawable.t6),120);
         drawable.addFrame(getResources().getDrawable(R.drawable.t7),120);
         drawable.addFrame(getResources().getDrawable(R.drawable.t8),120);
         drawable.setOneShot(false);
         iv.setBackground(drawable);
         drawable.start();
    }
    

    B、补间动画(Tween Animation)

    补间动画是指开发者无需定义动画过程的每一帧,只需要定义动画的开始和结束这两个关键帧,并制定动画变化的时间和方式,然后由系统进行计算,通过两个关键帧之间插入的渐变值来实现平滑过渡,从而实现动画效果。

    (1)主要包括四种基本效果:

    QQ图片20180921163614.png

    (2)插值器 Interpolator

    开始和结束关键帧之间插入渐变值,依据的就是Interpolator,Interpolator负责控制动画的变化速度,使得四种基本动画效果能够以匀速、加速、减速、抛物线等多种速度进行变化

    Android SDK默认提供了几个Interpolator实现类:

    QQ图片20180921163756.png

    (3)四种动画基本类型:

    QQ图片20180921163847.png

    a、公共属性

    QQ图片20180921163941.png

    注:android:zAdhustment:允许动画在播放期间,调整播放内容在Z轴方向顺序:
    top(1):在动画播放期间,强制把当前播放的内容放到其他内容的上面
    normal(0):正在播放当前的动画内容保持当前的Z轴顺序
    bottom(-1):在动画播放期间,强制把当前播放内容放到其他内容之下

    b、AlphaAnimation (透明渐变)

    (1)XML方式就是在res/anim目录中新建XML文件:

    xml文件
     <?xml version="1.0" encoding="utf-8"?>
     <alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="3000"
    android:fromAlpha="1.0"
    android:toAlpha="0.0"
    android:repeatCount="2"
    android:interpolator="@android:anim/overshoot_interpolator"
    android:repeatMode="restart"
    >
     </alpha>
    
    QQ图片20180921164127.png
    在Activity 中:
     Animation alphaAnimation;
     alphaAnimation=  AnimationUtils.loadAnimation          (AnimationActivity.this,R.anim.alpha_animation);
     iv1.startAnimation(alphaAnimation);
    

    (2)代码的方式:

     /**第一个参数开始透明度
      * 第二个参数结束透明度*/
     alphaAnimation=new AlphaAnimation(0,1);//透明度从0变化到1
     alphaAnimation.setDuration(2000);//持续时间
     alphaAnimation.setFillAfter(true);//动画结束后保留结束状态
     iv1.setAnimation(alphaAnimation);
    

    c、ScaleAnimation(缩放动画)

    (1)XML 实现:

    xml文件

    !--缩放动画-->
    <scale xmlns:android="http://schemas.android.com/apk/res/android"

    android:duration="2000"
    android:fromXScale="0"
    android:fromYScale="0"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toXScale="1"
    android:toYScale="1"
    android:repeatCount="2"
    android:repeatMode="reverse"
    android:startOffset="1000">
    
     </scale>
    
    Activity中
     Animation animation;
     animation=  AnimationUtils.loadAnimation(AnimationActivity.this,R.anim.scale_animation);
     iv1.startAnimation(alphaAnimation);
    
    QQ图片20180921164804.png

    (2)代码实现:

     /***
      * 缩放,放大
      * 动画开始时的 X 坐标的伸缩尺寸
      * 动画结束时的 X 坐标的伸缩尺寸
      * 动画开始时的 Y 坐标的伸缩尺寸
      * 动画结束时的 Y 坐标的伸缩尺寸
      * 缩放动画的中心点 X 坐标
      * 动画在 X 轴的伸缩模式,也就是中心点相对哪个物件,取值:                     Animation.ABSOLUTE、Animation.RELATIVE_TO或者      Animation.RELATIVE_TO_PARENT
       * 缩放动画的中心点 Y 坐标
       * 动画在 Y 轴的伸缩模式,也就是中心点相对哪个物件,取值:Animation.ABSOLUTE、Animation.RELATIVE_TO或者Animation.RELATIVE_TO_PARENT
       */
      private void scaleAnimation(){
    ScaleAnimation scale=new ScaleAnimation(1.0f, 0.5f, 1.0f, 0.5f,Animation.RELATIVE_TO_SELF,0.0f,Animation.RELATIVE_TO_SELF,0.0f);
    scale.setDuration(20000);
         // scale.setFillAfter(true);
          iv1.setAnimation(scale);
      }
    

    d、TranslateAnimation (移动动画)

    (1)XML实现

    xml文件
      <!--位移 动画-->
     <translate xmlns:android="http://schemas.android.com/apk/res/android"
    
    android:duration="2000"
    android:fromXDelta="0%"
    android:fromYDelta="0%"
    android:toXDelta="100%"
    android:toYDelta="100%"
    android:repeatCount="3"
    android:repeatMode="reverse">
    
      </translate>
    
    Activity中
       animation=  AnimationUtils.loadAnimation(AnimationActivity.this,R.anim.translate_animation);
      iv1.startAnimation(animation);
    

    (2)代码实现:

      /***
       * 位移
       * 动画开始时的 X 坐标
       * 动画结束时的 X 坐标
       *  动画开始时的 Y 坐标
       * 动画结束时的 Y 坐标
       */
      private void translateAnimation(){
         TranslateAnimation translateAnimation = new TranslateAnimation(0,100,0,100);
         translateAnimation.setDuration(3000);
         translateAnimation.setRepeatCount(3);
         translateAnimation.setRepeatMode(1);
         iv1.setAnimation(translateAnimation);
      }
    

    e、RotateAnimation(旋转动画)

    (1)XML实现

    xml文件
      <!--旋转动画,
      fromDegrees开始旋转角度
      toDegrees结束旋转角度
      pivotY Y轴旋转中心点
      pivotX X轴旋转中心点
      -->
      <rotate xmlns:android="http://schemas.android.com/apk/res/android"
    
    
    android:pivotY="50%"
    android:pivotX="50%"
    android:fromDegrees="0"
    android:toDegrees="720"
    android:duration="3000"
    android:repeatCount="2"
    android:repeatMode="reverse">
      </rotate>
    
    Activity中
      animation = AnimationUtils.loadAnimation(AnimationActivity.this,R.anim.rotate_animation);
      iv1.startAnimation(animation);
    

    (2)代码实现

      /**
       * 旋转
       * 开始角度
       * 结束时的角度
       * 动画在X轴的旋转模式
       * 动画相对于物件的Y轴坐标开始
       *
       */
      private void rotateAnimation(){
    RotateAnimation rotateAnimation=new RotateAnimation(0,720,50,50);
    rotateAnimation.setDuration(2000);
    iv1.setAnimation(rotateAnimation);
    

    f、自定义补间动画

    需要继承Animation,重写抽象基类中的applyTransformation方法
    该抽象方法

    (1)方法描述

    QQ图片20180921165334.png

    (2)Demo测试

    自定义
      import android.graphics.Camera;
      import android.graphics.Matrix;
      import android.view.animation.Animation;
      import android.view.animation.LinearInterpolator;
      import android.view.animation.Transformation;
    
      /**
       * Created by chaohao.zhao on 2018/8/29.
       * 自定义补间动画
       */
    
      public class CustomAnimation extends Animation {
    /**
     * Camera并非代表手机的摄像头,而是一个空间变换工具,作用有点类似于Matrix,但是比Matrix更加强大
     * */
    private Camera camera=new Camera();
    private float centerX;
    private float centerY;
    private int duration;
    
    
    public CustomAnimation(int duration,float centerX,float centerY){
        this.duration=duration;
        this.centerX=centerX;
        this.centerY=centerY;
    }
    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        //设置动画持续时间
        setDuration(duration);
        //设置动画结束后的结果保留
        setFillAfter(false);
        //设置匀速变化
        setInterpolator(new LinearInterpolator());
    }
    
    /**
     *
     * @param interpolatedTime 动画的时间进行比,无论动画时间是多少,数值都会是从0到1
     * @param t 不同时刻对view的变形程度,对目标组件所做的改变
     */
    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        super.applyTransformation(interpolatedTime, t);
        camera.save();
        //根据interpolatedTime时间来控制在X ,y , z轴上的偏移.是目标组件在三维空间位移变换
        camera.translate(100.f - 100.f * interpolatedTime,150.f * interpolatedTime,80.0f - 80.f * interpolatedTime);
        //设置根据interpolatedTime时间在x轴为中心旋转
        camera.rotateX(360 * interpolatedTime);
        //根据interpolateTime时间,在y轴为中心旋转
        camera.rotateY(360 * interpolatedTime);
        //沿着在 z 轴上旋转
        camera.rotateZ(360 * interpolatedTime);
        /**设置旋转中心*/
        Matrix matrix = t.getMatrix();
        camera.getMatrix(matrix);
        /**在旋转之间先把图片想上移动图片高度一半的距离,这样就对称了,然后在旋转*/
        matrix.preTranslate(-centerX,-centerY);
        /**centerX和centerY是界面中心的坐标,变换之后图片在下移动,图片高度的一半就是回到了原来的距离*/
        matrix.postTranslate(centerX,centerY);
        camera.restore();
    
    }
      }
    
    在Activity中:
      CustomAnimation customAnimation;
      ImageView iv;
      DisplayMetrics metrics= new DisplayMetrics();
      getWindowManager().getDefaultDisplay().getMetrics(metrics);
      customAnimation=new CustomAnimation(4000,metrics.xdpi /2,metrics.ydpi/2);
      iv.setAnimation(customAnimation);
    

    C、属性动画(property Animation)

    Android 3.0引入属性动画,在补间动画中,我们能改变View的绘制效果,View的真实属性是没有变化的,而属性动画则可以改变View对象的属性值,同时属性动画可以对任何对象执行动画,而不是局限在View的对象是哪个,从某种意义上说是增强版的补间动画。

    (1)动画属性

    QQ图片20180921165647.png

    属性动画的基类是Animator,他是一个抽象类,继承重写其中相关方法;Android SDK提供几个子类,打多少使用就足够完成开发。

    (2)Evaluator(设置颜色过渡动画)

    a.创建ArgbEvaluator 实现 TypeEvaluator(估值器)

      /**
       * Created by chaohao.zhao on 2018/8/31.
       * 用来控制属性动画计算属性值的。根据输入的初始值和结束之及一个进度比,计算出每一个进度的ARGB值.
       */
    
      public class ArgbEvaluator implements TypeEvaluator {
    private static ArgbEvaluator evaluator=new ArgbEvaluator();
    
    public static ArgbEvaluator getInstance(){
        return evaluator;
    }
    
    /**
     *
     * @param fraction 颜色渐变度 取0.0F-1.0F之间某一值
     * @param startValue 开始颜色值
     * @param endValue 结束颜色值
     * @return
     */
    @Override
    public Object evaluate(float fraction, Object startValue, Object endValue) {
        int startInt = (int) startValue;
        int startA = (startInt >> 24) & 0xff;
        int startR = (startInt >> 16) & 0xff;
        int startG = (startInt >> 8) & 0xff;
        int startB = startInt & 0xff;
    
        int endInt = (int) endValue;
        int endA = (endInt >> 24) & 0xff;
        int endR = (endInt >> 16) & 0xff;
        int endG = (endInt >> 8) & 0xff;
        int endB = endInt & 0xff;
        /**三个参数计算得到的渐变颜色值*/
        int value = startA + (int)(fraction * (endA - startA)) << 24 |
                    startR + (int)(fraction * (endR - startR)) << 16 |
                    startG + (int)(fraction * (endG - startG)) << 8|
                    startB + (int)(fraction * (endB - startB));
        return value;
    }
      }
    

    b.引用类,设置颜色动画

      /**
       *属性动画
       */
      public class AttritubeActivity extends AppCompatActivity {
    ViewPager viewPager;
    Toolbar toolbar;
    private int pagerOneColor;
    private int pagerTwoColor;
    private int pagerThreeColor;
    List<TextView> itemList=new ArrayList<>();
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_attritube);
        viewPager=findViewById(R.id.viewPager);
        toolbar=findViewById(R.id.toolbar);
        pagerOneColor = ContextCompat.getColor(this, R.color.colorPrimary);
        pagerTwoColor = ContextCompat.getColor(this, R.color.colorAccent);
        pagerThreeColor = ContextCompat.getColor(this, R.color.colorPrimaryDark);
    
        TextView textOne = new TextView(this);
        textOne.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        textOne.setGravity(Gravity.CENTER);
        textOne.setText("第一页");
        textOne.setBackgroundColor(pagerOneColor);
        itemList.add(textOne);
    
        TextView textTwo = new TextView(this);
        textTwo.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        textTwo.setGravity(Gravity.CENTER);
        textTwo.setBackgroundColor(pagerTwoColor);
        textTwo.setText("第二页");
        itemList.add(textTwo);
    
        TextView textThree = new TextView(this);
        textThree.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        textThree.setGravity(Gravity.CENTER);
        textThree.setBackgroundColor(pagerThreeColor);
        textTwo.setText("第三页");
        itemList.add(textThree);
        viewPager.setAdapter(new MyAdapter(itemList));
    
        viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                changeColor(position,positionOffset);
    
    
            }
    
            @Override
            public void onPageSelected(int position) {
    
            }
    
            @Override
            public void onPageScrollStateChanged(int state) {
    
            }
        });
    }
    public class MyAdapter extends PagerAdapter{
        List<TextView> txtList;
        public MyAdapter(List<TextView> list){
            this.txtList = list;
        }
    
        @Override
        public int getCount() {
            if (null == txtList){
                return  0;
            }
            return txtList.size();
        }
    
        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }
    
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView(txtList.get(position));
        }
    
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            container.addView(txtList.get(position));
            return txtList.get(position);
        }
    }
    public void changeColor (int position,float positionOffset){
        switch(position){
            case 0:
                setToolbarColor((Integer) ArgbEvaluator.getInstance().evaluate(positionOffset,pagerOneColor,pagerTwoColor));
                setStatusBarColor((Integer) ArgbEvaluator.getInstance().evaluate(positionOffset,pagerOneColor,pagerTwoColor));
                break;
            case 1:
                setToolbarColor((Integer) ArgbEvaluator.getInstance().evaluate(positionOffset,pagerTwoColor,pagerThreeColor));
                setStatusBarColor((Integer) ArgbEvaluator.getInstance().evaluate(positionOffset,pagerTwoColor,pagerThreeColor));
                break;
            case 2:
                setStatusBarColor(pagerThreeColor);
                break;
    
        }
    
    }
    /**
     * 给状态栏设置颜色
     * 安卓系统4.4以上可用
     * 不向下兼容
     *
     * @param color
     */
    private void setStatusBarColor(int color) {
        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                Window window = this.getWindow();
                window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
                window.setStatusBarColor(color);
                //window.setNavigationBarColor(activity.getResources().getColor(colorResId));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    private void setToolbarColor(int color) {
        if (toolbar != null) {
            toolbar.setBackgroundColor(color);
        }
    }
    
      }
    

    (3)AnimatorSet(组合动画)

    AnimatorSet也是Animator的子类,用来组合多个Animator,并制定Anination是顺序播放还是同时播放。

    a、属性及描述

    QQ图片20180921165928.png

    b、XML实现举个例子

    1、Xml中,创建 res中animator 文件夹

      <?xml version="1.0" encoding="utf-8"?>
    
      <!--
      ordering 表示动画开始顺序sequentially表示逐个开始,together 表示同时开始
      propertyName 对应属性名,
      valueFrom 初始动画值float,int和color三种类型的值
      valueTo 动画结束值float,int和color
      valueType 表示数值类型
      -->
      <set xmlns:android="http://schemas.android.com/apk/res/android"
    
    android:ordering="together">
    <!--第一个动画-->
    <objectAnimator
    
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:propertyName="alpha"
        android:duration="3000"
        android:valueType="floatType"
        android:valueFrom="0"
        android:valueTo="1"
        />
    <!--第二个动画-->
    <objectAnimator
    
        android:interpolator="@android:anim/anticipate_overshoot_interpolator"
        android:propertyName="scaleX"
        android:duration="3000"
        android:valueType="floatType"
        android:valueFrom="0.5"
        android:valueTo="1.5"
        />
    <!--第三个动画 移动  bounce_interpolator回弹插值器-->
    <objectAnimator
    
        android:interpolator="@android:anim/bounce_interpolator"
        android:propertyName="TranslationY"
        android:duration="3000"
        android:valueType="floatType"
        android:valueFrom="-400.0"
        android:valueTo="400.0"
        />
    <!--第四个动画 旋转-->
    <objectAnimator
    
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:duration="3000"
        android:propertyName="rotation"
        android:valueFrom="0"
        android:valueTo="720"
        android:valueType="floatType"
        />
    
    <objectAnimator
        android:interpolator="@android:anim/bounce_interpolator"
        android:propertyName="x"
        android:duration="3000"
        android:valueType="floatType"
        android:valueFrom="0.0"
        android:valueTo="300.0"
        />
      <!--第六个动画 移动 y轴-->
    <objectAnimator
    
        android:interpolator="@android:anim/bounce_interpolator"
        android:propertyName="y"
        android:duration="3000"
        android:valueType="floatType"
        android:valueFrom="0.0"
        android:valueTo="500.0"
        />
    
      </set>
    

    2、在activity中

      **
       * 组合动画
       */
      public class AnimatorSetActivity extends AppCompatActivity {
    ImageView img;
    AnimatorSet animatorSet;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_animator_set);
        img=findViewById(R.id.img);
        animatorSet= (AnimatorSet) AnimatorInflater.loadAnimator(this,R.animator.set_animator);
        animatorSet.setTarget(img);
        animatorSet.start();
    
    }
    

    }

    c、代码实现

      /**
       * 代码实现
       */
      public void animationSet(){
    ObjectAnimator animatorD=ObjectAnimator.ofFloat(img,"alpha",0,1);
    ObjectAnimator animatorA=ObjectAnimator.ofFloat(img,"TranslationX",-300,300,0);
    ObjectAnimator animatorB=ObjectAnimator.ofFloat(img,"scaleY",0.5f,1.5f,1f);
    ObjectAnimator animatorC=ObjectAnimator.ofFloat(img,"rotation",0,270,90,180,0);
    animatorSet=new AnimatorSet();
    /**一起执行*/
    //  animatorSet.playTogether(animatorA,animatorB,animatorC,animatorD);
    /**顺序执行*/
    animatorSet.playSequentially(animatorA,animatorB,animatorC,animatorD);
    animatorSet.setDuration(5000);
    animatorSet.start();
    }
    

    (4)ValueAnimator (数值器)

    本身不会作用与任何一个属性,本身也不会提供任何动画,他就是一个数值器,可以产生你想要的各种数值,其实在Android 动画中,如何产生每一步的具体实现动画效果,都是通过ValueAnimator计算出来的的
    ValueAnimator 直接继承自抽象类Animator,他是整个属性动画中最重要的一个类,它定义了属性动画的核心功能,包括计算各个帧的属性值、处理更新事件,按照属性值的类型控制计算机规则等,一个完整的属性动画由以下两部分组成。
    *计算动画各个帧的相关属性值。
    *将这些属性值设置给指定的对象。

    例子:切换出发地和 目的地城市

    QQ图片20180921170824.png

    因为切换只有平行移动,所以只需要获取X轴坐标就行。代码如下:

      public class ValueAnimatorActivity extends AppCompatActivity {
    Button switch_way;
    TextView origin,destination;
    int startX;
    int endX;
    private boolean moving = false;
    /**防止连续*/
    private static long lastClickTime;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_value_animator);
        switch_way = findViewById(R.id.switch_way);
        origin = findViewById(R.id.origin);
        destination = findViewById(R.id.destination);
    
        switch_way.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
    
                if (isFastDoubleClick()){
                   return;
                }
                move();
            }
        });
    }
     /**坐标
     * 因为只有平移移动
    * 只需要横坐标
    不能在onCreated中获取,也不能在onResume中获取,要在获取焦点时候获取
     * */
       private void getLocation(){
    
        int [] startLocation = new int[2];
        origin.getLocationOnScreen(startLocation);
        int [] endLocation = new int[2];
        destination.getLocationOnScreen(endLocation);
        /**开始出发地横坐标*/
        startX = startLocation[0];
        /**目的地横坐标*/
        endX = endLocation[0];
        Log.d("坐标点",startX+"     "+endX);
    }
    
    /**
     * 移动距离
     * 动画代码
     */
    private void move(){
        getLocation();
        /**出发地移动距离*/
        final int moveX = endX - startX + destination.getWidth() - origin.getWidth();
        /**出发地动画代码*/
        ValueAnimator startAnimator = ValueAnimator.ofInt(0,moveX)
                .setDuration(500);
        startAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int value = (int) animation.getAnimatedValue();
                origin.layout(startX + value,origin.getTop(),startX + value + origin.getWidth(),origin.getBottom());
            }
        });
        startAnimator.start();
    
    
        /**目的地移动距离*/
        final int rightMoveX = endX - startX;
        /**目的地动画代码*/
        ValueAnimator endAnimator = ValueAnimator.ofInt(0,rightMoveX).setDuration(500);
        endAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int value = (int) animation.getAnimatedValue();
                destination.layout(endX - value, destination.getTop(),endX + destination.getWidth() - value,destination.getBottom());
    
          }
        });
        endAnimator.start();
        /**调换位置*/
        endAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                TextView flagTxt = origin;
                origin = destination;
                destination = flagTxt;
    
            }
        });
    }
    /**
     * 防止双击按钮
     * @return
     */
    public static boolean isFastDoubleClick() {
        long time = System.currentTimeMillis();
        if ( time - lastClickTime < 500) {
            return true;
        }
        lastClickTime = time;
        return false;
        }
    }
    

    (5)过渡动画 (Transition Animation)

    过渡动画是在Android4.4引入的新的动画框架,他的本质上还是属性动画,只不过是对属性的一层封装,和属性动画最大的不同就是需要为动画前后准备不同的布局,transition 动画具有视觉连续的场景切换

    a、Scene Transition(场景过渡动画)

    是指以动画的形式实现View 两个场景的切换(从一个场景切换到另外一个场景),切换过程中通过Transition来设置不同的过渡动画效果。
    关键概念:Scene(场景) Transition(过渡)
    Transition:定义了界面之间切换的动画信息
    在使用TransitionManager 时没有指定使用哪个Transition,那么会使用默认的AutoTransition.AutoTransition动画效果就是先隐藏对象变透明,然后一定指定的对象,最后显示出来

    系统给出的常用的过渡动画:
    QQ图片20180921171102.png

    要实现一个场景过渡动画,至少需要一个transition实例和一个ending scene实例。并通过TransitionManager 执行过渡动画,执行方式有两种:TransitionManager.go()、beginDelayedTransition();

    (1)TransitionManager.go()开启场景动画
    /***
     * 过渡动画
     */
    public class SceneTransitionActivity extends AppCompatActivity {
        Scene scene1;
        Scene scene2;
        RelativeLayout layout;
        private boolean isScene = false;
        Button button;
        /**改变目标视图的布局边界*/
        ChangeBounds changeBounds;
        /**分解,从屏幕中间进,或者出去.移动视图*/
        Explode explode;
        /**改变目标视图的缩放比例和旋转角度*/
        ChangeTransform changeTransform;
        /**裁切目标视图边界*/
    ChangeClipBounds changeClipBounds;
    /**改变目标图片的大小和缩放比例*/
    ChangeImageTransform changeImageTransform;
    /**根据透明度,创建淡出淡入的动画*/
    Fade fade;
    /**滑动视图*/
    Slide slide;
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scene_transition);
    
        changeBounds = new ChangeBounds();
        explode = new Explode();
        changeTransform = new ChangeTransform();
        changeClipBounds = new ChangeClipBounds();
        changeImageTransform = new ChangeImageTransform();
        fade = new Fade();
        slide = new Slide();
        layout = findViewById(R.id.viewGp);
        button = findViewById(R.id.qiehuan);
    /**View一*/
        scene1 = Scene.getSceneForLayout(layout,R.layout.start_scene_transition,this);
        /**View二*/
    scene2 = Scene.getSceneForLayout(layout,R.layout.end_scene_transition,this);
        TransitionManager.go(scene1,changeImageTransform);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
    
                if (isScene){
                    TransitionManager.go(scene1,changeImageTransform);
                }else{
                    TransitionManager.go(scene2,changeImageTransform);
                }
                isScene = !isScene;
            }
        });
    }
    }
    

    (2)beginDelayedTransition()

    第一个参数是布局GroupView,第二个是动画
    TransitionManager.beginDelayedTransition(layout,fade);

    b、Activity过渡动画

    因为5.0以后才能使用,所以需要判断的

    (1)XML实现

    在res中创建transition文件夹

    xml

    <?xml version="1.0" encoding="utf-8"?>
    <transitionManager xmlns:android="http://schemas.android.com/apk/res/android">
    
    <transition
        android:fromScene="@layout/start_scene_transition"
        android:toScene="@layout/end_scene_transition"
        android:transition="@transition/activity_explode"/>
    </transitionManager>
    
    
    <?xml version="1.0" encoding="utf-8"?>
    <transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
    android:transitionOrdering="sequential">
    <fade
        android:fadingMode="fade_out"
        android:duration="1000"/>
    <changeBounds
        android:duration="2000"
        android:interpolator="@android:interpolator/overshoot"/>
    <fade
        android:fadingMode="fade_in"
        android:duration="1000"/>
    
    </transitionSet>
    
    TransitionInflater inflater  = TransitionInflater.from(this);
    TransitionManager transitionManager=inflater.inflateTransitionManager            (R.transition.trasition_manager,layout);
    scene1 = Scene.getSceneForLayout(layout,R.layout.start_scene_transition,this);
    scene2 = Scene.getSceneForLayout(layout,R.layout.end_scene_transition,this);
    
    在style中
    <resources>
    
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:windowAnimationStyle">@style/activityAniamtion</item>
    </style>
    
    <style name="activityAniamtion">
        <item name="android:activityOpenEnterAnimation">@transition/activity_fade</item>
        <item name="android:activityOpenExitAnimation">@transition/activity_fade</item>
    
    
    </style>
    
    </resources>
    
    (2)代码中
    public class OneAnimationTransitionActivity extends AppCompatActivity {
    
    Button button;
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Transition transition = TransitionInflater.from(this).inflateTransition(android.R.transition.explode);
    transition.setDuration(2000);
    transition.setInterpolator(CycleInterpolator);
    getWindow().setEnterTransition(transition);
    getWindow().setExitTransition(transition);
    
        getWindow().setEnterTransition(transition);
        setContentView(R.layout.activity_one_animation_transition);
        button = findViewById(R.id.but1);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(OneAnimationTransitionActivity.this,TwoAnimatorTransitionActivity.class), ActivityOptionsCompat.makeSceneTransitionAnimation(OneAnimationTransitionActivity.this).toBundle());
                }
            });
        }
    }
    

    c、Shared Element Transition(过渡)

    需要在第一个activity的xml中定义:1、transitionName=”shareNames” 2、在第二个activity中xml的根布局transitionName=”shareNames” ,名字必须一样:

    (1)xml中的写法

    a、第一个activity中的Xml:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.explem.chaohaozhao.myviewpager.view.OneAnimationTransitionActivity">
    
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="activity1"/>
    
    <Button
        android:id="@+id/but1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:transitionName="shareNames"
        android:text="跳转"/>
    
    
    </RelativeLayout>
    

    b、第二个activity中的XML

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:weightSum="2"
    android:transitionName="shareNames"
    android:background="@drawable/ff"
    tools:context="com.explem.chaohaozhao.myviewpager.view.TwoAnimatorTransitionActivity">
    
    <RelativeLayout
        android:id="@+id/viewGroup"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">
    </RelativeLayout>
    <Button
        android:id="@+id/qiehuan"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="场景切换"/>
    
    </LinearLayout>
    

    (2)在activity中的跳转代码:

    public class OneAnimationTransitionActivity extends AppCompatActivity {
    
    Button button;
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_one_animation_transition);
        button = findViewById(R.id.but1);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
               startActivity(new Intent(OneAnimationTransitionActivity.this,TwoAnimatorTransitionActivity.class), ActivityOptionsCompat.makeSceneTransitionAnimation(OneAnimationTransitionActivity.this,button,"shareNames").toBundle());
    
            }
        });
        }
    }

    相关文章

      网友评论

          本文标题:三、Android 动画机制

          本文链接:https://www.haomeiwen.com/subject/enfznftx.html