设置文本颜色动画时如何减少重组?

Abh*_*bhi 2 android android-jetpack-compose jetpack-compose-animation android-jetpack-compose-animation

当前代码

@Composable
fun TextDemo() {
    var selectedIndex by remember {
        mutableIntStateOf(0)
    }
    Row {
        TabText(
            text = "First",
            isSelected = selectedIndex == 0,
            onClick = {
                selectedIndex = 0
            },
        )
        TabText(
            text = "Second",
            isSelected = selectedIndex == 1,
            onClick = {
                selectedIndex = 1
            },
        )
    }
}

@Composable
fun TabText(
    text: String,
    isSelected: Boolean,
    onClick: () -> Unit,
) {
    val tabTextColor by animateColorAsState(
        targetValue = if (isSelected) {
            Color.Red
        } else {
            Color.Black
        },
        animationSpec = tween(
            easing = LinearEasing,
        ),
        label = "tab_text_color",
    )

    Text(
        modifier = Modifier
            .padding(8.dp)
            .clickable {
                onClick()
            },
        text = text,
        color = tabTextColor,
    )
}
Run Code Online (Sandbox Code Playgroud)

UI 供参考Text二合一Row

用户界面截图

布局检查器重组

布局检查器的屏幕截图

问题

如何减少文本颜色变化时的重新组合?

对于alphatransition等属性,可以在使用动画时避免重组Modifier.graphicsLayer {}

alpha每次选择更改时,使用动画而不是颜色的相同代码仅重新组合一次。

布局检查器屏幕截图

代码

@Composable
fun TabText(
    text: String,
    isSelected: Boolean,
    onClick: () -> Unit,
) {
    val alphaValue by animateFloatAsState(
        targetValue = if (isSelected) {
            1F
        } else {
            0.5F
        },
        animationSpec = tween(
            easing = LinearEasing,
        ),
        label = "tab_text_color",
    )

    Text(
        modifier = Modifier
            .graphicsLayer {
                alpha = alphaValue
            }
            .padding(8.dp)
            .clickable {
                onClick()
            },
        text = text,
    )
}
Run Code Online (Sandbox Code Playgroud)

Thr*_*ian 6

首先,当您记录读取 State 的重组时,最好在内部完成,SideEffect否则可能会出现误报,因为记录本身也算作 State read

要对文本颜色更改进行一种重组,您可以使用Canvas或 内部的任何绘制修改器,并在使用和函数进行更改Tab时仅调用绘制阶段。ColorTextMeasurerdrawTextDrawScope

第二种选择是将 BlendModes 与 Modifier.drawContent{} 结合使用,通过一次重新组合来更改颜色,如下所示

@Preview
@Composable
private fun TextAnimationTest() {

    var isSelected by remember {
        mutableStateOf(false)
    }

    SideEffect {
        println("Recomposing...")
    }

    val tabTextColor by animateColorAsState(
        targetValue = if (isSelected) {
            Color.Red
        } else {
            Color.Black
        },
        animationSpec = tween(
            easing = LinearEasing,
        ),
        label = "tab_text_color",
    )


  Column {
      Button(
          onClick = {
              isSelected = isSelected.not()
          }
      ) {
          Text("Selected: $isSelected")
      }

      Text("Some Text", modifier = Modifier
          .graphicsLayer {
              compositingStrategy = CompositingStrategy.Offscreen
          }
          .drawWithContent {
              drawContent()

              drawRect(
                  color = tabTextColor,
                  blendMode = BlendMode.SrcIn
              )
          }
      )
  }
}
Run Code Online (Sandbox Code Playgroud)