android 如何创建VectorDrawable与梯度和多种颜色与Jetpack合成?

1tu0hz3e  于 2023-03-16  发布在  Android
关注(0)|答案(1)|浏览(133)

这是一个share your knowledge, Q&A-style问题,灵感来自这个问题,但它增强了梯度,填充/空动画和闪光效果的VectorDrawables的目标,如下面的gif

第一张图纸

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24"
    android:viewportHeight="24"
    android:tint="?attr/colorControlNormal">
  <path
      android:fillColor="#EC407A"
      android:pathData="M12,21.35l-1.45,-1.32C5.4,15.36 2,12.28 2,8.5 2,5.42 4.42,3 7.5,3c1.74,0 3.41,0.81 4.5,2.09C13.09,3.81 14.76,3 16.5,3 19.58,3 22,5.42 22,8.5c0,3.78 -3.4,6.86 -8.55,11.54L12,21.35z"/>
</vector>

时钟

vector
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:width="24dp"
  android:height="24dp"
  android:tint="?attr/colorControlNormal"
  android:viewportHeight="24"
  android:viewportWidth="24">
  <group
    android:name="button"
    android:translateX="12"
    android:translateY="12">
    <group
      android:name="button_pivot"
      android:translateX="-12"
      android:translateY="-12">
      <group
        android:name="right_button"
        android:translateX="19.0722"
        android:translateY="4.5758">
        <path
          android:name="path_1"
          android:fillAlpha="1"
          android:fillColor="@android:color/white"
          android:pathData="M 2.9409942627,1.16249084473 c 0,0 -4.59599304199,-3.85699462891 -4.59599304199,-3.85699462891 c 0,0 -1.2859954834,1.53300476074 -1.2859954834,1.53300476074 c 0,0 4.59599304199,3.85600280762 4.59599304199,3.85600280762 c 0,0 1.2859954834,-1.53201293945 1.2859954834,-1.53201293945 Z"/>
      </group>
      <group
        android:name="left_button"
        android:translateX="4.9262"
        android:translateY="4.5729">
        <path
          android:name="left_button_path"
          android:fillAlpha="1"
          android:fillColor="@android:color/white"
          android:pathData="M 2.9409942627,-1.16250610352 c 0,0 -1.2859954834,-1.53199768066 -1.2859954834,-1.53199768066 c 0,0 -4.59599304199,3.85600280762 -4.59599304199,3.85600280762 c 0,0 1.2859954834,1.53300476074 1.2859954834,1.53300476074 c 0,0 4.59599304199,-3.8570098877 4.59599304199,-3.8570098877 Z"/>
      </group>
    </group>
  </group>
  <group
    android:name="alarm"
    android:translateX="12"
    android:translateY="12">
    <group
      android:name="alarm_pivot"
      android:translateX="-12"
      android:translateY="-12">
      <group
        android:name="alarm_hands"
        android:translateX="13.75"
        android:translateY="12.4473">
        <path
          android:name="alarm_hands_path"
          android:fillAlpha="1"
          android:fillColor="@android:color/white"
          android:pathData="M -1.25,-4.42700195312 c 0,0 -1.5,0 -1.5,0 c 0,0 0,6.0 0,6.0 c 0,0 4.74699401855,2.85400390625 4.74699401855,2.85400390625 c 0,0 0.753005981445,-1.23199462891 0.753005981445,-1.23199462891 c 0,0 -4.0,-2.37200927734 -4.0,-2.37200927734 c 0,0 0,-5.25 0,-5.25 Z"/>
      </group>
      <group
        android:name="alarm_body"
        android:translateX="12"
        android:translateY="13.0203">
        <path
          android:name="alarm_outline_path"
          android:fillAlpha="1"
          android:fillColor="@android:color/white"
          android:pathData="M -0.0050048828125,-9 c -4.97399902344,0 -8.99499511719,4.0299987793 -8.99499511719,9 c 0,4.9700012207 4.02099609375,9 8.99499511719,9 c 4.97399902344,0 9.00500488281,-4.0299987793 9.00500488281,-9 c 0,-4.9700012207 -4.03100585938,-9 -9.00500488281,-9 Z M 0,7 c -3.86700439453,0 -7,-3.13400268555 -7,-7 c 0,-3.86599731445 3.13299560547,-7 7,-7 c 3.86700439453,0 7,3.13400268555 7,7 c 0,3.86599731445 -3.13299560547,7 -7,7 Z"/>
      </group>
    </group>
  </group>
</vector>
06odsfpq

06odsfpq1#

