iT邦幫忙

2021 iThome 鐵人賽

DAY 21
2
Mobile Development

一天一腳步,30天學會 Android Compose UI!系列 第 21

Day 21 Compose UI Animation III

今年的疫情蠻嚴重的,希望大家都過得安好,希望疫情快點過去,能回到一些線下技術聚會的時光~

今天目標:了解 Compose UI 上 的 animation 位移 可以怎麼實作。

如果今天我們想實作一個圖片移動,從左下角移動到右上角,應該怎麼實作呢?思考的方式,是先定義出一個變化的時間,這個時間的數值會從 0 到1,然後讓畫面每隔一個時間就變化一次,從0的時間 到 1的時間,每個時間的畫面應該如何呈現,就可以完成動畫。

時間數值也可以不用0到1,可以有很多不同的變化,畫面變化跟呈現就是數學,將畫面想像成x,y軸,時間變化的0到1這個過程中,如何讓圖畫到你想要指定的位置上。

我參考了範例後改寫出下面的程式碼。

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
        val animationState =remember{mutableStateOf(false)}
        BoxWithConstraints(
            modifier = Modifier
                .fillMaxSize()
                .background(color = Color.Black)){
            MovingDemo(
                isMovingEnabled = animationState.value,
                maxWidth = maxWidth,
                maxHeight = maxHeight
            )
            LaunchButton(
                animationState = animationState.value,
                onToggleAnimationState ={animationState.value = !animationState.value})}
// 首先還是要先宣告圖跟按鈕
    }
}

@Composable
fun MovingDemo(
    isMovingEnabled: Boolean,
    maxWidth: Dp,
    maxHeight: Dp
) {
    val modifier: Modifier
    val emojiSize = 100.dp
    if (!isMovingEnabled) { 
        modifier = Modifier.offset(
            y = maxHeight - emojiSize, x = maxWidth
        )
// 如果確定開始執行後就每次改變 x與y的數值
} else {
        val infiniteTransition = rememberInfiniteTransition() 
// 記住動畫的變數
        val xPositionState = infiniteTransition.animateFloat(
            initialValue = 0f, // 初始值
            targetValue = 1f,  // 最後目標值
            animationSpec = infiniteRepeatable(
                animation = tween(
                    durationMillis = 2000,
                    easing = LinearOutSlowInEasing
                )
            )
// 每2000 millis seconds 變化一次,變化採 LinearOutSlowInEasing的方式
        )
        modifier = Modifier.offset(
            x = (maxWidth  - emojiSize ) * xPositionState.value,
            y = (maxHeight - emojiSize) - (maxHeight - emojiSize) * xPositionState.value,
        )
// 定義 x 與 y值的變化
    }
    Image(
        modifier = modifier
            .width(emojiSize)
            .height(emojiSize),
        painter = painterResource(id = R.drawable.horse),
        contentDescription = "A horse",
    )
// 如Day 7 一樣 宣告一個Image 
}


執行效果如上圖。

動畫的概念大多如此,可以思考譬如需要有一些特殊的畫面變化,如從下而上的 emoji 左右飄浮,或是從上而下如下雪般的雪花之類的,總之動畫的內容實在太多了,而且博大精深,可以探討的東西太多,所以今天會是最後一篇~
如果都搞懂了,我們就明天下個單元見!

參考資料:
https://www.youtube.com/watch?v=7yY2OocGiQU&ab_channel=AndroidDevelopers
https://www.youtube.com/watch?v=hLERtWC1THw&ab_channel=CodingWithMitch
https://github.com/mitchtabian/ComposePlayground/blob/animation-beta01-sample/app/src/main/java/com/codingwithmitch/composeplayground/ui/MainActivity.kt

本文同步發表在 Medium 上: 文章連結


上一篇
Day 20 Compose UI Animation II (change color & gradient)
下一篇
Day 22 Android Unit Test
系列文
一天一腳步,30天學會 Android Compose UI!30

尚未有邦友留言

立即登入留言