動(dòng)畫之ViewGroup

參考:

  1. https://blog.csdn.net/harvic880925/article/details/50785786
    非常感謝,
    沒有自己的內(nèi)容,基本上轉(zhuǎn)自上面的博客,非常感謝!

LayoutAnimation

layoutAnimation和gridLayoutAnimation在API 1中就有的函數(shù)。所以他們也只能使用animtion來做動(dòng)畫,而不能使用animator。

layoutAnimation的xml實(shí)現(xiàn)

步驟:

  1. anim文件夾下,定義layout_animation文件:
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    android:animation="@android:anim/slide_in_left"
    android:animationOrder="normal"
    android:delay="20" />
  1. 在ViewGroup類型控件中,配置android:layoutAnimation,如:

你妹RecylcerView測試,設(shè)置標(biāo)簽無效;通過代碼并且要在設(shè)置后,馬上加載數(shù)據(jù)才有效果,這是什么鬼,真是太坑了;

<android.support.v7.widget.RecyclerView
        android:id="@+id/recycler"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:layoutAnimation="@anim/tween_layout"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

或通過代碼(設(shè)置后馬上加載數(shù)據(jù))設(shè)置

    recycler.apply {
            layoutManager = LinearLayoutManager(context)
            addItemDecoration(DividerItemDecoration(context, LinearLayoutManager.VERTICAL))
            // 設(shè)置無效
            // layoutAnimation = AnimationUtils.loadLayoutAnimation(applicationContext, R.anim.tween_layout)
        }

        btn_start.setOnClickListener {
            // 有效,設(shè)置后馬上加載數(shù)據(jù)
            recycler.layoutAnimation = AnimationUtils.loadLayoutAnimation(applicationContext, R.anim.tween_layout)
            adapter = Adapter(mutableListOf("java", "Android", "Python", "javascript"))
            recycler.adapter = adapter
        }

注意:

  1. RecyclerView設(shè)置layoutanimation時(shí)機(jī);
  2. android:layoutAnimation只在viewGroup創(chuàng)建的時(shí)候,才會(huì)對(duì)其中的item添加動(dòng)畫。在創(chuàng)建成功以后,再向其中添加item將不會(huì)再有動(dòng)畫。

如:

operator fun plus(item: String) {
          data += item
          notifyItemInserted(data.size - 1)
 }
// 調(diào)用
adapter + "Better${Random().nextInt(10)}"

layoutAnimation字段說明

  1. delay:指每個(gè)Item的動(dòng)畫開始延時(shí),取值是android:animation所指定動(dòng)畫時(shí)長的倍數(shù),默認(rèn)為0.5
  2. animationOrder: 指viewGroup中的控件動(dòng)畫開始順序,取值有normal(正序)、reverse(倒序)、random(隨機(jī))
  3. animation:指定每個(gè)item入場所要應(yīng)用的動(dòng)畫;(只能是anim資源文件夾下的動(dòng)畫資源)

layoutAnimation的代碼實(shí)現(xiàn)

xml中l(wèi)ayoutAnimation標(biāo)簽所對(duì)應(yīng)的類為LayoutAnimationController,構(gòu)造如下:

public LayoutAnimationController(Animation animation)
public LayoutAnimationController(Animation animation, float delay)

animation對(duì)應(yīng)xml中的android:animation屬性,delay 為 android:delay屬性;

API方法,參考原博客:

具體例子:

btn_bycode.setOnClickListener {
    val anim = AnimationUtils.loadAnimation(baseContext, android.R.anim.slide_in_left)
    recycler.layoutAnimation = LayoutAnimationController(anim).apply {
        delay = 0.3f
        order = LayoutAnimationController.ORDER_REVERSE
    }
    adapter = Adapter(mutableListOf("java", "Android", "Python", "javascript"))
    recycler.adapter = adapter
}

GridLayoutAnimation

android gridview 首次加載數(shù)據(jù)時(shí),各子控件item的過渡動(dòng)畫;GridlayoutAnimation,僅能用于 android 原生控件 GridView;

略,后門專門來弄一個(gè)RecyclerView;

animateLayoutChanges與LayoutTransition

在API 11之后,Android為了支持ViewGroup類控件,在添加和移除其中控件時(shí)自動(dòng)添加動(dòng)畫,為我們提供了一個(gè)非常簡單的屬性:android:animateLayoutChanges=[true/false],所有派生自ViewGroup的控件都具有此屬性,只要在XML中添加上這個(gè)屬性,就能實(shí)現(xiàn)添加/刪除其中控件時(shí),帶有默認(rèn)動(dòng)畫了。

