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

溫馨提示×

溫馨提示×

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

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

Android?Compose狀態改變動畫animateXxxAsState怎么使用

發布時間:2022-12-01 10:20:02 來源:億速云 閱讀:160 作者:iii 欄目:開發技術

今天小編給大家分享一下Android Compose狀態改變動畫animateXxxAsState怎么使用的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

    animateXxxAsState

    在 Compose 中提供了一系列動畫 API,其中有一類 API 跟屬性動畫非常類似,它就是 animateXxxAsState,我翻譯成狀態改變動畫,其中 Xxx對應的是 DpFloatIntSizeOffsetRectIntOffsetIntSizeColor等數據類型,即當狀態改變時觸發對應數據類型的值的發生改變,從而執行數據從當前值到目標值變化的動畫。

    對應 Api 如圖:

    Android?Compose狀態改變動畫animateXxxAsState怎么使用

    接下來就看看這些 Api 到底是如何使用的。

    基礎使用

    我們首先以 animateDpAsState為例來看一下 animateXxxAsState 動畫到底如何使用。

    Dp是 Compose 提供的一個封裝數據類型,作用跟在傳統 Android 開發中 xml 使用的 dp單位是一樣的,是與屏幕像素密度相關的抽象單位。Compose 中為其提供了基礎數據類型的擴展,可以直接使用數值.dp進行使用,如:10.dp12.5.dp等。

    在 Compose 中跟長度相關的參數類型基本上都是 Dp,如寬高、圓角、間距等等。

    animateDpAsState的定義如下:

    fun animateDpAsState(
        targetValue: Dp,
        animationSpec: AnimationSpec<Dp> = dpDefaultSpring,
        finishedListener: ((Dp) -> Unit)? = null
    ): State<Dp>

    參數說明:

    • targetValue:目標值

    • animationSpec:動畫規格

    • finishedListener:動畫完成監聽

    返回值是一個 State 對象,即當其內部 value 值發生改變時會觸發 Compose 的重組,從而刷新界面。

    前面說了 animateXxxAsState 跟屬性動畫類似,但是好像不對呀,這里參數只有一個 targetValue即目標值,熟悉屬性動畫的都知道,屬性動畫的數值參數是一個可變參數,當為 1 個的時候,初始值為屬性當前值,目標值為傳入參數值,多個參數時初始值為第一個參數值,那這里只有一個 targetValue參數是不是也是初始值是從組件中獲取呢?

    我們來試試,創建一個 Box 通過改變其左邊距實現向右移動的動畫:

    val startPadding = animateDpAsState(10.dp)
    Box(Modifier
        .padding(start = startPadding.value, top = 10.dp)
        .size(100.dp, 100.dp)
        .background(Color.Blue)
    )

    因為需要對左邊距進行改變,所以將 padding 的 start 提取為 startPadding 變量,如上面的代碼,但是這樣的話那初始值就是 animateDpAsState傳入的值,也就是這里的 10.dp ,先運行一下看看是不是這樣:

    Android?Compose狀態改變動畫animateXxxAsState怎么使用

    運行效果確實是這樣,那怎么實現動畫效果呢?是修改 startPadding 的值么?我們給 Box 添加一個點擊事件修改 startPadding 的值看看:

    val startPadding = animateDpAsState(10.dp)
    Box(Modifier
        .padding(start = startPadding.value, top = 10.dp)
        .size(100.dp, 100.dp)
        .background(Color.Blue)
        // 添加點擊事件
        .clickable { 
            // 修改值 報錯
            startPadding.value = 100.dp
        }
    )

    這樣寫編輯器直接報錯了,錯誤信息如下:

    Android?Compose狀態改變動畫animateXxxAsState怎么使用

    說 val 變量不能重新賦值,是因為 startPadding 變量定義成了 val 所以不能修改么?并不是,因為我們重新賦值的不是 startPadding 變量,而是其內部的 value,而 startPadding 是 State 類型,State 內部的 value 是 val 的,定義如下:

    interface State<out T> {
        val value: T
    }

    所以并不能通過重新賦值修改 animateDpAsState創建的 State 的 value 值,那么怎么修改這個值讓其產生動畫呢?

    前面說了 animateXxxAsState 是依賴狀態改變而產生值的變化,所以實際上我們這里還需要定義一個額外的狀態變量,targetValue 參數根據這個狀態傳入不同的值,修改上面代碼如下:

    @Composable
    fun DpAnimationBox(){
        // 是否移動到右邊
        var moveToRight by remember { mutableStateOf(false) }
        //根據 moveToRight 變量傳入參數,true 代表在右邊則傳入 100.dp,false 在左邊則傳入 10.dp
        val startPadding = animateDpAsState(if (moveToRight) 100.dp else 10.dp)
        Box(Modifier
            .padding(start = startPadding.value, top = 10.dp)
            .size(100.dp, 100.dp)
            .background(Color.Blue)
            .clickable {
                // 改變 moveToRight 狀態,這里直接取反
                moveToRight = !moveToRight
            }
        )
    }

    修改點如下:

    • 使用 mutableStateOf 創建 moveToRight 變量,內部值為 Boolean 類型,即 MutableState,因為是在 Compose 函數中使用,需要用 remember 函數包裹,防止重組時重復創建

    • 修改 animateDpAsState 傳入參數的固定值為根據 moveToRight 傳入,即 if (moveToRight) 100.dp else 10.dp

    • 修改點擊事件處理,修改 moveToRight 的值

    運行看一下效果:

    Android?Compose狀態改變動畫animateXxxAsState怎么使用

    終于有效果了。所以實際是根據 moveToRight 的值改變導致傳入 animateDpAsState 的 targetValue 參數的值發生改變,而動畫執行的就是之前舊的值到當前設置最新值的動畫效果。

    上面的 moveToRight 是 MutableState 類型, 內部的 value 是 Boolean 類型,那是不是只能是 Boolean 類型呢,當然不是,可以是任何類型,只要在傳入 animateDpAsState 的參數值時根據這個類型的值進行自定義條件判斷傳入不同的數據即可,比如定義一個枚舉類型,根據不同類型傳入不同的參數,如下:

    enum class CustomState{
        STATE1,
        STATE2,
        STATE3,
    }
    var customState by remember { mutableStateOf(CustomState.STATE1) }
    val paddingValue = when(customState){
        CustomState.STATE1 -> 0.dp
        CustomState.STATE2 -> 100.dp
        CustomState.STATE3 -> 200.dp
    }
    val startPadding = animateDpAsState(paddingValue)

    甚至你可以直接創建一個跟動畫值相同的數據類型,比如這里可以直接創建一個 Dp 類型的狀態變量,然后在點擊時直接改變其值來驅動動畫執行,如下:

    @Composable
    fun DpAnimationBox(){
        // 動畫目標值
        var startPaddingValue by remember { mutableStateOf(10.dp) }
        // 蔣其設置給 animateDpAsState
        val startPadding = animateDpAsState(startPaddingValue)
        Box(Modifier
            .padding(start = startPadding.value, top = 10.dp)
            .size(100.dp)
            .background(Color.Blue)
            .clickable {
                // 改變動畫目標值
                if(startPaddingValue == 10.dp){
                    startPaddingValue = 100.dp
                }else{
                    startPaddingValue = 10.dp
                }
            }
        )
    }

    上面代碼同樣能實現跟之前一樣的效果。使用還是相當靈活的,開發中可以根據實際的需求定義不同的狀態來完成我們想要的動畫效果。

    動畫監聽

    animateXxxAsState提供了動畫完成時的監聽 finishedListener,可以通過監聽動畫完成進行自定義的業務處理,比如修改界面的顯示狀態或者開啟下一個動畫等。

    比如 animateDpAsStatefinishedListener 定義如下:

    (Dp) -> Unit

    有一個 Dp 類型的參數,即動畫完成時的目標值,使用如下:

    val startPadding = animateDpAsState(if (moveToRight) 100.dp else 10.dp) {
       //TODO: do something
    }

    比如我們想在上面的動畫結束時再讓方塊移動回去,那我們可以這么寫:

    val startPadding = animateDpAsState(if (moveToRight) 100.dp else 10.dp) {
        if(it == 100.dp){
            moveToRight = false
        }
    }

    效果如下:

    Android?Compose狀態改變動畫animateXxxAsState怎么使用

    或者我們想讓這個方塊往返重復執行,可以這么寫:

    val startPadding = animateDpAsState(if (moveToRight) 100.dp else 10.dp) {
        moveToRight = !moveToRight
    }

    效果如下:

    Android?Compose狀態改變動畫animateXxxAsState怎么使用

    通過對 animateXxxAsState動畫的監聽我們可以實現界面狀態的刷新或進行動畫的組合等自定義操作。

    使用示例

    前面講了 animateDpAsState動畫的使用,其他 animateXxxAsStateapi 的使用基本一樣,只是動畫作用的數據類型不一樣,下面將通過一個個簡單示例來看看其他幾個 api 的使用。

    animateFloatAsState

    animateFloatAsState作用于 Float 類型數據的動畫,比如 alpha 值,通過改變控件的 alpha 值可實現元素的顯示與隱藏,使用示例如下:

    @Composable
    fun FloatAnimationBox() {
        var show by remember { mutableStateOf(true) }
        val alpha by animateFloatAsState(if (show) 1f else 0f)
        Box(Modifier
            .padding(10.dp)
            .size(100.dp)
            .alpha(alpha)
            .background(Color.Blue)
            .clickable {
                show = !show
            }
        )
    }

    動畫效果:

    Android?Compose狀態改變動畫animateXxxAsState怎么使用

    animateIntAsState

    animateIntAsState作用于 Int 數據類型,上面的 animateDpAsState實現的動畫也可以使用 animateIntAsState實現,如下:

    @Composable
    fun IntAnimationBox() {
        var moveToRight by remember { mutableStateOf(false) }
        val startPadding by animateIntAsState(if (moveToRight) 100 else 10)
        Box(Modifier
            .padding(start = startPadding.dp, top = 10.dp)
            .size(100.dp)
            .background(Color.Blue)
            .clickable {
                moveToRight = !moveToRight
            }
        )
    }

    效果跟使用 animateDpAsState 實現的一樣:

    Android?Compose狀態改變動畫animateXxxAsState怎么使用

    animateColorAsState

    animateColorAsState是作用于 Color 上,可實現顏色的過渡動畫,比如將上面的方塊顏色從藍色變為紅色,代碼如下:

    @Composable
    fun ColorAnimationBox() {
        var toRed by remember { mutableStateOf(false) }
        val color by animateColorAsState(if (toRed) Color.Red else Color.Blue)
        Box(Modifier
            .padding(10.dp)
            .size(100.dp)
            .background(color)
            .clickable {
                toRed = !toRed
            }
        )
    }

    效果如下:

    Android?Compose狀態改變動畫animateXxxAsState怎么使用

    animateSizeAsState/animateIntSizeAsState

    animateSizeAsState作用于 Size 上,看到這個我們一下就想到了用于控件的 size 上,比如上面的 Modifier.size()上,但實際上 Modifier.size()的參數并不是 Size 類型,而是 Dp 類型或者 DpSize,而 DpSize 并不是 Size 的子類,所以不能直接將 Size 類型的數據直接傳入 Modifier.size()中,而是需要轉換一下:

    @Composable
    fun SizeAnimationBox() {
        var changeSize by remember { mutableStateOf(false) }
        // 定義 Size 動畫
        val size by animateSizeAsState(if (changeSize) Size(200f, 50f) else Size(100f, 100f))
        Box(Modifier
            .padding(10.dp)
            // 設置 Size 值
            .size(size.width.dp, size.height.dp)
            .background(Color.Blue)
            .clickable {
                changeSize = !changeSize
            }
        )
    }

    效果如下:

    Android?Compose狀態改變動畫animateXxxAsState怎么使用

    animateIntSizeAsState 跟 animateSizeAsState幾乎一樣,只是它作用于 IntSize,跟 Size 的唯一區別就是參數是 Int 類型而不是 Float 類型,如下:

    val size by animateIntSizeAsState(if (changeSize) IntSize(200, 50) else IntSize(100, 100))

    animateOffsetAsState/animateIntOffsetAsState

    animateOffsetAsState作用于 Offset 類型數據,用于控制偏移量,同樣的它不能直接用于 Modifier.offset()上,因為 Modifier.offset()接收的也是 Dp 類型參數,所以也需要進行轉換,如下:

    @Composable
    fun OffsetAnimationBox() {
        var changeOffset by remember { mutableStateOf(false) }
        // 定義 offset 動畫
        val offset by animateOffsetAsState(if (changeOffset) Offset(100f, 100f) else Offset(0f, 0f))
        Box(Modifier
            // 設置 offset 數值
            .offset(offset.x.dp, offset.y.dp)
            .padding(10.dp)
            .size(100.dp)
            .background(Color.Blue)
            .clickable {
                changeOffset = !changeOffset
            }
        )
    }

    效果如下:

    Android?Compose狀態改變動畫animateXxxAsState怎么使用

    animateIntOffsetAsState則作用于 IntOffset類型數據,使用方法與上面一致,只是將 Float 類型換成 Int 類型:

    val intOffset by animateIntOffsetAsState(if (changeOffset) IntOffset(100, 100) else IntOffset(0, 0))

    Modifier.offset()提供了一個返回 IntOffset 的函數參數,可以如下使用:

    Modifier.offset { intOffset }

    animateRectAsState

    animateRectAsState作用于 Rect數據,即可以同時控制位置和大小,通過 animateRectAsState可實現上面方塊的位置和大小變化的動畫,使用如下:

    @Composable
    fun RectAnimationBox() {
        var changeRect by remember { mutableStateOf(false) }
    	// 定義 rect
        val rect by animateRectAsState(if (changeRect) Rect(100f, 100f, 310f, 150f) else Rect(10f, 10f, 110f, 110f))
        Box(Modifier
            // 設置位置偏移
            .offset(rect.left.dp, rect.top.dp)
            // 設置大小
            .size(rect.width.dp, rect.height.dp)
            .background(Color.Blue)
            .clickable {
                changeRect = !changeRect
            }
        )
    }

    效果如下:

    Android?Compose狀態改變動畫animateXxxAsState怎么使用

    實戰

    上面講了 animateXxxAsState動畫 api 的基本使用,下面就用這些 api 來完成一個實戰效果,還是上一篇《Compose 中屬性動畫的使用》的效果:

    Android?Compose狀態改變動畫animateXxxAsState怎么使用

    前面說了animateXxxAsState是依賴于狀態的動畫,分析上面的動畫一共存在 4 個狀態:

    • 默認狀態:顯示藍色矩形按鈕,文字為 Upload

    • 開始上傳狀態:按鈕變為圓形且中間為白色,邊框為灰色,文字消失

    • 上傳中狀態:邊框根據進度變為藍色

    • 上傳完成狀態:按鈕從圓形回到圓角矩形,且顏色變為紅色,文字變為 Success

    實現原理如下:

    Android?Compose狀態改變動畫animateXxxAsState怎么使用

    首先通過一個枚舉定義上述四種狀態:

    enum class UploadState {
        Normal,
        Start,
        Uploading,
        Success
    }

    然后實現默認狀態的界面展示:

    @Composable
    fun UploadAnimation() {
        val originWidth = 180.dp
        val circleSize = 48.dp
        var uploadState by remember { mutableStateOf(UploadState.Normal) }
        var text by remember { mutableStateOf("Upload") }
        val textAlpha by animateFloatAsState(1f)
        val backgroundColor by animateColorAsState(Color.Blue)
        val boxWidth by animateDpAsState(originWidth)
        val progressAlpha by animateFloatAsState(0f)
        val progress by animateIntAsState(0)
        // 界面布局
        Box(
            modifier = Modifier
                .padding(start = 10.dp, top = 10.dp)
                .width(originWidth),
            contentAlignment = Alignment.Center
        ) {
            // 按鈕
            Box(
                modifier = Modifier
                    .clip(RoundedCornerShape(circleSize / 2))
                    .background(backgroundColor)
                    .size(boxWidth, circleSize)
                    .clickable {
                        // 點擊時修改狀態為開始上傳
                        uploadState = UploadState.Start
                    },
                contentAlignment = Alignment.Center,
            ) {
                // 進度
                Box(
                    modifier = Modifier.size(circleSize).clip(ArcShape(progress))
                        .alpha(progressAlpha).background(Color.Blue)
                )
                // 白色蒙版
                Box(
                    modifier = Modifier.size(40.dp).clip(RoundedCornerShape(20.dp))
                        .alpha(progressAlpha).background(Color.White)
                )
                // 文字
                Text(text, color = Color.White, modifier = Modifier.alpha(textAlpha))
            }
        }
    }

    然后根據上傳按鈕的狀態定義不同狀態時的數據值:

    var textAlphaValue = 1f
    var backgroundColorValue = Color.Blue
    var boxWidthValue = originWidth
    var progressAlphaValue = 0f
    var progressValue = 0
    when (uploadState) {
        // 默認狀態不處理
        UploadState.Normal -> {}
        // 開始上傳
        UploadState.Start -> {
            // 文字透明度變為0
            textAlphaValue = 0f
            // 按鈕背景顏色變為灰色
            backgroundColorValue = Color.Gray
            // 按鈕寬度變為圓的寬度
            boxWidthValue = circleSize
            // 中間進度的透明度變為 1
            progressAlphaValue = 1f
        }
        // 上傳中狀態
        UploadState.Uploading -> {
            textAlphaValue = 0f
            backgroundColorValue = Color.Gray
            boxWidthValue = circleSize
            progressAlphaValue = 1f
            // 進度值變為 100
            progressValue = 100
        }
        // 上傳完成
        UploadState.Success -> {
            // 文字透明度變為 1
            textAlphaValue = 1f
            // 顏色變為紅色
            backgroundColorValue = Color.Red
            // 按鈕寬度變化默認時的原始寬度
            boxWidthValue = originWidth
            // 進度透明度變為 0f
            progressAlphaValue = 0f
        }
    }
    val textAlpha by animateFloatAsState(textAlphaValue)
    val backgroundColor by animateColorAsState(backgroundColorValue)
    val boxWidth by animateDpAsState(boxWidthValue)
    val progressAlpha by animateFloatAsState(progressAlphaValue)
    val progress by animateIntAsState(progressValue)

    此時運行后點擊按鈕效果如下:

    Android?Compose狀態改變動畫animateXxxAsState怎么使用

    點擊后只有開始上傳的動畫,沒有后續的動畫效果,這是因為我們在點擊的時候只是將狀態變為了 UploadState.Start 而沒有進行后續狀態的改變,所以需要監聽動畫完成然后繼續改變按鈕的狀態來實現完整的動畫效果,代碼修改如下:

        val boxWidth by animateDpAsState(boxWidthValue){
            // 按鈕寬度變化完成監聽,當狀態為 Start 則修改為 Uploading
            if(uploadState == UploadState.Start){
                uploadState = UploadState.Uploading
            }
        }
        val progress by animateIntAsState(progressValue){
            // 進度完成監聽,當狀態為 Uploading 則修改為 Success
            if(uploadState == UploadState.Uploading){
                uploadState = UploadState.Success
                // 文字內容修改為 Success
                text = "Success"
            }
        }

    分別給按鈕寬度變化動畫和進度動畫進行監聽并修改其狀態,這樣就將整個動畫串聯起來了,最終效果如下:

    Android?Compose狀態改變動畫animateXxxAsState怎么使用

    以上就是“Android Compose狀態改變動畫animateXxxAsState怎么使用”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。

    向AI問一下細節

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

    AI

    泾川县| 益阳市| 漳州市| 元朗区| 晴隆县| 金山区| 宁明县| 宾川县| 漾濞| 利辛县| 平阳县| 顺平县| 五常市| 图木舒克市| 东源县| 清水县| 柯坪县| 广元市| 交城县| 白玉县| 抚松县| 济宁市| 孙吴县| 康保县| 象山县| 绍兴市| 邳州市| 固始县| 澄迈县| 瓮安县| 陆丰市| 临湘市| 汶上县| 徐水县| 资中县| 奉节县| 建湖县| 镇赉县| 曲阳县| 筠连县| 乌拉特中旗|