動畫

Prerequisites:

動畫預覽

點選「Start Interactive Mode」開始動畫
img

點選左上角紅色「Stop Interactive Mode」停止動畫
img

Animation Spec 動畫

Spring 彈簧

dampingRatio 彈簧彈性

愈小愈有彈性

Spring.DampingRatioHighBouncy     // 0.2f - 高彈性
Spring.DampingRatioMediumBouncy   // 0.5f - 中等彈性
Spring.DampingRatioLowBouncy      // 0.75f - 低彈性
Spring.DampingRatioNoBouncy       // 1.0f - 無彈性(臨界阻尼)

自訂彈性

1
2
3
4
val customSpring = spring<Float>(
    dampingRatio = 0.3f,  // 越小越有彈性
    stiffness = Spring.StiffnessMedium
)

stiffness 彈簧剛硬度

愈低愈柔軟,愈會回彈。

Spring.StiffnessHigh       // 10_000f - 高剛度(快速)
Spring.StiffnessMedium     // 1_500f  - 中等剛度
Spring.StiffnessLow        // 200f    - 低剛度(緩慢)
Spring.StiffnessVeryLow    // 50f     - 非常低

自訂回彈

1
2
3
4
5
// 自定義
val softSpring = spring<Float>(
    dampingRatio = Spring.DampingRatioMediumBouncy,
    stiffness = 100f  // 非常柔軟
)

animateContentSize + animationSpec(spirng)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@Preview(showBackground = true, widthDp = 300, heightDp = 400)
@Composable
fun GreetingPreview2() {
  AnimateContentSizeExample1()
}

@Composable
fun AnimateContentSizeExample1() {
  var isExpanded by remember { mutableStateOf(false) }
  Box(
    modifier = Modifier
      .fillMaxWidth()
      .animateContentSize(
        // 加上animationSpec
        animationSpec = spring(
          dampingRatio = Spring.DampingRatioHighBouncy,
          stiffness = Spring.StiffnessLow
        )
      )
      .background(Color.Blue)
      .padding(16.dp)
      .clickable {
        isExpanded = !isExpanded
      }
  ) {
    Column {
      Text("click")
      if(isExpanded) {
        Text("hello \n" +"world \n" +"hi \n",
          modifier = Modifier.background(Color.White))
      }
    }
  }
}

tween 動畫持續時間

durationMillis 動畫持續時間

語法

1
2
3
4
5
6
// 基本用法
val tweenSpec = tween<Float>(
    durationMillis = 300,      // 動畫持續時間(毫秒)
    delayMillis = 0,           // 延遲開始時間
    easing = LinearEasing      // 動畫速度
)

tween程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Composable
fun AnimateContentSizeExample() {
  var isExpanded by remember { mutableStateOf(false) }
  Box(
    modifier = Modifier
      .fillMaxWidth()
      .animateContentSize(
        // 展開動畫持續1秒
        animationSpec = tween(durationMillis = 1000)
      )
      .background(Color.Blue)
      .padding(16.dp)
      .clickable {
        isExpanded = !isExpanded
      }
  ) {
    Column {
      Text("click")
      if (isExpanded) {
        Text("hello \n" + "world \n" + "hi \n",
          modifier = Modifier.background(Color.White)
        )
      }
    }
  }
}

easing

進入畫面與離開畫面的動畫速度

  • LinearEasing 線性(均速)
  • FastOutSlowInEasing // 最常用的緩動
  • FastOutLinearInEasing // 快速出,線性進
  • LinearOutSlowInEasing // 線性出,慢速進

其它

// 彈性效果
CubicBezierEasing(0.68f, -0.55f, 0.265f, 1.55f)

// 回彈效果
EaseOutBounce

速度比較

easing = LinearEasing  // 線性:均速運動
// 0% ______ 50% ______ 100% (速度一樣)

easing = FastOutSlowInEasing  // 快速出,慢速入(最自然)
// 0% ████___ 50% ___██ 100% (開始快,結束慢)

easing = LinearOutSlowInEasing  // 線性出,慢速入
// 0% ______ 50% ___██ 100% (結束時減速)

easing = FastOutLinearInEasing  // 快速出,線性入
// 0% ████___ 50% ______ 100% (開始時加速)

animateXXXXAsState 狀態改變產生動畫

狀態變化時自動產生動畫效果。