注意:默認(rèn) layoutAnimation動(dòng)畫只是對(duì)首次加載數(shù)據(jù)有效;

android:animateLayoutChanges屬性

通過給容器添加 android:animateLayoutChanges 并設(shè)置為true, 在添加或刪除控件時(shí),就有了自帶動(dòng)畫效果了,默認(rèn)是一個(gè)漸變的動(dòng)畫;

<LinearLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="56dp"
        android:orientation="horizontal"
        android:animateLayoutChanges="true"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent">
</LinearLayout>

LayoutTransition

android:animateLayoutChanges默認(rèn)是一個(gè)漸變動(dòng)畫,無法自定義;如果我們想改變這個(gè)默認(rèn)動(dòng)畫效果,需要使用到 LayoutTransition,這也是從API 11 開始支持的;

使用LayoutTransition步驟:

  1. 創(chuàng)建實(shí)例;
  2. 創(chuàng)建動(dòng)畫并設(shè)置:
  3. 將LayoutTransaction設(shè)置進(jìn)ViewGroup

不知道怎么回事,使用kotlin來編寫時(shí),總是報(bào)錯(cuò),Java代碼正常:

btn_layout_transition.setOnClickListener {
            val transition = LayoutTransition()
            val objAnimator = ObjectAnimator.ofFloat(container, "rotation", 0f, -90f, 90f, 0f)
            transition.setAnimator(LayoutTransition.APPEARING, objAnimator)
            container.layoutTransition = transition
}

報(bào)錯(cuò)為:
layoutTransition 為 Unresolved reference: setLayoutTransition
以后解決了,再來更新;

Java 代碼實(shí)現(xiàn):

// 1.創(chuàng)建實(shí)例
LayoutTransition transition = new LayoutTransition();
// 2. 創(chuàng)建動(dòng)畫并設(shè)置, 這里為添加子view時(shí),動(dòng)畫
transition.setAnimator(LayoutTransition.APPEARING,
                        ObjectAnimator.ofFloat(null, "rotation", 0f, -90f, 90f, 0f));
// 3. 將LayoutTransaction設(shè)置進(jìn)ViewGroup
container.setLayoutTransition(transition);
// 這樣添加時(shí),子 view 會(huì)有動(dòng)畫了
container.addView(getCustomView());

LayoutTransition.setAnimator 函數(shù)

public void setAnimator(int transitionType, Animator animator)  

參數(shù)說明:

  • transitionType 表示當(dāng)前應(yīng)用動(dòng)畫的對(duì)象范圍,取值有:
    1. APPEARING —— 元素在容器中出現(xiàn)時(shí)所定義的動(dòng)畫。
    2. DISAPPEARING —— 元素在容器中消失時(shí)所定義的動(dòng)畫。
    3. CHANGE_APPEARING —— 由于容器中要顯現(xiàn)一個(gè)新的元素,其它需要變化的元素所應(yīng)用的動(dòng)畫
    4. CHANGE_DISAPPEARING —— 當(dāng)容器中某個(gè)元素消失,其它需要變化的元素所應(yīng)用的動(dòng)畫
  • animator 即響應(yīng)的屬性動(dòng)畫;

LayoutTransition.APPEARING與LayoutTransition.DISAPPEARING
表示入場動(dòng)畫,與出場動(dòng)畫

// LayoutTransition.APPEARING,入場
LayoutTransition transition = new LayoutTransition();
    transition.setAnimator(LayoutTransition.APPEARING,
            ObjectAnimator.ofFloat(null, "alpha", 0.5f, 1.0f, 0.8f, 1.0f));

// LayoutTransition.DISAPPEARING,出場
transition.setAnimator(LayoutTransition.DISAPPEARING,
            ObjectAnimator.ofFloat(null, "rotationX", 0f, 90f));

// 設(shè)置給ViewGroup
container.setLayoutTransition(transition);

CHANGE_APPEARING與CHANGE_DISAPPEARING

CHANGE_APPEARING的使用

在添加控件時(shí),除了被添加控件本身的入場動(dòng)畫以外,其它需要移動(dòng)位置的控件,在移動(dòng)位置時(shí),也被添加上了動(dòng)畫(left點(diǎn)位移動(dòng)畫),這些除了被添加控件以外的其它需要移動(dòng)位置的控件組合,所對(duì)應(yīng)的動(dòng)畫就是LayoutTransition.CHANGE_APPEARING

