Android 動畫基礎(chǔ)知識學(xué)習(xí)(下)

學(xué)習(xí)資料:Android開發(fā)藝術(shù)探索Animation的api

1.屬性動畫

屬性動畫可以對任意對象的屬性進行動畫不僅僅是View岭埠,動畫默認時間間隔是300ms盏混,默認幀率是100ms/幀蔚鸥。

作用:在一個時間間隔內(nèi)完成對一個對象從屬性值到另一個屬性值的改變。

三個常用類:ValueAnimator,ObjectAnimator,AnimatorSet


屬性動畫

Java代碼

private void initView() {
        Button bt = (Button) findViewById(R.id.bt_object_animation_activity);
        ImageView iv = (ImageView) findViewById(R.id.iv_object_animation_activity);

        //改變背景屬性
        ValueAnimator colorAnim = ObjectAnimator.ofInt(iv, "backgroundColor", Color.parseColor("#FF4081"), Color.CYAN);
        colorAnim.setRepeatCount(2);
        colorAnim.setRepeatMode(ObjectAnimator.REVERSE);
        colorAnim.setDuration(1000);
        colorAnim.setEvaluator(new ArgbEvaluator());//估值器

        //動畫集合
        AnimatorSet set = new AnimatorSet();
        set.playTogether(
                ObjectAnimator.ofFloat(iv, "rotationX", 0, 360),//繞x軸旋轉(zhuǎn)360度
                ObjectAnimator.ofFloat(iv, "rotation", 0, -90),//逆時針旋轉(zhuǎn)90度
                ObjectAnimator.ofFloat(iv, "translationX", 0, 90),//右移
                ObjectAnimator.ofFloat(iv, "scaleY", 1, 0.5f),//y軸縮放到一半
                ObjectAnimator.ofFloat(iv, "alpha", 1, 0.25f, 1)//透明度變換
        );
        //延遲一秒開始
        set.setStartDelay(1000);

        bt.setOnClickListener((v) -> {
            //改變屬性 位置  向下移動iv高的二分之一
            ObjectAnimator.ofFloat(iv, "translationY", iv.getHeight() / 2).start();
            //背景屬性改變開始
            colorAnim.start();
            //集合動畫
            set.setDuration(3000).start();
        });
}

軸點默認為View的中心點括饶。

常用的propertyName

  • rotationX 圍繞x軸旋轉(zhuǎn)
  • rotationY 圍繞y軸旋轉(zhuǎn)
  • rotation 圍繞軸點旋轉(zhuǎn)
  • translationX 在x軸方向上平移
  • translationY 在y軸方向上平移
  • scaleX 在x軸方向縮放
  • scaleY 在y軸方向縮放
  • alpha 透明度
  • width 寬度
  • height 高度

1.2 常用方法介紹

Animation的api

1.2.1 ObjectAnimator

  • ObjectAnimator.ofFloat(Object target, String propertyName, float... values)

Constructs and returns an ObjectAnimator that animates between float values.

返回一個根據(jù)方法內(nèi)的具體的values創(chuàng)建的ObjectAnimator對象

  1. Object target 株茶,目標控件View的對象
  2. String propertyName,屬性的名字
  3. float... values ,根據(jù)具體需求需要的屬性值

  • ofPropertyValuesHolder(Object target, PropertyValuesHolder... values)

Constructs and returns an ObjectAnimator that animates between the sets of values specified in PropertyValueHolder objects

返回一個由PropertyValueHolder對象創(chuàng)建的ObjectAnimator對象

 public void byPropertyValuesHolder(ImageView iv) {
       PropertyValuesHolder pvh_1 = PropertyValuesHolder.ofFloat("rotationX", 0, 360);
       PropertyValuesHolder pvh_2 = PropertyValuesHolder.ofFloat("rotation", 0, -90);
       PropertyValuesHolder pvh_3 = PropertyValuesHolder.ofFloat("alpha", 1, 0.25f, 1);
       ObjectAnimator.ofPropertyValuesHolder(iv, pvh_1, pvh_2, pvh_3).setDuration(1000).start();
}

  • ofInt(Object target, String propertyName, int... values)

Constructs and returns an ObjectAnimator that animates between int values.

返回一個由int值屬性創(chuàng)建的ObjectAnimator對象


  • setTarget(Object target)
    設(shè)置動畫目標View

