三、Android 动画机制

2018-09-21  本文已影响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());

        }
    });
    }
}
上一篇下一篇

猜你喜欢

热点阅读