// 添加元素調(diào)用addView()方法時(shí),index之后的元素才有動(dòng)畫
// 必須的left,top
PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left", 0, 100, 0);
PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top", 1, 1);
                transition.setAnimator(LayoutTransition.CHANGE_APPEARING,
                        ObjectAnimator.ofPropertyValuesHolder(container, pvhLeft,pvhTop));
container.setLayoutTransition(transition);
container.addView(getCustomView(), 0);  // 0 之后的所有元素都有動(dòng)畫

注意的地方:

  1. LayoutTransition.CHANGE_APPEARING和LayoutTransition.CHANGE_DISAPPEARING必須使用PropertyValuesHolder所構(gòu)造的動(dòng)畫才會(huì)有效果,不然無效!
  2. 在構(gòu)造PropertyValuesHolder動(dòng)畫時(shí),”left”、”top”屬性的變動(dòng)是必寫的。如果不需要變動(dòng),則直接寫為:
PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,0);  
PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",0,0);  
  1. 在構(gòu)造PropertyValuesHolder時(shí),所使用的ofInt,ofFloat中的參數(shù)值,第一個(gè)值和最后一個(gè)值必須相同,不然此屬性所對(duì)應(yīng)的的動(dòng)畫將被放棄,在此屬性值上將不會(huì)有效果;
// 第一個(gè)value與最后一個(gè)value必須相等
PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,100,0);  

4.在構(gòu)造PropertyValuesHolder時(shí),所使用的ofInt,ofFloat中,如果所有參數(shù)值都相同,也將不會(huì)有動(dòng)畫效果;

// 動(dòng)畫無效
PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",100,100);  

CHANGE_DISAPPEARING的使用

PropertyValuesHolder outLeft = PropertyValuesHolder.ofInt("left", 0, 0);
PropertyValuesHolder outTop = PropertyValuesHolder.ofInt("top", 0, 0);
PropertyValuesHolder rotation = PropertyValuesHolder.ofFloat("rotationY", 0f, 90f, 0f);

transition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING,
                    ObjectAnimator.ofPropertyValuesHolder(container, outLeft, outTop, rotation));
if(container.getChildCount() > 0) {
    container.removeViewAt(0);
}

坑真多,不用為妙

LayoutTransition其他函數(shù)

/** 
 * 設(shè)置所有動(dòng)畫完成所需要的時(shí)長 
 */  
public void setDuration(long duration)  
/** 
 * 針對(duì)單個(gè)type,設(shè)置動(dòng)畫時(shí)長; 
 * transitionType取值為:APPEARING、DISAPPEARING、CHANGE_APPEARING、CHANGE_DISAPPEARING 
 */  
public void setDuration(int transitionType, long duration)   
/** 
 * 針對(duì)單個(gè)type設(shè)置插值器 
 * transitionType取值為:APPEARING、DISAPPEARING、CHANGE_APPEARING、CHANGE_DISAPPEARING 
 */  
public void setInterpolator(int transitionType, TimeInterpolator interpolator)  
/** 
 * 針對(duì)單個(gè)type設(shè)置動(dòng)畫延時(shí) 
 * transitionType取值為:APPEARING、DISAPPEARING、CHANGE_APPEARING、CHANGE_DISAPPEARING 
 */  
public void setStartDelay(int transitionType, long delay)  
/** 
 * 針對(duì)單個(gè)type設(shè)置,每個(gè)子item動(dòng)畫的時(shí)間間隔 
 */  
public void setStagger(int transitionType, long duration)  

setStagger

//設(shè)置單個(gè)item間的動(dòng)畫間隔
transition.setStagger(LayoutTransition.CHANGE_APPEARING, 100);

監(jiān)聽函數(shù)
在任何類型的LayoutTransition開始和結(jié)束時(shí),都會(huì)調(diào)用TransitionListener的startTransition和endTransition方法。

transition.addTransitionListener(new LayoutTransition.TransitionListener() {
    public void startTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType) {}
    public void endTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType) {}
});

參數(shù)說明:

  • LayoutTransition transition:當(dāng)前的LayoutTransition實(shí)例
  • ViewGroup container:當(dāng)前應(yīng)用LayoutTransition的container
  • View view:當(dāng)前在做動(dòng)畫的View對(duì)象
  • int transitionType:當(dāng)前的LayoutTransition類型,取值有:APPEARING、DISAPPEARING、CHANGE_APPEARING、CHANGE_DISAPPEARING
最后編輯于
?著作權(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)容

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