1.2.2 ValueAnimator

  • ValueAnimatorsetEvaluator(new ArgbEvaluator())
    設(shè)置估值器

  • addUpdateListener(ValueAnimator.AnimatorUpdateListener listener)

Adds a listener to the set of listeners that are sent update events through the life of an animation.

添加一個監(jiān)聽图焰,可以用來在動畫過程中改變屬性


  • setRepeatCount(int num)
    設(shè)置動畫的循環(huán)次數(shù)启盛,默認為0,-1為無限循環(huán)

  • setStartDelay(long startDelay)
    設(shè)置動畫開始的延遲時間


  • cancel()
    取消一個正在進行的動畫技羔。取消前僵闯,動畫進行到哪個狀態(tài),取消后藤滥,就保持在那個狀態(tài)鳖粟。

  • end()
    結(jié)束動畫。調(diào)用結(jié)束方法后拙绊,View會跳轉(zhuǎn)到結(jié)束狀態(tài)向图。如果動畫設(shè)置了循環(huán)次數(shù)setRepeatCount()和重復(fù)模式setRepeatMode(ObjectAnimator.REVERSE),結(jié)束狀態(tài)就要根據(jù)具體設(shè)置分析标沪。


1.2.3 AnimatorSet

  • playTogether(Animator... items)

Sets up this AnimatorSet to play all of the supplied animations at the same time.

同時播放所有的Animator動畫對象榄攀。


  • playSequentially(Animator... items)

Sets up this AnimatorSet to play each of the supplied animations when the previous animation ends.

順序播放Animator動畫對象

  • setInterpolator(TimeInterpolator interpolator)

Sets the TimeInterpolator for all current child animations of this AnimatorSet.

設(shè)置插值器


1.2.4 Animator

直接子類:AnimatorSetValueAnimator
間接子類:ObjectAnimatorTimeAnimator

Animator類的方法子類都可以直接使用。

  • addListener(Animator.AnimatorListener listener)

Adds a listener to the set of listeners that are sent events through the life of an animation, such as start, repeat, and end.

為動畫添加一個監(jiān)聽過程的接口金句。如果不想實現(xiàn)AnimatorListener接口中的所有方法也可以繼承AnimatorListenerAdapter檩赢。

set.addListener(new Animator.AnimatorListener() {
    @Override
    public void onAnimationStart(Animator animator) {
         toast("動畫開始");
    }
    @Override
    public void onAnimationEnd(Animator animator) {
         toast("動畫結(jié)束");
    }
    @Override
    public void onAnimationCancel(Animator animator) {
         toast("動畫取消");
    }
    @Override
    public void onAnimationRepeat(Animator animator) {
        toast("動畫重建");
    }
});

實現(xiàn)了接口中全部的方法。


繼承AnimatorListenerAdapter:

set.addListener(new AnimatorListenerAdapter() {
    @Override
    public void onAnimationEnd(Animator animation) {
        super.onAnimationEnd(animation);
        toast("動畫結(jié)束");
    }
});

根據(jù)實際需求违寞,實現(xiàn)不同的方法贞瞒。


  • addPauseListener(Animator.AnimatorPauseListener listener)

Adds a pause listener to this animator

為動畫增加暫停監(jiān)聽


2.插值器和估值器

TimeInterpolator,時間插值器趁曼。用來根據(jù)時間流逝的百分比來計算出當(dāng)前屬性的值變化的百分比军浆。

常用插值器:

名稱 作用
LinearInterpolator 線性插值器。勻速動畫
AccelerateDecelerateInterpolator 加速減速插值器
DecelerateInterpolator 勻減速插值器挡闰。動作越來越慢
BounceInterpolator 回彈插值器瘾敢。到達平移后,回彈
CycleInterpolator 循環(huán)插值器尿这。在兩點間往還運動
PathInterpolator 路徑插值器簇抵。根據(jù)單一方向定義的路徑坐標運動
OvershootInterpolator 超越插值器。超出后射众,再返回來
AnticipateInterpolator 預(yù)期插值器碟摆。先反向運動再根據(jù)指定的方向運動

都是Interpolator的子類


