Android 動(dòng)畫

視圖動(dòng)畫:

AlphaAnimation、RotateAnimation、TranslateAnimation、ScaleAnimation 和 動(dòng)畫集:AnimationSet

  • AlphaAnimation(透明度動(dòng)畫):
AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
alphaAnimation.setDuration(1000);
view.startAnimation(alphaAnimation);
  • RotateAnimation(旋轉(zhuǎn)動(dòng)畫):
RotateAnimation rotateAnimation = new RotateAnimation(0, 360, 
RotateAnimation.RELATIVE_TO_SELF, 0.5F, RotateAnimation.RELATIVE_TO_SELF, 0.5F);
rotateAnimation.setDuration(1000);
view.startAnimation(rotateAnimation);
  • TranslateAnimation(位移動(dòng)畫):
TranslateAnimation  translateAnimation = new TranslateAnimation(0, 200, 0, 0);
translateAnimation.setDuration(1000);
view.startAnimation(translateAnimation);
  • ScaleAnimation(縮放動(dòng)畫):
ScaleAnimation scaleAnimation = new ScaleAnimation(0, 1, 0, 1, 
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setDuration(1000);
view.startAnimation(scaleAnimation);
  • AnimationSet(動(dòng)畫集合):
AnimationSet animationSet = new AnimationSet(true);
        animationSet.setDuration(4000);
        animationSet.addAnimation(alphaAnimation);
        animationSet.addAnimation(rotateAnimation);
        animationSet.addAnimation(translateAnimation);
        animationSet.addAnimation(scaleAnimation);
        animationSet.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                Log.e(TAG, "onAnimationStart: 動(dòng)畫開始執(zhí)行的時(shí)候調(diào)用");
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                Log.e(TAG, "onAnimationEnd: 動(dòng)畫結(jié)束執(zhí)行的時(shí)候調(diào)用");
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
                Log.e(TAG, "onAnimationRepeat: 動(dòng)畫重復(fù)執(zhí)行的時(shí)候調(diào)用");
            }
        });
//啟動(dòng)動(dòng)畫
view.startAnimation(animationSet);

屬性動(dòng)畫

PropertyValuesHolder、Animator、ObjectAnimator 、ValueAnimator

  • ObjectAnimator :

ObjectAnimator 是屬性動(dòng)畫框架中最重要的實(shí)行類,創(chuàng)建一個(gè)ObjectAnimator只需要通過它的靜態(tài)工廠類直接返回一個(gè)ObjectAnimator對(duì)象.(通過ofxxx方法);
必須具備get 、set方法,不然ObjectAnimator就無法起效;

  • 1.translationX 和 translationY:控制view對(duì)象從布局容器的左下方坐標(biāo)偏移的位置;
  • 2.rotation 、rotationX 和 rotationY:控制view對(duì)象圍繞它的支點(diǎn)進(jìn)行2D和3D旋轉(zhuǎn);
  • 3.scaleX 和 scaleY: 控制view對(duì)象圍繞它的支點(diǎn)進(jìn)行2D縮放;
  • 4.pivotX 和 pivotY:這兩個(gè)屬性控制著View對(duì)象的支點(diǎn)位置, 圍繞這個(gè)支點(diǎn)進(jìn)行旋轉(zhuǎn)和縮放變換處理;
    默認(rèn)情況下,該支點(diǎn)的位置就是view的中心點(diǎn);
  • 5.alpha:它表示view對(duì)象的alpha透明度,默認(rèn)值是1(不透明) ,0代表完全透明(不可見);
    如果沒有g(shù)et set方法,那么可以自定義一個(gè)屬性或者包裝類,來間接地給這個(gè)屬性增加get set方法, 或者通過ValueAnimator來實(shí)現(xiàn);
  1. 自帶屬性:
ObjectAnimator  objectAnimator = ObjectAnimator.ofFloat(view, "translationX", 200);
objectAnimator.setDuration(1000);
objectAnimator.start();

 ObjectAnimator animatorColor = ObjectAnimator.ofInt(view,"BackgroundColor",0xffff0000,0xff00ff00);
animatorColor.setEvaluator(new ArgbEvaluator());
animatorColor.setDuration(1000);
animatorColor.start();
  1. 自定義屬性:
