android中的動畫完全總結
這裡會講到的動畫有檢視動畫(幀動畫,補間動畫),屬性動畫,activity和fragment切換時的動畫,viewgroup新增和移除子view時的動畫,android隨後新的系統api的transition,Scene實現過渡效果,內容還是很多的。下面一一來說。
在Android動畫中,總共有兩種型別的動畫View Animation(檢視動畫)和Property Animator(屬性動畫);其中
View Animation包括Tween Animation(補間動畫)和Frame Animation(逐幀動畫);
Property Animator包括ValueAnimator和ObjectAnimation;
1.幀動畫:
2.補間動畫:有xml定義或者java檔案定義都可以<span style="font-size:14px;"> /** * 幀動畫就是搞幾個圖片讓他輪播 * 在res/drawable下定義xml檔案 * <?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="true"> <item android:drawable="@drawable/iv1" android:duration="150"> </item> <item android:drawable="@drawable/iv2" android:duration="150"> </item> <item android:drawable="@drawable/iv3" android:duration="150"> </item> </animation-list> 將xml作為imageview的背景圖片 程式碼中呼叫 imageview.getbackground強轉為AnimationDrawable 呼叫start.. 呼叫stop */</span>
xml中定義:
<span style="font-size:14px;"> * Android的animation由四種類型組成:alpha、scale、translate、rotate * 還有個動畫集合set可以把以上動畫放在一起同時執行 * 可以用xml檔案定義res/anim資料夾下 * * 1.scale標籤是縮放動畫,可以實現動態調控制元件尺寸的效果,有下面幾個屬性: android:fromXScale 起始的X方向上相對自身的縮放比例,浮點值,比如1.0代表自身無變化,0.5代表起始時縮小一倍,2.0代表放大一倍; android:toXScale 結尾的X方向上相對自身的縮放比例,浮點值; android:fromYScale 起始的Y方向上相對自身的縮放比例,浮點值, android:toYScale 結尾的Y方向上相對自身的縮放比例,浮點值; android:pivotX 縮放起點X軸座標,可以是數值、百分數、百分數p 三種樣式,比如 50、50%、50%p,當為數值時,表示在當前View的左上角,即原點處加上50px,做為起始縮放點;如果是50%,表示在當前控制元件的左上角加上自己寬度的50%做為起始點;如果是50%p,那麼就是表示在當前的左上角加上父控制元件寬度的50%做為起始點x軸座標。(具體意義,後面會舉例演示) android:pivotY 縮放起點Y軸座標,取值及意義跟android:pivotX一樣。 * * * android:fillAfter 如果設定為true,控制元件動畫結束時,將保持動畫最後時的狀態 * android:fillBefore 如果設定為true,控制元件動畫結束時,還原到開始動畫前的狀態 *android:repeatCount 重複次數 android:repeatMode 重複型別,有reverse和restart兩個值,reverse表示倒序回放,restart表示重新放一遍,必須與repeatCount一起使用才能看到效果。因為這裡的意義是重複的型別,即回放時的動作。 android:interpolator 設定插值器,其實就是指定的動作效果,比如彈跳效果等,不在這小節中講解,後面會單獨列出一單講解。 * * * 2. * alpha標籤——調節透明度 1、自身屬性 android:fromAlpha 動畫開始的透明度,從0.0 --1.0 ,0.0表示全透明,1.0表示完全不透明 android:toAlpha 動畫結束時的透明度,也是從0.0 --1.0 ,0.0表示全透明,1.0表示完全不透明 3.Rotate android:fromDegrees 開始旋轉的角度位置,正值代表順時針方向度數,負值程式碼逆時針方向度數 android:toDegrees 結束時旋轉到的角度位置,正值代表順時針方向度數,負值程式碼逆時針方向度數 android:pivotX 縮放起點X軸座標,可以是數值、百分數、百分數p 三種樣式,比如 50、50%、50%p,具體意義已在scale標籤中講述,這裡就不再重講 android:pivotY 縮放起點Y軸座標,可以是數值、百分數、百分數p 三種樣式,比如 50、50%、50%p 4.translate標籤所具有的屬性為: android:fromXDelta 起始點X軸座標,可以是數值、百分數、百分數p 三種樣式,比如 50、50%、50%p,具體意義已在scale標籤中講述,這裡就不再重講 android:fromYDelta 起始點Y軸從標,可以是數值、百分數、百分數p 三種樣式; android:toXDelta 結束點X軸座標 android:toYDelta 結束點Y軸座標 * */</span>
除了上面4個外,還有一個AnimationSet,是可以將上面動畫組合在一起的。
xml中定義後,使用下面的程式碼應用動畫,
<span style="font-size:14px;"> public static void start(View view){
// AnimationSet set = new AnimationSet(true);
// set.addAnimation(AnimationUtils.loadAnimation(this, R.anim.scale_anim));
// set.addAnimation(AnimationUtils.loadAnimation(this, R.anim.alpha_anim));
// set.addAnimation(AnimationUtils.loadAnimation(this, R.anim.rotate_anim));
//
// set.setAnimationListener(new AnimationListener() {
// @Override
// public void onAnimationStart(Animation animation) {
// }
//
// @Override
// public void onAnimationRepeat(Animation animation) {
// }
//
// @Override
// public void onAnimationEnd(Animation animation) {
// view.startAnimation(AnimationUtils.loadAnimation(MainActivity.this, R.anim.translate_anim));
// }
// });
// view.startAnimation(set);
view.startAnimation(AnimationUtils.loadAnimation(view.getContext(), R.anim.set_anim));
}</span>
<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<alpha
android:duration="2500"
android:fromAlpha="0"
android:toAlpha="1" />
</set></span>
<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<set>
<rotate
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2500"
android:fillAfter="true"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="360" >
</rotate>
</set></span>
<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXScale="0"
android:toXScale="1"
android:fromYScale="0"
android:toYScale="1"
android:pivotX="67%p"
android:pivotY="67%p"
android:duration="2500" />
</set></span>
<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2500"
android:fillAfter="true"
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="67%p"
android:toYDelta="67%p" >
</translate>
</set></span>
<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<rotate
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2500"
android:fillAfter="true"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="360" >
</rotate>
<alpha
android:duration="2500"
android:fromAlpha="0"
android:toAlpha="1" />
<scale
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2500"
android:fromXScale="0"
android:fromYScale="0"
android:pivotX="67%p"
android:pivotY="67%p"
android:toXScale="1"
android:toYScale="1" />
<translate
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2500"
android:fromXDelta="0"
android:fromYDelta="0"
android:startOffset="2500"
android:toXDelta="67%p"
android:toYDelta="67%p" >
</translate>
</set></span>
<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000" >
<translate
android:fromXDelta="-50%p"
android:toXDelta="0" />
<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0" />
</set></span>
java程式碼建立補間動畫,
只是根據xml中定義的,翻譯成java程式碼就可以了。
如xml中定義了,
<span style="font-size:14px;"> /**
* 程式碼生成animation。xml檔案對應的Java類
* TranslateAnimation
RotateAnimation
ScaleAnimation
AlphaAnimation
我們可以根據xml中的屬性翻譯過來就行了
*/
//例如這個:
/**
* <?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<rotate
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2500"
android:fillAfter="true"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="360" >
</rotate>
<alpha
android:duration="2500"
android:fromAlpha="0"
android:toAlpha="1" />
<scale
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2500"
android:fromXScale="0"
android:fromYScale="0"
android:pivotX="67%p"
android:pivotY="67%p"
android:toXScale="1"
android:toYScale="1" />
<translate
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2500"
android:fromXDelta="0"
android:fromYDelta="0"
android:startOffset="2500"
android:toXDelta="67%p"
android:toYDelta="67%p" >
</translate>
</set>
*/</span>
那麼如果我們用java程式碼來生成的話就是這樣的:
<span style="font-size:14px;"> public static void start(View view){
RotateAnimation rotateAnimation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setFillAfter(true);
rotateAnimation.setDuration(2500);
AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
alphaAnimation.setDuration(2500);
ScaleAnimation scaleAnimation = new ScaleAnimation(0, 1, 0, 1, Animation.RELATIVE_TO_PARENT,0.67f, Animation.RELATIVE_TO_PARENT, 0.67f);
scaleAnimation.setDuration(2500);
TranslateAnimation translateAnimation = new TranslateAnimation( Animation.RELATIVE_TO_PARENT, 0, Animation.RELATIVE_TO_PARENT, 0.67f, Animation.RELATIVE_TO_PARENT, 0, Animation.RELATIVE_TO_PARENT, 0.67f);
translateAnimation.setStartOffset(2500);
translateAnimation.setDuration(2500);
AnimationSet set = new AnimationSet(true);
set.addAnimation(rotateAnimation);
set.addAnimation(alphaAnimation);
set.addAnimation(scaleAnimation);
set.addAnimation(translateAnimation);
view.startAnimation(set);
}</span>
上面的程式碼還是很簡單的,想想如果位置從A平移到B,是應該以什麼樣的速率來移動呢,預設的是勻速了,所有你也可以指定或者自定義動畫過程中要用到的插值器,Interpolator插值器,用來定義動畫執行過程中的具體行為,變化速率。插值器也可以用在屬性動畫上。
/**
*Interpolator插值器,用來定義動畫執行過程中的具體行為,變化速率
*
*已經定義好了的插值器有這些
*AccelerateDecelerateInterpolator 在動畫開始與介紹的地方速率改變比較慢,在中間的時候加速
AccelerateInterpolator 在動畫開始的地方速率改變比較慢,然後開始加速
AnticipateInterpolator 開始的時候向後然後向前甩
AnticipateOvershootInterpolator 開始的時候向後然後向前甩一定值後返回最後的值
BounceInterpolator 動畫結束的時候彈起
CycleInterpolator 動畫迴圈播放特定的次數,速率改變沿著正弦曲線
DecelerateInterpolator 在動畫開始的地方快然後慢
LinearInterpolator 以常量速率改變
OvershootInterpolator 向前甩一定值後再回到原來位置
*/
應用插值器, public static void useSystemInterpolator(View view,Interpolator i){
AnimationSet set = new AnimationSet(true);
set.addAnimation(AnimationUtils.loadAnimation(view.getContext(), R.anim.scale_anim));
set.setInterpolator(i);
view.startAnimation(set);
}
3.屬性動畫,也可以用xml或者java定義。
涉及到2個類
ValueAnimator,這個本身不能對view造成動畫效果,它是根據指定屬性的起始值,可選指定插值器,新增監聽動畫回撥變化過程中的返回值,根據返回值來動態改變view的屬性值。
ObjectAnimator,物件動畫,直接作用於view
/** * 補間動畫雖能對控制元件做動畫,但並沒有改變控制元件內部的屬性值。 比如平移後,雖然外觀上位置看像移動了,其實是沒有移動 * * 屬性動畫,ValueAnimator; 它本身不會對任何view做操作,需要我們監聽它的值變化, * 在變化中自己改變view的值,從而實現動畫.至於這個區間的值變化是怎樣的,我們可以自己去 * 設定它的animator.setInterpolator(new BounceInterpolator()); * * 而和它的子類ObjectAnimator關聯了我們要動畫的物件,這樣子我們就不需要 * 每次監聽變化了 */
xml定義,
/**
* xml檔案中定義屬性動畫
* 標籤對應;
* <value_animator />:對應ValueAnimator
<objectAnimator />:對應ObjectAnimator
<set />:對應AnimatorSet
*
* <value_animator
android:duration="int"
android:valueFrom="float | int | color"
android:valueTo="float | int | color"
android:startOffset="int"
android:repeatCount="int"
android:repeatMode=["repeat" | "reverse"]
android:valueType=["intType" | "floatType"]
android:interpolator=["@android:interpolator/XXX"]/>
*/
public static void loadXmlAnimator(final View view){
// ValueAnimator valueAnimator = (ValueAnimator) AnimatorInflater.loadAnimator(view.getContext(), R.animator.value_animator);
// valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
// @Override
// public void onAnimationUpdate(ValueAnimator animation) {
// int offset = (int)animation.getAnimatedValue();
// view.layout( offset,offset,view.getWidth()+offset,view.getHeight() + offset);
// }
// });
// valueAnimator.start();
// ObjectAnimator objectAnimator = (ObjectAnimator) AnimatorInflater.loadAnimator(view.getContext(), R.animator.object_animator);
// objectAnimator.setTarget(view);
// objectAnimator.start();
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(view.getContext(), R.animator.set_animator);
set.setTarget(view);
set.start();
}
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="TranslationY"
android:duration="2000"
android:valueFrom="0.0"
android:valueTo="400.0"
android:interpolator="@android:anim/accelerate_interpolator"
android:valueType="floatType"
android:repeatCount="1"
android:repeatMode="reverse"
android:startOffset="2000"/>
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="rotation"
android:repeatCount="1"
android:valueFrom="0"
android:valueTo="360"
android:valueType="floatType" >
</objectAnimator>
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="together">
<objectAnimator
android:propertyName="x"
android:duration="2500"
android:valueFrom="0"
android:valueTo="400"
android:valueType="floatType"/>
<objectAnimator
android:propertyName="y"
android:duration="2500"
android:valueFrom="0"
android:valueTo="300"
android:valueType="floatType"/>
</set>
<?xml version="1.0" encoding="utf-8"?>
<animator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:interpolator="@android:anim/bounce_interpolator"
android:startOffset="2000"
android:valueFrom="0"
android:valueTo="300"
android:valueType="intType" />
java中定義,
package com.example.customeviewserial.property_animation;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorInflater;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.BounceInterpolator;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import com.example.customeviewserial.R;
/**
* GroupFlexBoll提供一個例子說明用java程式碼建立屬性動畫
*關鍵程式碼startTranslate()方法
* */
public class GroupFlexBoll extends RelativeLayout {
private static final int[] BTN_RES = { R.drawable.home,
R.drawable.iv1, R.drawable.iv2,
R.drawable.iv3 };
private static final int SWAP_ANGLE = 90;
private static final int BOLLNUM = 3;
private static final float SPACE_ANGLE = SWAP_ANGLE / (BOLLNUM - 1);
RelativeLayout.LayoutParams params;
private int radius;
private ImageView homeImageView;
private ImageView iv1;
private ImageView iv2;
private ImageView iv3;
public GroupFlexBoll(Context context, AttributeSet attrs) {
super(context, attrs);
addView(context);
}
private void addView(Context context) {
homeImageView = new ImageView(context);
homeImageView.setTag("home");
params = new RelativeLayout.LayoutParams(40, 40);
params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
homeImageView.setImageResource(BTN_RES[0]);
addView(homeImageView, params);
iv1 = new ImageView(context);
iv1.setImageResource(BTN_RES[1]);
iv1.setTag("iv1");
addView(iv1, params);
iv2 = new ImageView(context);
iv2.setImageResource(BTN_RES[2]);
iv2.setTag("iv2");
addView(iv2, params);
iv3 = new ImageView(context);
iv3.setImageResource(BTN_RES[3]);
iv3.setTag("iv3");
addView(iv3, params);
setSubBtnVisible(false);
}
public void setOperationListener(OnClickListener l) {
homeImageView.setOnClickListener(l);
iv1.setOnClickListener(l);
iv2.setOnClickListener(l);
iv3.setOnClickListener(l);
}
private void setSubBtnVisible(boolean isVisible) {
if (isVisible) {
iv1.setVisibility(View.VISIBLE);
iv2.setVisibility(View.VISIBLE);
iv3.setVisibility(View.VISIBLE);
} else {
iv1.setVisibility(View.GONE);
iv2.setVisibility(View.GONE);
iv3.setVisibility(View.GONE);
}
}
private void setSubBtnEnable(boolean isEnabled){
if(isEnabled){
iv1.setEnabled(true);
iv2.setEnabled(true);
iv3.setEnabled(true);
}else{
iv1.setEnabled(false);
iv2.setEnabled(false);
iv3.setEnabled(false);
}
}
private boolean isOpend = false;
private int boll_radius;
public void toggle() {
isOpend = !isOpend;
doAnimation();
}
private void doAnimation() {
setSubBtnVisible(true);
startTranslate();
}
private void startTranslate() {
int willTranslateLen = boll_radius * 2 * 3;
ObjectAnimator animator1Y, animator2Y, animator3Y, animator1X, animator2X, animator3X;
if (isOpend) {
animator1Y = ObjectAnimator.ofFloat(iv1, "translationY", 0,
-willTranslateLen);
animator2Y = ObjectAnimator.ofFloat(iv2, "translationY", 0,
(float) (-willTranslateLen * Math.cos(Math.toRadians(45))));
animator3Y = ObjectAnimator.ofFloat(iv3, "translationY", 0, 0);
animator1X = ObjectAnimator.ofFloat(iv1, "translationX", 0, 0);
animator2X = ObjectAnimator.ofFloat(iv2, "translationX", 0,
(float) (-willTranslateLen * Math.sin(Math.toRadians(45))));
animator3X = ObjectAnimator.ofFloat(iv3, "translationX", 0,
(float) (-willTranslateLen * Math.sin(Math.toRadians(90))));
} else {
animator1Y = ObjectAnimator.ofFloat(iv1, "translationY",
-willTranslateLen, 0);
animator2Y = ObjectAnimator.ofFloat(iv2, "translationY",
(float) (-willTranslateLen * Math.cos(Math.toRadians(45))),
0);
animator3Y = ObjectAnimator.ofFloat(iv3, "translationY", 0, 0);
animator1X = ObjectAnimator.ofFloat(iv1, "translationX", 0, 0);
animator2X = ObjectAnimator.ofFloat(iv2, "translationX",
(float) (-willTranslateLen * Math.sin(Math.toRadians(45))),
0);
animator3X = ObjectAnimator.ofFloat(iv3, "translationX",
(float) (-willTranslateLen * Math.sin(Math.toRadians(90))),
0);
}
Animator rotateAnimator1 = AnimatorInflater.loadAnimator(getContext(), R.animator.rotate);
Animator rotateAnimator2 = AnimatorInflater.loadAnimator(getContext(), R.animator.rotate);
Animator rotateAnimator3 = AnimatorInflater.loadAnimator(getContext(), R.animator.rotate);
rotateAnimator1.setTarget(iv1);
rotateAnimator2.setTarget(iv2);
rotateAnimator3.setTarget(iv3);
rotateAnimator1.setDuration(100);
rotateAnimator2.setDuration(100);
rotateAnimator3.setDuration(100);
AnimatorSet set = new AnimatorSet();
set.addListener(new AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
homeImageView.setEnabled(false);
setSubBtnEnable(false);
}
@Override
public void onAnimationRepeat(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
if (isOpend == false) {
setSubBtnVisible(false);
}else{
setSubBtnEnable(true);
}
homeImageView.setEnabled(true);
}
@Override
public void onAnimationCancel(Animator animation) {
}
});
set.playTogether(animator1Y, animator2Y, animator3Y, animator1X,
animator2X, animator3X,rotateAnimator1,rotateAnimator2,rotateAnimator3);
set.setDuration(1500);
if(isOpend){
set.setInterpolator(new BounceInterpolator());
}else{
set.setInterpolator(new AccelerateInterpolator());
}
set.start();
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (changed) {
int measuredWidth = getMeasuredWidth();
int measuredHeight = getMeasuredHeight();
radius = Math.min(measuredWidth, measuredHeight);
measureBtnSize();
}
}
private void measureBtnSize() {
params.width = radius / 4;
params.height = radius / 4;
boll_radius = radius / 8;
homeImageView.setLayoutParams(params);
iv1.setLayoutParams(params);
iv2.setLayoutParams(params);
iv3.setLayoutParams(params);
}
}
控制動畫順序,
package com.example.customeviewserial.set_order_animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.view.View;
/**
* Created by Administrator on 2016/5/24 0024.
*/
public class GuideUser {
/**
* AnimatorSet實現的屬性動畫集合,
* 控制各個動畫的執行順序
* playSequentially,playTogether
*/
public static void startAnimatorSet(View... view){
ObjectAnimator tv1BgAnimator = ObjectAnimator.ofInt(view[0], "BackgroundColor", 0xffff00ff, 0xffffff00, 0xffff00ff);
ObjectAnimator tv1TranslateY = ObjectAnimator.ofFloat(view[1], "translationY", 0, 300, 0);
ObjectAnimator tv2TranslateY = ObjectAnimator.ofFloat(view[2], "translationY", 0, 400, 0);
AnimatorSet animatorSet = new AnimatorSet();
// animatorSet.playSequentially(tv1BgAnimator,tv1TranslateY,tv2TranslateY);
animatorSet.playTogether(tv1BgAnimator,tv1TranslateY,tv2TranslateY);
//自由設定動畫順序——AnimatorSet.Builder
AnimatorSet.Builder builder = animatorSet.play(tv1BgAnimator);
/**
* //和前面動畫一起執行
public Builder with(Animator anim)
//執行先執行這個動畫再執行前面動畫
public Builder before(Animator anim)
//執行前面的動畫後才執行該動畫
public Builder after(Animator anim)
//延遲n毫秒之後執行動畫
public Builder after(long delay)
*/
//AnimatorSet沒有統一設定的情況下,各自按各自的來。這裡統一設定了時間,會覆蓋各自的時間
animatorSet.setDuration(1000);
animatorSet.start();
}
}
4.viewgroup初始化,viewgroup中新增和移除子view時新增動畫;
涉及到LayoutTransition和之前提到的屬性動畫;
/**
* 普通viewGroup新增進入統一動畫的LayoutAnimation
* 和針對grideView新增進入動畫的gridLayoutAnimation; 這2個類只能保證在建立的時候有動畫。
*
* android:animateLayoutChanges==true可以為任何viewgroup控制元件加上預設動畫
* 和LayoutTransition則可以來自定義動畫
*
* 1.可以在xml檔案中指定
* 在anim資料夾中定義<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:animation="@anim/slide_in_left"
android:animationOrder="normal"
android:delay="1" />
delay值是animation時間值的倍數
animation引用的只能是animation動畫,不能是animator
定義好後,在layout中引用 android:layoutAnimation="@anim/layout_animation"
動畫只在第一次建立容器的時候有動畫
android:animationOrder指viewGroup中的控制元件動畫開始順序,取值有normal(正序)、reverse(倒序)、random(隨機)
2.可以在Java檔案中指定
//程式碼設定通過載入XML動畫設定檔案來建立一個Animation物件;
Animation animation= AnimationUtils.loadAnimation(this,R.anim.slide_in_left); //得到一個LayoutAnimationController物件;
LayoutAnimationController controller = new LayoutAnimationController(animation); //設定控制元件顯示的順序;
controller.setOrder(LayoutAnimationController.ORDER_REVERSE); //設定控制元件顯示間隔時間;
controller.setDelay(0.3f); //為ListView設定LayoutAnimationController屬性;
mListView.setLayoutAnimation(controller);
mListView.startLayoutAnimation();
對應的GridView:
Animation animation = AnimationUtils.loadAnimation(MyActivity.this,R.anim.slide_in_left);
GridLayoutAnimationController controller = new GridLayoutAnimationController(animation);
controller.setColumnDelay(0.75f);
controller.setRowDelay(0.5f);
controller.setDirection(GridLayoutAnimationController.DIRECTION_BOTTOM_TO_TOP|GridLayoutAnimationController.DIRECTION_LEFT_TO_RIGHT);
controller.setDirectionPriority(GridLayoutAnimationController.PRIORITY_NONE);
grid.setLayoutAnimation(controller);
grid.startLayoutAnimation();
3.LayoutTransition則可以來為viewgroup自定義新增屬性動畫
LayoutTransaction transitioner = new LayoutTransition();
ObjectAnimator animOut = ObjectAnimator.ofFloat(null, "rotation", 0f, 90f, 0f);
transitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);
linearLayout.setLayoutTransition(mTransitioner);
第一個引數int transitionType:表示當前應用動畫的物件範圍,取值有:
APPEARING —— 元素在容器中出現時所定義的動畫。
DISAPPEARING —— 元素在容器中消失時所定義的動畫。
CHANGE_APPEARING —— 由於容器中要顯現一個新的元素,其它需要變化的元素所應用的動畫
CHANGE_DISAPPEARING —— 當容器中某個元素消失,其它需要變化的元素所應用的動畫
*/
/**
* 測試LayoutTransition效果
* 這裡有幾點注意事項:
1、LayoutTransition.CHANGE_APPEARING和LayoutTransition.CHANGE_DISAPPEARING必須使用PropertyValuesHolder所構造的動畫才會有效果,不然無效!也就是說使用ObjectAnimator構造的動畫,在這裡是不會有效果的!
2、在構造PropertyValuesHolder動畫時,”left”、”top”屬性的變動是必寫的。如果不需要變動,則直接寫為:
PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,0);
PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",0,0);
3、在構造PropertyValuesHolder時,所使用的ofInt,ofFloat中的引數值,第一個值和最後一個值必須相同,不然此屬性所對應的的動畫將被放棄,在此屬性值上將不會有效果;
PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,100,0);
比如,這裡ofInt(“left”,0,100,0)第一個值和最後一個值都是0,所以這裡會有效果的,如果我們改為ofInt(“left”,0,100);那麼由於首尾值不一致,則將被視為無效引數,將不會有效果!
4、在構造PropertyValuesHolder時,所使用的ofInt,ofFloat中,如果所有引數值都相同,也將不會有動畫效果。
比如
*/
下面是一個具體例子,
/**
*為viewgroup應用LayoutTransition動畫
*/
private void useLayoutTransition() {
LayoutTransition layoutTransition = new LayoutTransition();
boolean checked = radio_appear.isChecked();
boolean checked2 = radio_disappear.isChecked();
boolean checked3 = radio_change_appear.isChecked();
boolean checked4 = radio_change_disappear.isChecked();
if (checked || checked2 || checked3 || checked4) {
} else {
return;
}
if (checked) { // 自身動畫新增
ObjectAnimator appearAnimator = ObjectAnimator.ofFloat(null,
"alpha", 0, 1);
layoutTransition.setAnimator(LayoutTransition.APPEARING,
appearAnimator);
}
if (checked2) { // 自身移除動畫
ObjectAnimator disappearAnimator = ObjectAnimator.ofFloat(null,
"alpha", 1, 0);
layoutTransition.setAnimator(LayoutTransition.DISAPPEARING,
disappearAnimator);
}
if (checked3) { // 自身新增時對其他控制元件應用的動畫
PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",
0, 100, 0);
PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top", 0,
0);
Animator changeAppearAnimator = ObjectAnimator
.ofPropertyValuesHolder(layout, pvhLeft, pvhTop);
layoutTransition.setAnimator(LayoutTransition.CHANGE_APPEARING,
changeAppearAnimator);
}
if (checked4) { // 自身移除時對其他控制元件應用的動畫
PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",
0, 0);
PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top", 0,
0);
PropertyValuesHolder pvhRotateX = PropertyValuesHolder.ofFloat(
"rotationX", 0,180, 0);
Animator changeDisAppearAnimator = ObjectAnimator
.ofPropertyValuesHolder(layout, pvhLeft, pvhTop,
pvhRotateX);
layoutTransition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING,
changeDisAppearAnimator);
}
layoutTransition.setDuration(1000);
// layoutTransition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 500);
layoutTransition.setStagger(LayoutTransition.CHANGE_DISAPPEARING, 100);
layoutTransition.setStagger(LayoutTransition.CHANGE_APPEARING, 100);//其他條目動畫時的間隔
layout.setLayoutTransition(layoutTransition);
}
5.在activity和fragment進入和退出時運用動畫。這些動畫都是對activity或者fragment整體的所有佈局元素統一進行相同的動畫。
activity的進入和退出的動畫,我們可以使用程式碼中應用:
在startActivity或者finish之後呼叫overridePendingTransition(int enterAnim,int exitAnim);
這裡的動畫id是xml中定義的檢視動畫,enterAnim是進入的那個activity的動畫,exitAnim是退出的那個activity的動畫。
還有一種方法是使用主題的方式為application或者activity指定主題,例如,
定義主題:
<style name="FeelyouWindowAnimTheme" parent="@android:style/Animation.Activity">
<item name="android:activityOpenEnterAnimation">@anim/in_from_left</item>
<item name="android:activityOpenExitAnimation">@anim/out_from_right</item>
<item name="android:activityCloseEnterAnimation">@anim/in_from_right</item>
<item name="android:activityCloseExitAnimation">@anim/out_from_left</item>
</style>
<style name="AnimActivityTheme">
<item name="android:windowAnimationStyle">@style/FeelyouWindowAnimTheme</item>
</style>
res/anim/下定義一些檢視動畫:
in_from_left.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="250"
android:fromXDelta="100%p"
android:toXDelta="0" />
</set>
in_from_right.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="250"
android:fromXDelta="-100%p"
android:toXDelta="0" />
</set>
out_from_left.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="250"
android:fromXDelta="0"
android:toXDelta="100%p" />
</set>
out_from_right.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="250"
android:fromXDelta="0"
android:toXDelta="-100%p" />
</set>
應用主題:
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AnimActivityTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".Main2Activity"></activity>
</application>
fragment的進入和退出動畫如下:
請使用v4包下的Fragment保證相容,在fragmentTransition提交之前應用動畫就行;
if (null == mFragmentManager) {
mFragmentManager = getSupportFragmentManager();
}
fragment = new BlankFragment();
FragmentTransaction fragmentTransaction = mFragmentManager
.beginTransaction();
fragmentTransaction.setCustomAnimations(
R.anim.in_from_left,
R.anim.out_from_right,
R.anim.in_from_right,
R.anim.out_from_left);
fragmentTransaction.add(R.id.container, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
6.android5.0為我們提供了一種針對activity或者fragment切換過渡時的新動畫,不像上面的過渡動畫是針對整個的佈局元素執行的是同一個動畫,android5.0的過渡動畫更加豐富,可以針對其中的共享某些元素執行動畫。可以根據原理自己寫效果了。
提供了三種Transition型別:
進入:一個進入的過渡(動畫)決定activity中的所有的檢視怎麼進入螢幕。
退出:一個退出的過渡(動畫)決定一個activity中的所有檢視怎麼退出螢幕。
共享元素:一個共享元素過渡(動畫)決定兩個activities之間的過渡,怎麼共享(它們)的檢視。
</pre><p><pre name="code" class="java"> Transition過渡可以在xml檔案中定義或者Java程式碼建立對應的類,例如在res/transition資料夾下定義它的節點可以是Transition的子類, ChangeBounds ChangeClipBounds ChangeImageTransform ChangeTransform TransitionSet Explode Fade Slide TransitionInflater提供將xml中定義的transition轉為transition物件 TransitionManager管理Scene和Transition TransitionDrawable實現drawable有過渡效果
changeBounds - 改變目標檢視的佈局邊界
changeClipBounds - 裁剪目標檢視邊界
changeTransform - 改變目標檢視的縮放比例和旋轉角度
changeImageTransform - 改變目標圖片的大小和縮放比例
過渡動畫的執行時機;並且傳入一個你想要執行的動畫
Window.setEnterTransition():設定進入動畫
Window.setExitTransition():設定退出效果
Window.setSharedElementEnterTransition():設定共享元素的進入動畫
Window.setSharedElementExitTransition():設定共享元素的退出動畫
具體使用:
/ /允許使用transitions
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
//設定一個transition
getWindow().setExitTransition(new Explode());//new Slide() new Fade() ;
//跳轉
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
為共享元素執行過渡動畫時,有點不同:
使用android:transitionName屬性給兩個佈局中的共享元素指定一個相同的名字(名字一定不要寫錯)
然後執行:startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this,view,"shareName").toBundle());
如果有多個共享元素使用:
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this,
Pair.create(view1, "agreedName1"),
Pair.create(view2, "agreedName2"));
退出要使用:在程式碼中觸發通過finishAfterTransition()方法觸發返回動畫,而不是呼叫finish()方法.
7.Scene的使用: api19開始才有的特性,Scene場景,常見使用方法, public Scene(ViewGroup sceneRoot, View layout) public static Scene getSceneForLayout(ViewGroup sceneRoot, int layoutId, Context context) Transition過渡,內部包含場景轉換時的動畫。可能對SurfaceView,TextureView不起作用。 工作原理是,捕捉兩個Scene的狀態,根據這2個狀態的區別建立屬性動畫Animator.實際上是對屬性動畫的一個應用,使用更簡單的api實現 了複雜的功能。 這些優點將使得我們只用少量程式碼就可以建立複雜的Activity和Fragment切換動畫使用步驟:
應用scene transition 場景轉換 1.建立transition 從xml中Transition mFadeTransition = TransitionInflater.from(this). inflateTransition(R.transition.fade_transition);從java中建立,Transition mFadeTransition = new Fade();2.使用TransitionManager.go(mEndingScene, mFadeTransition);
res/transition/fade_transition.xml
<?xml version="1.0" encoding="utf-8"?><fade xmlns:android="http://schemas.android.com/apk/res/android" />
例子:
package com.example.androidtest;
import android.annotation.TargetApi;
import android.app.Activity;
import android.graphics.drawable.TransitionDrawable;
import android.os.Build;
import android.os.Bundle;
import android.transition.AutoTransition;
import android.transition.Scene;
import android.transition.TransitionManager;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.ImageView;
import android.widget.RelativeLayout;
@TargetApi(Build.VERSION_CODES.KITKAT)
public class MainActivity extends Activity {
private AutoTransition transition;
private Scene scene1;
private Scene scene2;
private boolean start;
private ImageView iv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.start_layout);
iv = (ImageView)findViewById(R.id.iv);
// get the root layout ID
RelativeLayout rootLayout = (RelativeLayout) findViewById(R.id.base);
//場景的定義,首先根佈局要一樣且定義id;每個場景中具有相同id的視為同一個view實現過渡效果,不同的id則只是簡單的漸隱漸顯
scene1 = Scene.getSceneForLayout(rootLayout, R.layout.start_layout,this);
scene2 = Scene.getSceneForLayout(rootLayout, R.layout.end_layout, this);
// create transition, set properties
//程式碼建立過渡,也可以使用xml中定義過渡,再使用TransitionInflater.from(this).inflateTransition(resource)解析
transition = new AutoTransition();
transition.setDuration(2000);
transition.setInterpolator(new AccelerateDecelerateInterpolator());
// initialize flag
start = true;
}
/**
* 下面幾個效果需要api21
* ChangeBounds
ChangeClipBounds
ChangeImageTransform
ChangeTransform
TransitionSet
Explode
Fade
Slide
* @param v
*/
public void changeScene(View v) {
// check flag
if (start) {
TransitionManager.go(scene2, transition);
start = false;
} else {
TransitionManager.go(scene1, transition);
start = true;
}
//TransitionDrawable是針對圖片之間的過渡
TransitionDrawable drawable = (TransitionDrawable) iv.getBackground();
drawable.startTransition(2000);
}
}
start_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/base"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ff000000"
tools:context=".TransitionsActivity" >
<ImageView
android:id="@+id/iv"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerInParent="true"
android:background="@drawable/transitiondrawable" />
<ImageButton
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:background="#00000000"
android:contentDescription="shape"
android:onClick="changeScene"
android:src="@drawable/shape1" />
<ImageButton
android:id="@+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:background="#00000000"
android:contentDescription="shape"
android:onClick="changeScene"
android:src="@drawable/shape2" />
<ImageButton
android:id="@+id/btn3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:background="#00000000"
android:contentDescription="shape"
android:onClick="changeScene"
android:src="@drawable/shape3" />
<ImageButton
android:id="@+id/btn4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:background="#00000000"
android:contentDescription="shape"
android:onClick="changeScene"
android:src="@drawable/shape4" />
</RelativeLayout>
end_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ff000000"
android:id="@+id/base"
tools:context=".TransitionsActivity">
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn1"
android:src="@drawable/shape1"
android:background="#00000000"
android:contentDescription="shape"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:onClick="changeScene"/>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn2"
android:src="@drawable/shape2"
android:background="#00000000"
android:contentDescription="shape"
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true"
android:onClick="changeScene"/>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn3"
android:src="@drawable/shape3"
android:background="#00000000"
android:contentDescription="shape"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:onClick="changeScene"/>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn4"
android:src="@drawable/shape4"
android:background="#00000000"
android:contentDescription="shape"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:onClick="changeScene"/>
</RelativeLayout>
res/drawable/transitiondrawable.xml
<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:drawable="@drawable/shape1">
</item>
<item android:drawable="@drawable/shape2">
</item>
</transition>