Tal*_*lal 6 android-animation kotlin android-jetpack-compose android-jetpack-compose-canvas android-jetpack-compose-animation
如何为撰写中的框制作彩虹边框动画,我看到的所有示例都是针对圆形的,并且它们使用旋转和绘制,但我真正需要的是为撰写中的框制作相同的动画。
\n谢谢
\n使用旋转但它没有 \xc2\xb4t 工作
\nThr*_*ian 12
这可以使用混合模式来完成。如果您不熟悉混合模式,您可以查看下面的答案。
Jetpack Compose 将 PorterDuffMode 应用于图像
结果
您需要先创建一个具有彩虹颜色的 Brush.sweepGradient
val gradientColors = listOf(
Color.Red,
Color.Magenta,
Color.Blue,
Color.Cyan,
Color.Green,
Color.Yellow,
Color.Red
)
Run Code Online (Sandbox Code Playgroud)
然后需要将此扫描渐变绘制为从可组合项溢出的圆形,然后我们将绘制一个具有某种颜色的边框的矩形,并在圆形上应用 BlendMode.SrcIn 以获得带有圆形画笔的矩形形状,我们以无限动画旋转
fun Modifier.drawRainbowBorder(
strokeWidth: Dp,
durationMillis: Int
) = composed {
val infiniteTransition = rememberInfiniteTransition(label = "rotation")
val angle by infiniteTransition.animateFloat(
initialValue = 0f,
targetValue = 360f,
animationSpec = infiniteRepeatable(
animation = tween(durationMillis, easing = LinearEasing),
repeatMode = RepeatMode.Restart
), label = "rotation"
)
val brush = Brush.sweepGradient(gradientColors)
Modifier.drawWithContent {
val strokeWidthPx = strokeWidth.toPx()
val width = size.width
val height = size.height
drawContent()
with(drawContext.canvas.nativeCanvas) {
val checkPoint = saveLayer(null, null)
// Destination
drawRect(
color = Color.Gray,
topLeft = Offset(strokeWidthPx / 2, strokeWidthPx / 2),
size = Size(width - strokeWidthPx, height - strokeWidthPx),
style = Stroke(strokeWidthPx)
)
// Source
rotate(angle) {
drawCircle(
brush = brush,
radius = size.width,
blendMode = BlendMode.SrcIn,
)
}
restoreToCount(checkPoint)
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果你想画画,Shape可以使用下面的功能。该函数需要使用Modifier.clip,因为Outline使用以下命令绘制小于原始形状尺寸的a
val outline = shape.createOutline(
size = Size(
size.width - strokeWidthPx,
size.height - strokeWidthPx
),
layoutDirection = layoutDirection,
density = density
)
Run Code Online (Sandbox Code Playgroud)
使用 RoundedCornerShape 以及可能使用其他自定义形状(取决于它们的对齐方式)在拐角附近创建非常小但明显的空白空间。我检查了 Modifier.border 如何防止这种情况,它检查 3 种形状类型
when (val outline = shape.createOutline(size, layoutDirection, this)) {
is Outline.Generic ->
drawGenericBorder(
borderCacheRef,
brush,
outline,
fillArea,
strokeWidthPx
)
is Outline.Rounded ->
drawRoundRectBorder(
borderCacheRef,
brush,
outline,
topLeft,
borderSize,
fillArea,
strokeWidthPx
)
is Outline.Rectangle ->
drawRectBorder(
brush,
topLeft,
borderSize,
fillArea,
strokeWidthPx
)
}
Run Code Online (Sandbox Code Playgroud)
当它是通用类型时,它会创建掩码Path,我不打算在本示例中执行此操作,但如果您不想剪辑内容,则可以实现类似的方法。
fun Modifier.drawAnimatedBorder(
strokeWidth: Dp,
shape: Shape,
brush: (Size) -> Brush = {
Brush.sweepGradient(gradientColors)
},
durationMillis: Int
) = composed {
val infiniteTransition = rememberInfiniteTransition(label = "rotation")
val angle by infiniteTransition.animateFloat(
initialValue = 0f,
targetValue = 360f,
animationSpec = infiniteRepeatable(
animation = tween(durationMillis, easing = LinearEasing),
repeatMode = RepeatMode.Restart
), label = "rotation"
)
Modifier
.clip(shape)
.drawWithCache {
val strokeWidthPx = strokeWidth.toPx()
val outline: Outline = shape.createOutline(size, layoutDirection, this)
val pathBounds = outline.bounds
onDrawWithContent {
// This is actual content of the Composable that this modifier is assigned to
drawContent()
with(drawContext.canvas.nativeCanvas) {
val checkPoint = saveLayer(null, null)
// Destination
// We draw 2 times of the stroke with since we want actual size to be inside
// bounds while the outer stroke with is clipped with Modifier.clip
// Using a maskPath with op(this, outline.path, PathOperation.Difference)
// And GenericShape can be used as Modifier.border does instead of clip
drawOutline(
outline = outline,
color = Color.Gray,
style = Stroke(strokeWidthPx * 2)
)
// Source
rotate(angle) {
drawCircle(
brush = brush(size),
radius = size.width,
blendMode = BlendMode.SrcIn,
)
}
restoreToCount(checkPoint)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
用法
@Preview
@Composable
private fun AnimatedRainbowBorderSample() {
Column(
modifier = Modifier
.fillMaxSize()
.padding(20.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Box(
modifier = Modifier
.size(140.dp, 100.dp)
.drawRainbowBorder(
strokeWidth = 4.dp,
durationMillis = 3000
),
contentAlignment = Alignment.Center
) {
Text(text = "Hello World", fontSize = 20.sp)
}
Spacer(modifier = Modifier.height(10.dp))
Box(
modifier = Modifier
.drawAnimatedBorder(
strokeWidth = 4.dp,
durationMillis = 2000,
shape = RoundedCornerShape(10.dp)
)
.padding(12.dp),
contentAlignment = Alignment.Center
) {
Text(text = "Hello World", fontSize = 20.sp)
}
Spacer(modifier = Modifier.height(10.dp))
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly) {
Box(
modifier = Modifier
.size(120.dp)
// .border(2.dp, Color.Black, RoundedCornerShape(20.dp))
.drawAnimatedBorder(
strokeWidth = 6.dp,
durationMillis = 3000,
shape = RoundedCornerShape(20.dp)
),
contentAlignment = Alignment.Center
) {
Image(
modifier = Modifier
.matchParentSize(),
painter = painterResource(id = R.drawable.avatar_1_raster),
contentDescription = null,
contentScale = ContentScale.FillBounds
)
}
Box(
modifier = Modifier
.size(120.dp)
.drawAnimatedBorder(
strokeWidth = 6.dp,
durationMillis = 3000,
shape = CircleShape
),
contentAlignment = Alignment.Center
) {
Image(
modifier = Modifier
.matchParentSize(),
painter = painterResource(id = R.drawable.avatar_2_raster),
contentDescription = null,
contentScale = ContentScale.FillBounds
)
}
}
Spacer(modifier = Modifier.height(10.dp))
Box(
modifier = Modifier
.size(80.dp)
.drawAnimatedBorder(
strokeWidth = 4.dp,
durationMillis = 2000,
shape = CircleShape
)
)
Spacer(modifier = Modifier.height(10.dp))
Box(
modifier = Modifier
.drawAnimatedBorder(
strokeWidth = 4.dp,
durationMillis = 2000,
shape = CutCornerShape(8.dp)
)
.padding(12.dp),
contentAlignment = Alignment.Center
) {
Text(text = "Hello World", fontSize = 20.sp)
}
Spacer(modifier = Modifier.height(10.dp))
Box(
modifier = Modifier
.drawAnimatedBorder(
strokeWidth = 4.dp,
durationMillis = 2000,
shape = createBubbleShape(
arrowWidth = 20f,
arrowHeight = 20f,
arrowOffset = 20f,
arrowDirection = ArrowDirection.Left
)
)
.padding(12.dp),
contentAlignment = Alignment.Center
) {
Text(text = "Hello World", fontSize = 20.sp)
}
Spacer(modifier = Modifier.height(10.dp))
Box(
modifier = Modifier
.drawAnimatedBorder(
brush = {
Brush.sweepGradient(
colors = listOf(
Color.Gray,
Color.White,
Color.Gray,
Color.White,
Color.Gray
)
)
},
strokeWidth = 4.dp,
durationMillis = 2000,
shape = RoundedCornerShape(10.dp)
)
.padding(12.dp),
contentAlignment = Alignment.Center
) {
Text(text = "Hello World", fontSize = 20.sp)
}
}
}
Run Code Online (Sandbox Code Playgroud)
额外的气泡形状
fun createBubbleShape(
arrowWidth: Float,
arrowHeight: Float,
arrowOffset: Float,
arrowDirection: ArrowDirection
): GenericShape {
return GenericShape { size: Size, layoutDirection: LayoutDirection ->
val width = size.width
val height = size.height
when (arrowDirection) {
ArrowDirection.Left -> {
moveTo(arrowWidth, arrowOffset)
lineTo(0f, arrowOffset)
lineTo(arrowWidth, arrowHeight + arrowOffset)
addRoundRect(
RoundRect(
rect = Rect(left = arrowWidth, top = 0f, right = width, bottom = height),
cornerRadius = CornerRadius(x = 20f, y = 20f)
)
)
}
ArrowDirection.Right -> {
moveTo(width - arrowWidth, arrowOffset)
lineTo(width, arrowOffset)
lineTo(width - arrowWidth, arrowHeight + arrowOffset)
addRoundRect(
RoundRect(
rect = Rect(
left = 0f,
top = 0f,
right = width - arrowWidth,
bottom = height
),
cornerRadius = CornerRadius(x = 20f, y = 20f)
)
)
}
ArrowDirection.Top -> {
moveTo(arrowOffset, arrowHeight)
lineTo(arrowOffset + arrowWidth / 2, 0f)
lineTo(arrowOffset + arrowWidth, arrowHeight)
addRoundRect(
RoundRect(
rect = Rect(
left = 0f,
top = arrowHeight,
right = width,
bottom = height
),
cornerRadius = CornerRadius(x = 20f, y = 20f)
)
)
}
else -> {
moveTo(arrowOffset, height - arrowHeight)
lineTo(arrowOffset + arrowWidth / 2, height)
lineTo(arrowOffset + arrowWidth, height - arrowHeight)
addRoundRect(
RoundRect(
rect = Rect(
left = 0f,
top = 0f,
right = width,
bottom = height - arrowHeight
),
cornerRadius = CornerRadius(x = 20f, y = 20f)
)
)
}
}
}
}
enum class ArrowDirection {
Left, Right, Top, Bottom
}
Run Code Online (Sandbox Code Playgroud)
本教程中提供完整示例,包含资源和其他内容
| 归档时间: |
|
| 查看次数: |
1337 次 |
| 最近记录: |