中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android?Compose之Animatable動畫停止怎么使用

發布時間:2023-05-10 14:36:52 來源:億速云 閱讀:264 作者:iii 欄目:開發技術

本篇內容主要講解“Android Compose之Animatable動畫停止怎么使用”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Android Compose之Animatable動畫停止怎么使用”吧!

打斷停止

顧名思義即動畫在運行過程中被打斷,那么是被什么打斷呢?被同一個 Animatable的另一個動畫打斷,簡單的說就是當 Animatable在執行某一個動畫的過程中,此時再使用同一個 Animatable 去開啟另一個動畫,此時就會打斷正在運行中的動畫,即停止正在運行中的話執行新的動畫。

那么為什么要打斷正在運行中的動畫呢?不能兩個動畫一起執行嗎?假設一個動畫是將方塊移動到 200dp 的位置,另一個動畫是將方塊移動到 0dp 的位置,如果不會被打斷兩個動畫可以同時執行,那就會出現方塊一會兒往 200dp 位置一會兒往 0dp 移動的閃爍情況,顯然動畫效果不符合預期,所以被設計成了后一個動畫會打斷前一個動畫。

下面就用一個實例演示動畫的打斷,代碼如下:

// 方塊顏色,默認為藍色
var backgroundColor by remember { mutableStateOf(Color.Blue) }
// 動畫實例
val animatable = remember { Animatable(10.dp, Dp.VectorConverter) }
// 獲取協程作用域
val scope = rememberCoroutineScope()
Box {
    // 動畫方塊
    Box(
        Modifier
            // 使用動畫值
            .padding(start = animatable.value, top = 30.dp)
            .size(100.dp, 100.dp)
            .background(backgroundColor)
            .clickable { // 點擊事件
                // 啟動動畫
                scope.launch {
                    animatable.animateTo(200.dp,
                        // 為了方便看到效果,動畫時間設置為 1000ms                 
                        animationSpec = tween(durationMillis = 1000)
                    )
                }
            }
    )
    // 按鈕,用于開啟新動畫
    Button(onClick = {
        // 修改方塊顏色,方便觀察區分兩個動畫
        backgroundColor = Color.Cyan
        // 啟動新動畫
        scope.launch {
            animatable.animateTo(50.dp, animationSpec = tween(durationMillis = 1000))
        }
    }, Modifier.padding(top = 170.dp, start = 70.dp)) {
        Text(text = "Next", style = TextStyle(fontSize = 10.sp))
    }
}

界面上添加了一個方塊和一個按鈕,點擊方塊執行動畫移動到 200dp 位置,點擊按鈕執行動畫移動到 50dp 位置,為了區分兩個動畫動畫執行時為方塊設置了不同的顏色

從上面的效果可以看出,對同一個 Animatable開啟新的動畫確實會打斷正在運行的動畫。

除了上面演示的 animateTo可以打斷動畫以外,AnimatablesnapToanimateDecay同樣可以打斷動畫。

主動停止

前面介紹的是新動畫打斷正在運行的動畫,那么如果我們想主動停止一個Animatable動畫該怎么辦呢?很簡單,Animatable提供了stop方法用于停止動畫。

示例代碼如下:

var backgroundColor by remember { mutableStateOf(Color.Blue) }
// 動畫實例
val animatable = remember { Animatable(10.dp, Dp.VectorConverter) }
val scope = rememberCoroutineScope()
Box {
    // 動畫方塊
    Box(
        Modifier
            // 使用動畫值
            .padding(start = animatable.value, top = 30.dp)
            .size(100.dp, 100.dp)
            .background(backgroundColor)
            .clickable { // 點擊事件,開啟動畫
                scope.launch {
                    animatable.animateTo(200.dp,
                    	// 為了方便觀察動畫效果,動畫時長設置為 1000ms
                        animationSpec = tween(durationMillis = 1000)
                    )
                }
            }
    )
    // 停止按鈕
    Button(onClick = {
        // 修改方塊顏色
        backgroundColor = Color.Cyan
        // 停止動畫
        scope.launch {
            animatable.stop()
        }
    }, Modifier.padding(top = 170.dp, start = 70.dp)) {
        Text(text = "Stop", style = TextStyle(fontSize = 10.sp))
    }
}