函數 用途 返回值類型 常用場景
animateDpAsState 動畫化尺寸、間距 Dp 大小變化、位移
animateFloatAsState 動畫化小數值 Float 透明度、旋轉、縮放
animateColorAsState 動畫化顏色 Color 顏色過渡

animateDpAsState

  • 尺寸、間距、位移等與 Dp 相關的值

語法

1
2
3
4
5
val animatedValue: Dp by animateDpAsState(
    targetValue: Dp,                    // 目標值
    animationSpec: AnimationSpec<Dp> = tween(),  // 動畫
    label: String = "DpAnimation"       // 除錯標籤
)

img

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Composable
fun AnimationDpStateExample() {
  var isExpended by remember { mutableStateOf(false) }
  val animateBoxHeight by animateDpAsState(
    // 高度原本是0 按一下按鈕 變成100
    targetValue = if (isExpended) 100.dp else 0.dp,
    // 動畫
    animationSpec = tween(2000),
    label = "Height Animate"
  )
  Column {
    Button(onClick = {
      isExpended = !isExpended
    }) {
      Text("Click")
    }
    Box(
      modifier = Modifier
        .fillMaxWidth()
        // 會自動轉換成dp
        .height(animateBoxHeight)
        .background(Color.Blue)
    ) {
      Text("Content")
    }
  }
}

animateFloatAsState

animateFloatAsState 旋轉、透明度、縮小放大與 Float 相關的值。

img

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@Composable
fun AnimationFloatStateExample() {
  var isExpended by remember { mutableStateOf(false) }
  val animateRotate by animateFloatAsState(
    targetValue = if (isExpended) 45f else 0f,
    animationSpec = tween(2000),
    label = "Rotate Animate"
  )
  val animateAlpha by animateFloatAsState(
    targetValue = if (isExpended) 1f else 0.5f,
    animationSpec = tween(2000),
    label = "Rotate Animate"
  )
  val animateScale by animateFloatAsState(
    targetValue = if (isExpended) 1.5f else 1.0f,
    animationSpec = tween(2000),
    label = "Scale Animate"
  )
  val animationYOffset by animateDpAsState(
    targetValue = if (isExpended) 60.dp else 0.dp,
    animationSpec = tween(2000),
    label = "Offset Animate"
  )
  Column {
    Button(onClick = {
      isExpended = !isExpended
    }) {
      Text("Click")
    }
    Box(
      modifier = Modifier
        .size(100.dp)
        .offset(y = animationYOffset)
        .graphicsLayer {
          rotationZ = animateRotate
          scaleX = animateScale
          scaleY = animateScale
          alpha = animateAlpha
        }
        .background(Color.Blue)
    ) {
      Text("Content")
    }
  }
}

animateColorAsState

  • 顏色變化、漸變色轉換

img

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Composable
fun AnimationColorStateExample() {
  var isExpended by remember { mutableStateOf(false) }
  val animateBgColor by animateColorAsState(
    targetValue = if (isExpended) Color.Yellow else Color.Blue,
    animationSpec = tween(2000),
    label = "Color Animate"
  )
  Column {
    Button(onClick = {
      isExpended = !isExpended
    }) {
      Text("Click")
    }
    Box(
      modifier = Modifier
        .size(100.dp)
        .background(animateBgColor)
    ) {
      Text("Content")
    }
  }
}

AnimatedVisibility 顯示與消失動畫

官方文件有許多進入動畫與離開動畫的展示效果。

語法

1
2
3
4
5
6
7
8
9
10
11
12
13
// 顯示或隱藏
var isVisible by remember { mutableStateOf(false) }
AnimatedVisibility(
  // 顯示或隱藏
  visible = isVisible,
  // 進入動畫
  enter = fadeIn(),
  // 離開動畫
  exit = fadeOut()
) {
	// 要顯示與隱藏的東西
	// 要顯示與隱藏的東西
}

完整程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Composable
fun AnimatedVisibilityExample() {
  var isVisible by remember { mutableStateOf(false) }
  Column {
    Button(onClick = {
      isVisible = !isVisible
    }) {
      Text("Click")
    }
    AnimatedVisibility(
      visible = isVisible,
      enter = fadeIn(),
      exit = fadeOut()
    ) {
      Box(
        modifier = Modifier
          .size(100.dp)
          .background(Color.Blue)
      ) {
        Text("Content")
      }
    }
  }
}

infiniteTransition 無限循環動畫

results matching ""

    No results matching ""