public class WrapperView {

    private View view;

    public WrapperView(View view) {
        this.view =view;
    }

    public int getWidth(){
        return view.getLayoutParams().width;
    }

    public void setWidth(int width) {
        view.getLayoutParams().width = width;
        view.requestLayout();
    }
}

WrapperView wrapperView = new WrapperView(tvWrapper);
ObjectAnimator objectAnimatorWrapper = ObjectAnimator.ofInt(wrapperView, "width", 100).setDuration(1000);
        objectAnimatorWrapper.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
                Log.e(TAG, "onAnimationStart: 動(dòng)畫開始執(zhí)行的時(shí)候調(diào)用");
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                //這個(gè)應(yīng)該是用得最多的吧
                Log.e(TAG, "onAnimationEnd: 動(dòng)畫結(jié)束執(zhí)行的時(shí)候調(diào)用");
            }

            @Override
            public void onAnimationCancel(Animator animation) {
                Log.e(TAG, "onAnimationEnd: 動(dòng)畫取消執(zhí)行的時(shí)候調(diào)用");
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
                Log.e(TAG, "onAnimationEnd: 動(dòng)畫重復(fù)執(zhí)行的時(shí)候調(diào)用");
            }
        });
objectAnimatorWrapper.start();

  • PropertyValuesHolder:

類似AnimationSet

  1. 動(dòng)畫合并:
PropertyValuesHolder valuesHolderTranslastion = PropertyValuesHolder.ofFloat("translationX", 100f);
PropertyValuesHolder valuesHolderScaleX = PropertyValuesHolder.ofFloat("scaleX", 1.0f, 0.3f);
PropertyValuesHolder valuesHolderScaleY = PropertyValuesHolder.ofFloat("scaleY", 1.0f, 0.3f);
PropertyValuesHolder valuesHolderColor = PropertyValuesHolder.ofInt("BackgroundColor", 0xff888888, 0xff00ff00);
ObjectAnimator objectAnimatorProper = ObjectAnimator.ofPropertyValuesHolder(tvObjProperty, valuesHolderTranslastion, valuesHolderScaleX, valuesHolderScaleY, valuesHolderColor);
objectAnimatorProper.setDuration(1000);
objectAnimatorProper.start();
  1. 動(dòng)畫拆分:
 // 在 0% 處開始向X移動(dòng)
Keyframe keyframe1 = Keyframe.ofFloat(0, 0);
// 時(shí)間經(jīng)過 50% 的時(shí)候,動(dòng)畫完成度 100%
Keyframe keyframe2 = Keyframe.ofFloat(0.5f, 100);
// 時(shí)間見過 100% 的時(shí)候,動(dòng)畫完成度倒退到 0%位置
Keyframe keyframe3 = Keyframe.ofFloat(1, 0);
PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("translationX", keyframe1, keyframe2, keyframe3);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(tvObjPropertyKey, holder);
animator.start();

  • ValueAnimator:

ValueAnimator 是 ObjectAnimator 的父類,ValueAnimator 就是一個(gè)不能指定目標(biāo)對(duì)象版本的 ObjectAnimator

ValueAnimator valueAnimator = ValueAnimator.ofFloat(0,1000);
        valueAnimator.setTarget(view);
        valueAnimator.setDuration(1000);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
              // TODO: 2018/10/24
                float value = (float) animation.getAnimatedValue();
                if (value==500f){
                    ScaleAnimation scaleAnimation = new ScaleAnimation(0, 1, 0, 1, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
                    scaleAnimation.setDuration(100);
                    view.startAnimation(scaleAnimation);
                }
            }
        });

  • Animator:

res/animator下創(chuàng)建布局文件,代碼加載xml布局文件

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:propertyName="scaleX"
    android:valueFrom="1.0"
    android:valueTo="2.0"
    android:valueType="floatType">
</objectAnimator>

Animator animatorXml = AnimatorInflater.loadAnimator(MainActivity.this,R.animator.animator_xml);
animatorXml.setTarget(view);
animatorXml.start();

AnimationUtils (工具類)

  • Android SDK 提供的工具類:
返回值 公共方法 描述
static long currentAnimationTimeMillis() 以毫秒返回當(dāng)前動(dòng)畫時(shí)間
static Animation loadAnimation(Context context, int id) 從資源加載動(dòng)畫對(duì)象
static Interpolator loadInterpolator(Context context, int id) 從資源中加載內(nèi)插器對(duì)象
static LayoutAnimationController loadLayoutAnimation(Context context, int id) 從資源加載動(dòng)畫對(duì)象(返回值不同)
static Animation makeInAnimation(Context c, boolean fromLeft) 用布爾參數(shù)決定滑入的方向是左側(cè)還是右側(cè)向上
static Animation makeInChildBottomAnimation(Context c) 視圖總是從屏幕的底部向上滑入
static Animation makeOutAnimation(Context c, boolean toRight) 用布爾參數(shù)決定滑入的方向是左側(cè)還是右側(cè)
animation = AnimationUtils.loadAnimation(this, R.anim.animation_utils);
view.startAnimation(animation);

ViewAnimationUtils (5.X的工具類)

createCircularReveal(View view, int centerX, int centerY, float startRadius, float endRadius)

  • centerX : 中心點(diǎn)X坐標(biāo);
  • centerY : 中心點(diǎn)Y坐標(biāo);
  • startRadius: 動(dòng)畫圓的起始半徑;
  • endRadius: 動(dòng)畫圓的結(jié)束半徑.
ViewAnimationUtils.createCircularReveal(ImageView, centerX, centerY, mImageView.getWidth(), 0);

Interpolator(插值器)

Interpolator 其實(shí)就是速度設(shè)置器。你在參數(shù)里填入不同的 Interpolator ,動(dòng)畫就會(huì)以不同的速度模型來執(zhí)行;Google TimeInterpolator

  • AccelerateDecelerateInterpolator:

先加速再減速。這是默認(rèn)的 Interpolator;

  • LinearInterpolator:

勻速;

  • AccelerateInterpolator:

持續(xù)加速;

  • DecelerateInterpolator:

以最高速開始,持續(xù)減速直到停止;

  • AnticipateInterpolator:

先回退一下段,然后再正常運(yùn)動(dòng);

  • OvershootInterpolator:

到終點(diǎn)的時(shí)候超出一下段,然后彈回來;

  • AnticipateOvershootInterpolator:

開始前回拉,最后超過一些然后回彈;

  • BounceInterpolator:

到達(dá)終點(diǎn)的時(shí)候彈回來兩下,然后回到終點(diǎn);

  • CycleInterpolator:

這個(gè)也是一個(gè)正弦 / 余弦曲線,不過它和 AccelerateDecelerateInterpolator 的區(qū)別是,它可以自定義曲線的周期,所以動(dòng)畫可以不到終點(diǎn)就結(jié)束,也可以到達(dá)終點(diǎn)后回彈,回彈的次數(shù)由曲線的周期決定,曲線的周期由 CycleInterpolator() 構(gòu)造方法的參數(shù)決定。

  • PathInterpolator:

自定義動(dòng)畫完成度 / 時(shí)間完成度曲線。
用這個(gè) Interpolator 你可以定制出任何你想要的速度模型。定制的方式是使用一個(gè) Path 對(duì)象來繪制出你要的動(dòng)畫完成度 / 時(shí)間完成度曲線

  • FastOutLinearInInterpolator(5.0以上):

貝塞爾曲線的持續(xù)加速的運(yùn)動(dòng)路線,AccelerateInterpolator比FastOutLinearInInterpolator斜率要低一點(diǎn);

  • FastOutSlowInInterpolator(5.0以上):

貝塞爾曲線,前期加速度要快得多;

  • LinearOutSlowInInterpolator(5.0以上):

減速曲線,初始速度更高;