需要注意的是 stop方法也是一個掛起函數,需要在協程中執行

觸達邊界停止

Animatable可以通過 updateBounds函數為動畫設置邊界值,當動畫運動到邊界時會立即停止動畫,updateBounds定義如下:

fun updateBounds(lowerBound: T? = this.lowerBound, upperBound: T? = this.upperBound)

updateBounds方法有兩個參數 lowerBoundupperBound分別為動畫的邊界下限值和上限值,默認為 null即不做限制,可以單獨設置上限和下限的值,當設置對應值后,動畫運行過程中動畫值達到邊界值時就會立即停止動畫。

示例代碼如下:

// 創建狀態 通過狀態驅動動畫
var moveToRight by remember { mutableStateOf(false) }
// 動畫實例
val animatable = remember { Animatable(10.dp, Dp.VectorConverter) }
// 設置動畫邊界
animatable.updateBounds(lowerBound = 10.dp, upperBound = 200.dp)
val scope = rememberCoroutineScope()
Box(
    Modifier
        // 使用動畫值
        .padding(start = animatable.value, top = 30.dp)
        .size(100.dp, 100.dp)
        .background(Color.Blue)
        .clickable { // 點擊事件
            // 修改狀態
            moveToRight = !moveToRight
            scope.launch {
                // 執行動畫
                animatable.animateTo(
                    // 根據狀態設置動畫的目標值,分別是向右到 400dp 和 向左到 -100dp 位置
                    if (moveToRight) 400.dp else -100.dp,
                    animationSpec = tween(durationMillis = 1000)
                )
            }
        }
)

上面代碼分別設置了下限值為 10dp、上限值為 200dp,同時動畫目標值分別設置為 -100dp 和 400dp:

可以看出來,雖然動畫目標設置分別設置了 -100dp 和 400dp,但是因為我們設置了邊界值為 10dp 和 200dp,所以動畫向右運動時到達邊界值即 200dp 位置時就停止了,向左同樣的到達邊界值 10dp 也停止了動畫,這就是動畫邊界的作用。

多維邊界

之前介紹了 Compose 動畫是可以作用于多維數值的,比如作用于 Size、Offset、React 等數據時就是多維的動畫,此時對動畫設置邊界后,動畫目標值只要有其中一維的數值達到邊界就會立即停止,并不會等到所有維的數值都達到邊界才會停止。

下面用一個示例來舉例說明,還是上面的方塊動畫,上面只進行了橫向的動畫,如果我們要同時進行橫向和豎向的動畫,可以使用 Offset 來進行動畫,然后對其進行邊界設置來觀察效果,代碼如下:

// 創建狀態 通過狀態驅動動畫
var moveToRight by remember { mutableStateOf(false) }
// 動畫實例
val animatable = remember { Animatable(Offset(10f, 30f), Offset.VectorConverter) }
// 設置邊界值,下限:Offset(10f, 30f)  上限:Offset(400f, 200f)
animatable.updateBounds(lowerBound = Offset(10f, 30f), upperBound = Offset(400f, 200f))
val scope = rememberCoroutineScope()
Box {
    Box(
        Modifier
            // 使用動畫值
            .padding(start = animatable.value.x.dp, top = animatable.value.y.dp)
            .size(100.dp, 100.dp)
            .background(Color.Blue)
            .clickable {
                // 修改狀態
                moveToRight = !moveToRight
                scope.launch {
                    animatable.animateTo(
                        // 根據狀態設置動畫的目標值
                        // 分別為向右和向下的 Offset(400f,400f)
                        // 向上和向左的 Offset(-100f,0f)
                        if (moveToRight) Offset(400f,400f) else Offset(-100f,0f),
                        animationSpec = tween(durationMillis = 1000)
                    )
                }
            }
    )
}

可以發現,上限設置為 Offset(400f, 200f)即 x 軸最大為 400dp、y 軸最大為 200dp,動畫目標值為Offset(400f,400f),當方塊移動到 y 坐標為 200dp 時 y 坐標的值達到邊界值,動畫就停止了,此時 x 坐標值并未達到邊界值。同樣的往回執行時 x 坐標先觸發達到邊界值 10dp 時停止了動畫。

