tft每日頭條

 > 生活

 > 效果控件面闆講解

效果控件面闆講解

生活 更新时间:2025-02-14 01:18:01

效果控件面闆講解(響應視窗屬性動畫)1

在上一篇文章中,我們介紹了所有關于 "邊到邊" (edge-to-edge) 的 API 改動: 讓您的軟鍵盤動起來。在這篇文章中,我們會繼續跟進軟鍵盤動畫這一實際任務。為了展示可以實現的效果,您可以查看下面這個來自同一個應用的示例,左邊的是運行在 Android 10 上,而右邊的是運行在 Android 11 上 (動畫效果是實際速度的 20%):

效果控件面闆講解(響應視窗屬性動畫)2

如上動圖所示: 在 Android 10 以及以前版本的設備上,當用戶點擊文字輸入框來輸入回複,軟鍵盤會帶着動畫效果移動到預期的位置,但是應用在兩個狀态間的動畫很突兀。這是一個您在設備上已經看過很久的效果,降慢速度到實際速度的 20% 使得它更為明顯。

您可以在右邊看到相同的場景運行在 Android 11 上的效果。這一次,當用戶點擊文字輸入框的時候,應用跟随着軟鍵盤一起移動并且創造了一個更流暢的體驗。

所以您如何才能在您的應用中添加這種體驗呢?這都依賴新 API 的支持...

WindowInsetsAnimation 類

在 Android 11 中支持實現這種效果的 API 就是新的 WindowInsetsAnimation 類,它包含一個涉及視窗屬性的動畫。應用可以通過 WindowInsetsAnimation.Callback 類監聽各種動畫事件,這個回調可以被設置到一個視圖上:

valcb=object:WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP){ //TODO } view.setWindowInsetsAnimationCallback(cb)

讓我們來看一下這個回調類,以及它提供的方法:

想象一下當前軟鍵盤是關閉的,用戶剛剛點擊了 EditText。系統現在馬上要顯示軟鍵盤,由于我們已經設置了 WindowInsetsAnimation.Callback,我們會按順序收到如下的調用:

valcb=object:WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP){ overridefunonPrepare(animation:WindowInsetsAnimation){ //#1:第一,onPrepare被調用會允許應用記錄當前布局的任何狀态 } //#2:在onPrepare之後,正常的WindowInsets會被下發到視圖層次 //結構中,它包含了結束狀态。這意味着您的視圖的 //OnApplyWindowInsetsListener會被調用,這會導緻一個布局傳遞 //以反映結束狀态 overridefunonStart( animation:WindowInsetsAnimation, bounds:WindowInsetsAnimation.Bounds ):WindowInsetsAnimation.Bounds{ //#3:接下來是onStart,這個會在動畫開始的時候被調用。 //這允許應用記錄下視圖的目标狀态或者結束狀态 returnbounds } overridefunonProgress( insets:WindowInsets, runningAnimations:List<WindowInsetsAnimation> ):WindowInsets{ //#4:接下來是一個很重要的調用:onProgress。這個會在動畫中每次視窗屬性 //更改的時候被調用。在軟鍵盤的這個例子中,這個調用會發生在軟鍵盤在屏幕 //上滑動的時候。 returninsets } overridefunonEnd(animation:WindowInsetsAnimation){ //#5:最後onEnd在動畫已經結束的時候被調用。使用這個來 //清理任何舊的狀态。 } }

這就是回調在理論上是如何工作的,現在讓我們在場景中實踐一下...

實現示例

我們會使用 WindowInsetsAnimation.Callback 來實現在文章開頭您看到的示例。讓我們從實現我們的回調函數開始:

onPrepare() 方法

首先我們要複寫 onPrepare(),并且在其他布局改變發生之前記錄下視圖的底部坐标:

效果控件面闆講解(響應視窗屬性動畫)3

valview=binding.conversationList valcb=object:WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP){ varstartBottom=0 varendBottom=0 overridefunonPrepare(animation:WindowInsetsAnimation){ //#1:首先onPrepare被調用,這允許應用記錄下當前布局中的任何視圖狀态。 //我們要記錄下這個視圖在視窗中的底部坐标。 startBottom=view.calculateBottomInWindow() } }

屬性分發

這時候結束狀态的屬性會被分發,而我們的 OnApplyWindowInsetsListener 會被調用,監聽器會更新容器視圖的内邊距,這會導緻内容被推上去。

然而用戶不會看到這個如下圖所示的狀态。

效果控件面闆講解(響應視窗屬性動畫)4

onStart() 方法

接下來我們實現 onStart() 方法,這會讓我們先記錄下這個視圖結束時候的位置。

我們利用 translationY 在視覺上将視圖移動回初始位置,因為我們不想現在就讓用戶看到結束狀态。由于系統保證了任何由視窗屬性變更導緻的重新布局都會在 onStart() 的同一幀被調用,所以用戶此時不會看到閃動。

效果控件面闆講解(響應視窗屬性動畫)5

valview=binding.conversationList valcb=object:WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP){ varstartBottom=0 varendBottom=0 overridefunonStart( animation:WindowInsetsAnimation, bounds:WindowInsetsAnimation.Bounds ):WindowInsetsAnimation.Bounds{ //#3:接下來是onStart,它會在動畫開始的時候被調用 //我們記錄下視窗中視圖的底部 endBottom=view.calculateBottomInWindow() //然後我們移動視圖回到它視覺上的初始位置 view.translationY=startBottom-endBottom //我們不會更改邊界,所以我們會返回傳入的邊界值 returnbounds } }

onProgress() 方法

最後我們要複寫 onProgress() 方法,這會讓我們可以在軟鍵盤滑入的時候更新我們的視圖。

我們會在起始和結束狀态之間插值,并再次使用 translationY 使得視圖可以和軟鍵盤一起移動。

效果控件面闆講解(響應視窗屬性動畫)6

valview=binding.conversationList valcb=object:WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP){ varstartBottom=0 varendBottom=0 overridefunonProgress( insets:WindowInsets, runningAnimations:List<WindowInsetsAnimation> ):WindowInsets{ //#4:接下來是最重要的調用:onProgress //它會在動畫中每次視窗屬性改變的時候被調用。 //從起始位置到結束位置,我們利用線性插值的方式和動畫本身的分數 //來計算視圖的偏移量。 valoffset=lerp( startBottom-endBottom, 0, animation.interpolatedFraction ) //…然後我們再用translationY來設置 view.translationY=offset returninsets } }

軟鍵盤的協同效果

使用這個方法,我們已經實現了軟鍵盤和應用視圖的同步。如果您想查看完整的實現,請查閱 WindowInsetsAnimation 的示例: android/user-interface-samples

如果您在您的應用中添加了上述實現,請在下方評論區留言告訴我們您的使用感受。在下一篇文章中,我們會繼續探索如何能讓您的應用控制軟鍵盤,比如在滾動列表的時候自動打開軟鍵盤。

視圖裁剪

如果您在您的視圖上嘗試我們在這篇文章中介紹的方法,您可能會發現視圖在移動的過程中被裁剪了。這是因為我們在移動視圖的過程中,視圖本身可能會因為 OnApplyWindowInsetsListener 導緻的布局改變而被調整大小。

我們會在以後的文章中介紹如何解決這個問題,而目前我會推薦查看 WindowInsetsAnimation 示例,其中也包含了一個可以避免這個問題的技巧。

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关生活资讯推荐

热门生活资讯推荐

网友关注

Copyright 2023-2025 - www.tftnews.com All Rights Reserved