SVG(矢量動(dòng)畫)

  • Android 5.X增加了對(duì)SVG矢量圖的支持(VectorDrawable,AnimatedVectorDrawable):
    <path>標(biāo)簽支持的指令:
  • M: 移動(dòng) moveTo;
  • L: 直線;
  • H: 水平線;
  • V: 垂直線;
  • C: 三次貝塞爾曲線;
  • S: 三次貝塞爾曲線;
  • Q: 二次貝塞爾曲線;
  • T: 映射前面路徑后的終點(diǎn);
  • Z: 關(guān)閉路徑;
  • A: 弧線;
  • RX,RY表示橢圓半圓的半軸大小;
  • XROTATION表示X軸與水平方向的順時(shí)針方向的夾角;
  • FLAG1有兩個(gè)值:1.表示大角度的弧線,0.表示小角度弧線;
  • FLAG2有兩個(gè)值,確定從起點(diǎn)至終點(diǎn)的方向:1.表示順時(shí)針,0.表示逆時(shí)針;
  • X,Y軸為終點(diǎn)坐標(biāo);

1.大小寫效果一樣,2.坐標(biāo)軸和canvas一樣左上角(0,0),3.指令和數(shù)據(jù)間的空格可以省略,4.同個(gè)指令出現(xiàn)多個(gè)時(shí)候可以只用一個(gè)。

   defaultConfig {
        //配置信息
        vectorDrawables.useSupportLibrary = true
    }
<!--res/drawable下新建-->
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:height="100dp"
    android:width="100dp"
    android:viewportWidth="100"
    android:viewportHeight="100">
    <group>
        <path
            android:name="path1"
            android:strokeColor="@color/colorPrimaryDark"
            android:strokeWidth="5"
            android:strokeLineCap="round"
            android:pathData="M 20,80 L 50,80 80,80"/>
    </group>

    <group>
        <path
            android:name="path2"
            android:strokeColor="@color/colorPrimaryDark"
            android:strokeWidth="5"
            android:strokeLineCap="round"
            android:pathData="M 20,20 L 50,20 80,20"/>
    </group>
</vector>


<!--res/animator下新建-->
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:propertyName="pathData"
    android:valueFrom="M 20,80 L 50,80 80,80"
    android:valueTo="M 20,80 L 50,50 80,80"
    android:valueType="pathType"
    android:interpolator="@android:anim/bounce_interpolator">
</objectAnimator>

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:propertyName="pathData"
    android:valueFrom="M 20,20 L 50,20 80,20"
    android:valueTo="M 20,20 L 50,50 80,20"
    android:valueType="pathType"
    android:interpolator="@android:anim/bounce_interpolator">

</objectAnimator>

<!--res/drawble-v21下新建-->
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/svg_line">

    <target
        android:name="path1"
        android:animation="@animator/animator_svg_path1"/>

    <target
        android:name="path2"
        android:animation="@animator/animator_svg_path2"/>
</animated-vector>

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    Drawable drawable = imageViewSVG.getDrawable();
                    if (drawable instanceof Animatable){
                        ((Animatable) drawable).start();
                    }
                }

SVG編輯器鏈接
本項(xiàng)目的簡單Demo地址


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 【Android 動(dòng)畫】 動(dòng)畫分類補(bǔ)間動(dòng)畫(Tween動(dòng)畫)幀動(dòng)畫(Frame 動(dòng)畫)屬性動(dòng)畫(Property ...
    Rtia閱讀 6,372評(píng)論 1 38
  • 動(dòng)畫基礎(chǔ)概念 動(dòng)畫分類 Android 中動(dòng)畫分為兩種,一種是 Tween 動(dòng)畫、還有一種是 Frame 動(dòng)畫。 ...
    Rtia閱讀 1,353評(píng)論 0 6
  • Animation Animation類是所有動(dòng)畫(scale、alpha、translate、rotate)的基...
    四月一號(hào)閱讀 2,022評(píng)論 0 10
  • 目前我的工作是法語導(dǎo)游,接待法語國家的游客來我國游玩。我的法語是自學(xué)的,所以想和對(duì)法語有興趣的同學(xué)分享一下。 1....
    心的新旅行閱讀 463評(píng)論 7 1
  • 獨(dú)立思考的能力,我想這是我目前最欠缺的吧。人的惰性作祟,很多時(shí)候都奉行拿來主義。遇到問題不會(huì),沒有通過自己的思考,...
    黑賽矩陣閱讀 189評(píng)論 2 1

友情鏈接更多精彩內(nèi)容