如果就是想讓動畫都達到邊界才停止,此時不應該采用多維動畫的方式,而是應該使用多個單維動畫,對其分別設置邊界即可。

動畫停止監聽

動畫停止可分為異常停止和正常停止,其中打斷和主動停止動畫屬于異常停止,動畫運行完成或達到邊界后停止屬于正常停止。

異常停止

一個動畫打斷另一個動畫,或調用 stop主動停止動畫都屬于異常停止,此時動畫會拋出 CancellationException的異常,在代碼中可通過捕獲該異常來監聽動畫的異常停止,代碼如下:

scope.launch {
    try {
        // 異常停止時動畫會拋出異常,不會正常返回動畫結果
        val animationResult = animatable.animateTo(200.dp,
            animationSpec = tween(durationMillis = 1000)
        )
        // 動畫異常停止時會拋出異常,下面的代碼不會被執行
        // do something
    } catch (e: CancellationException) {
        Log.e("ANIMATOIN", "動畫異常停止")
    }
}

正常停止

動畫觸達邊界停止屬于正常停止,此時動畫會正常返回結果,從結果中的 endReason可判斷動畫是否為觸達邊界停止,代碼如下:

scope.launch {
    val animationResult = animatable.animateTo(200.dp,
        animationSpec = tween(durationMillis = 1000)
    )
    // 判斷動畫是否觸達邊界停止
    if(animationResult.endReason == AnimationEndReason.BoundReached){
        // do something
    }
}

同時動畫結果還能拿到動畫停止時的速度等數據,這樣就能通過監聽動畫邊界停止進行自定義的處理,比如結合上一篇介紹的衰減動畫讓動畫到達邊界后反向運動,代碼如下:

@Preview
@Composable
fun AnimationBound3() {
    // 動畫實例
    val animatable = remember { Animatable(10.dp, Dp.VectorConverter) }
    // 設置邊界值
    animatable.updateBounds(upperBound = 200.dp, lowerBound = 10.dp)
    val scope = rememberCoroutineScope()
    val splineBasedDecay = rememberSplineBasedDecay<Dp>()
    Box(
        Modifier
            // 使用動畫值
            .padding(start = animatable.value, top = 30.dp)
            .size(100.dp, 100.dp)
            .background(Color.Blue)
            .clickable {
                scope.launch {
                    // 啟動動畫,設置初始速度為 3000dp
                    val animationResult = animatable.animateDecay(3000.dp, splineBasedDecay)
                    // 判斷是否為到達邊界停止
                    if(animationResult.endReason == AnimationEndReason.BoundReached){
                        // 執行反向動畫,初始速度取動畫結束時速度的負數
                        reverseAnimation(animatable, -animationResult.endState.velocity, splineBasedDecay)
                    }
                }
            }
    )
}
/// 反向執行動畫
private suspend fun reverseAnimation(
    animatable: Animatable<Dp, AnimationVector1D>,
    initialVelocity: Dp,
    splineBasedDecay: DecayAnimationSpec<Dp>
) {
    val result =  animatable.animateDecay(initialVelocity, splineBasedDecay)
    // 判斷是邊界停止時遞歸執行反向動畫直到動畫非邊界停止
    if(result.endReason == AnimationEndReason.BoundReached){
        reverseAnimation(animatable, -result.endState.velocity, splineBasedDecay)
    }
}

到此,相信大家對“Android Compose之Animatable動畫停止怎么使用”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

都安| 渝中区| 会同县| 罗定市| 博白县| 三门县| 丰台区| 渝中区| 河曲县| 潜江市| 平谷区| 调兵山市| 双峰县| 体育| 抚远县| 赣榆县| 鹤山市| 来宾市| 金川县| 衡阳县| 华亭县| 田阳县| 虹口区| 长宁区| 泽普县| 丽水市| 泾川县| 中方县| 文安县| 巴青县| 阳谷县| 青铜峡市| 吉首市| 屯门区| 宾阳县| 南召县| 霍城县| 慈利县| 麟游县| 义乌市| 耒阳市|