三、Android 动画机制
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.pnga、公共属性
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.pngb、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());
}
});
}
}