TypeEvaluator,類型估值算法(估值器)叨橱。用來根據(jù)當(dāng)前屬性變化改變的百分比來計算改變后的屬性值典蜕。

  • IntEvaluator断盛,針對整型屬性
  • FloatEvaluator,針對浮點型屬性
  • ArgbEvaluator愉舔,針對Color屬性

2.1簡單Demo

模擬小球下落
private void initView() {
    Button bt = (Button) findViewById(R.id.bt_interpolator_activity);
    ImageView iv = (ImageView) findViewById(R.id.iv_interpolator_activity);
    LinearLayout root = (LinearLayout) findViewById(R.id.root_interpolator_activity);//根布局

    AnimatorSet set = new AnimatorSet();
    set.setInterpolator(new BounceInterpolator());
    set.setDuration(3000);
    //利用View的post方法拿到根布局的高度
    root.post(() -> {
        //計算下降高度
        int height = root.getHeight() - iv.getHeight() - bt.getHeight();
        //設(shè)置動畫
        set.play(ObjectAnimator.ofFloat(iv, "translationY", height));
    });
        
    bt.setOnClickListener(v ->set.start());
    }

利用BounceInterpolator可以很方便的做出模擬小球下落的動畫钢猛。也可以根據(jù)需求進行自定義插值器。


2.2 對任意屬性做動畫

Object的屬性abc做動畫轩缤,必須滿足2個條件:

  1. object必須提供setAbc()的方法命迈。如果動畫的時候沒有傳遞初始值,還要提供getAbc()方法火的。因為系統(tǒng)要去abc的初始值壶愤。如果不滿足,程序直接Crash
  2. objectsetAbc對屬性abc所做的改變必須能夠通過某種方法反映出來馏鹤,比如UI改變之類的征椒。這條不滿足,動畫無效但程序不會Crash

2.2.1 改變Button的寬度

例如湃累,想要利用屬性對話來改變一個Button的寬度勃救。

private void initView() {
    Button bt = (Button) findViewById(R.id.bt_button_activity);
    bt.setOnClickListener((v) -> performAnimate(bt));
}

private void performAnimate(Button bt) {
    ObjectAnimator.ofInt(bt, "width", 500).setDuration(1000).start();
}

實際測試,這段代碼完全不起作用治力。


2.2.2不起作用的原因

Button繼承的TextView

/**
 * Makes the TextView exactly this many pixels wide.
 * You could do the same thing by specifying this number in the
 * LayoutParams.
 *
 * @see #setMaxWidth(int)
 * @see #setMinWidth(int)
 * @see #getMinWidth()
 * @see #getMaxWidth()
 *
 * @attr ref android.R.styleable#TextView_width
 */
 @android.view.RemotableViewMethod
 public void setWidth(int pixels) {
    mMaxWidth = mMinWidth = pixels;
    mMaxWidthMode = mMinWidthMode = PIXELS;

    requestLayout();
    invalidate();
 }


 /**
  * Return the width of the your view.
  *
  * @return The width of your view, in pixels.
  */
  @ViewDebug.ExportedProperty(category = "layout")
  public final int getWidth() {
     return mRight - mLeft;
  }

getWidth()方法View的方法剪芥,是可以獲取Button高度的。setWidth()方法TextView和子類的專屬方法琴许。是用來設(shè)置TextView的最大寬度和最小寬度的,并不是用來設(shè)置TextView的寬度的方法溉躲。TextView的寬度對應(yīng)于XMLandroid:layout_width榜田,setWidth方法對應(yīng)的是android:width

也就是說:ButtonsetWidth()getWidth()對應(yīng)的就不是一個屬性锻梳。只滿足的條件1箭券,不滿足條件2


2.2.3 解決辦法

有三種解決辦法:

  • 如果有權(quán)限,給對象加上getset方法
  • 用一個類包裝原始對象疑枯,間接提供getset方法
  • 采用ValueAnimation辩块,監(jiān)聽動畫過程,實現(xiàn)屬性的改變

getset方法往往拿不到權(quán)限荆永。

利用包裝類方法:

private void initView() {
    Button bt = (Button) findViewById(R.id.bt_button_activity);
    bt.setOnClickListener((v) -> performAnimate(bt,bt.getWidth()));
}
    
 private void performAnimate(Button bt,int width) {
    ButtonWrapper wrapper = new ButtonWrapper(bt);
    wrapper.setWidth(width);
    ObjectAnimator.ofInt(wrapper, "width", 500).setDuration(1000).start();
}