如链接中的答案所示,基本上要做的是使用blendMode = BlendMode.SrcIn创建一个目标矩形,并使用触摸或动画更新此矩形。
第一种方法是绘制一个覆盖Icon一半高度的矩形

@Composable
private fun ClipIconSample() {
    val vectorRes2: Painter = painterResource(id = R.drawable.vd_dashboard_active)
    Icon(
        vectorRes2,
        modifier = Modifier
            .drawWithContent {
                val height = size.height

                with(drawContext.canvas.nativeCanvas) {
                    val checkPoint = saveLayer(null, null)

                    // Destination
                    drawContent()

                    // Source
                    drawRect(
                        Color(0xffEC407A),
                        topLeft = Offset(0f, height / 2),
                        size = Size(size.width, size.height / 2),
                        blendMode = BlendMode.SrcIn

                    )

                    restoreToCount(checkPoint)

                }
            }
            .size(100.dp),
        contentDescription = null
    )
}

对于第二个替换颜色与刷子

@Composable
private fun GradientClipIconSample() {
    val vectorRes2: Painter = painterResource(id = R.drawable.vd_dashboard_active)
    Icon(
        vectorRes2,
        modifier = Modifier
            .drawWithContent {
                with(drawContext.canvas.nativeCanvas) {
                    val checkPoint = saveLayer(null, null)

                    // Destination
                    drawContent()

                    // Source
                    drawRect(
                        brush = Brush.sweepGradient(
                            colors = listOf(
                                Color.Green,
                                Color.Cyan,
                                Color.Red,
                                Color.Blue,
                                Color.Yellow,
                                Color.Magenta,
                            )
                        ),
                        blendMode = BlendMode.SrcIn
                    )

                    restoreToCount(checkPoint)

                }
            }
            .size(100.dp),
        contentDescription = null
    )
}

第三个将targetValue更改为

var targetValue by remember {
    mutableStateOf(0f)
}
val progress by animateFloatAsState(
    targetValue = targetValue,
    animationSpec = tween(1000)
)

全面执行

@Composable
private fun FillIconSample() {
    val vectorRes2: Painter = painterResource(id = R.drawable.vd_dashboard_active)
    var targetValue by remember {
        mutableStateOf(0f)
    }
    val progress by animateFloatAsState(
        targetValue = targetValue,
        animationSpec = tween(1000)
    )
    Icon(
        vectorRes2,
        modifier = Modifier
            .clickable(
                interactionSource = MutableInteractionSource(),
                indication = null,
            ) {
                targetValue = if (targetValue == 0f) {
                    1f
                } else {
                    0f
                }
            }
            .drawWithContent {
                val height = size.height * progress

                with(drawContext.canvas.nativeCanvas) {
                    val checkPoint = saveLayer(null, null)

                    val totalHeight = size.height
                    val filledHeight = totalHeight * progress

                    // Destination
                    drawContent()

                    // Source
                    drawRect(
                        Color(0xffEC407A),
                        topLeft = Offset(0f, totalHeight - height),
                        size = Size(size.width, height),
                        blendMode = BlendMode.SrcIn

                    )

                    restoreToCount(checkPoint)

                }
            }
            .size(100.dp),
        contentDescription = null
    )
}

闪光效果是一种渐变,其中进度变化为

@Composable
private fun ShimmerIconSample() {

    val vectorRes2: Painter = painterResource(id = R.drawable.vd_clock_alarm)

    val transition = rememberInfiniteTransition()

    val progress by transition.animateFloat(
        initialValue = 0f,
        targetValue = 1f,
        animationSpec = infiniteRepeatable(
            animation = tween(1500, easing = LinearEasing),
            repeatMode = RepeatMode.Restart
        )
    )

    Icon(
        vectorRes2,
        modifier = Modifier
            .drawWithContent {
                with(drawContext.canvas.nativeCanvas) {
                    val checkPoint = saveLayer(null, null)
                    val canvasWidth = size.width

                    val brush = Brush.horizontalGradient(
                        colors = listOf(
                            Color(0xff616161),
                            Color.White,
                            Color(0xff9E9E9E),
                            Color(0xff616161),
                        ),
                        startX = canvasWidth * progress,
                        endX = canvasWidth * progress * 2f
                    )

                    // Destination
                    drawContent()

                    // Source
                    drawRect(
                        brush = brush,
                        blendMode = BlendMode.SrcIn
                    )

                    restoreToCount(checkPoint)

                }
            }
            .size(100.dp),
        contentDescription = null
    )
}

相关问题