private static class ButtonWrapper {
    private View target;

    public ButtonWrapper(View target) {
        this.target = target;
    }

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

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

拿到Button的寬度后废亭,設(shè)置給ButtonWrapper。這樣動畫開始后具钥,Button會從原始大小開始變化豆村。


利用ValueAnimation方法:

private void initView() {
    Button bt = (Button) findViewById(R.id.bt_button_activity);
       
    bt.setOnClickListener((v) -> performAnimate(bt,bt.getWidth(),500));
}
    
private void performAnimate(Button bt,int start, int end) {
    ValueAnimator valueAnimator = ValueAnimator.ofInt(1,100);

    //IntEvaluator對象,估值的時候使用
    IntEvaluator intEvaluator = new IntEvaluator();

    valueAnimator.addUpdateListener((animator -> {
        //獲取當(dāng)前動畫的進度值 骂删, 整型掌动, 1到100
        int currentValue = (int) animator.getAnimatedValue();

        //獲取當(dāng)前進度的占整個動畫過程的比例四啰,浮點型, 0到1
        float fraction = animator.getAnimatedFraction();
        //直接利用整型估值器粗恢,通過比例計算寬度柑晒,然后Button設(shè)置
        bt.getLayoutParams().width = intEvaluator.evaluate(fraction,start,end);
        bt.requestLayout();
    }));
    //開啟動畫
    valueAnimator.setDuration(1000).start();
}
 

監(jiān)控動畫過程,利用IntEvaluator估值器


3.最后

動畫基礎(chǔ)知識大概介紹完眷射,自定義TypeEvaluatorInterpolator以及配合自定義View更多高級的用法匙赞,以后再做補充。

接下來相當(dāng)長的時間會用來學(xué)習(xí)自定義View凭迹。想通過一系列博客來記錄學(xué)習(xí)罚屋,一開始先學(xué)習(xí)一些View的基礎(chǔ)屬性知識為學(xué)習(xí)自定義View做準備,再學(xué)習(xí)具體的測量嗅绸,繪制過程脾猛,View的事件體系,工作原理鱼鸠。學(xué)習(xí)過程中間會加入繼續(xù)對動畫的深入學(xué)習(xí)猛拴,也可能會加入RxJava的后續(xù)學(xué)習(xí)或者其他的框架的學(xué)習(xí)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蚀狰,一起剝皮案震驚了整個濱河市愉昆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌麻蹋,老刑警劉巖跛溉,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異扮授,居然都是意外死亡芳室,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進店門刹勃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來堪侯,“玉大人,你說我怎么就攤上這事荔仁∥榛拢” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵乏梁,是天一觀的道長次洼。 經(jīng)常有香客問我,道長遇骑,這世上最難降的妖魔是什么滓玖? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮质蕉,結(jié)果婚禮上势篡,老公的妹妹穿的比我還像新娘翩肌。我一直安慰自己,他們只是感情好禁悠,可當(dāng)我...
    茶點故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布念祭。 她就那樣靜靜地躺著,像睡著了一般碍侦。 火紅的嫁衣襯著肌膚如雪粱坤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天瓷产,我揣著相機與錄音站玄,去河邊找鬼。 笑死濒旦,一個胖子當(dāng)著我的面吹牛株旷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播尔邓,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼晾剖,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了梯嗽?” 一聲冷哼從身側(cè)響起齿尽,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎灯节,沒想到半個月后循头,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡炎疆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年卡骂,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片磷雇。...
    茶點故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖躏救,靈堂內(nèi)的尸體忽然破棺而出唯笙,到底是詐尸還是另有隱情,我是刑警寧澤盒使,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布崩掘,位于F島的核電站,受9級特大地震影響少办,放射性物質(zhì)發(fā)生泄漏苞慢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一英妓、第九天 我趴在偏房一處隱蔽的房頂上張望挽放。 院中可真熱鬧绍赛,春花似錦、人聲如沸辑畦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纯出。三九已至蚯妇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間暂筝,已是汗流浹背箩言。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留焕襟,地道東北人陨收。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像胧洒,于是被迫代替她去往敵國和親畏吓。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內(nèi)容