带有渐变背景的Jetpack Compose按钮?

是否可以创建具有渐变背景的按钮?

@Composable
fun GradientButtonExample() {

    val horizontalGradientBrush = Brush.horizontalGradient(
        colors = listOf(
            Color(0xffF57F17),
            Color(0xffFFEE58),
            Color(0xffFFF9C4)
        )
    )

    val verticalGradientBrush = Brush.verticalGradient(
        colors = listOf(
            Color(0xff4E342E),
            Color(0xff8D6E63),
            Color(0xffD7CCC8)
        )
    )

    Button(onClick = {}) {
        Text(
            text = "Horizontal Gradient",
            modifier = Modifier
                .background(brush = horizontalGradientBrush)
        )
    }

    Button(onClick = {}) {
        Text(
            text = "Vertical Gradient",
            modifier = Modifier
                .background(brush = verticalGradientBrush)
        )
    }
}

Textbackground(brush) 添加渐变会在 ButtonText 之间留下一个边距。当我用 modifier.background(brush = horizontalGradientBrush) 设置按钮的背景时, Button 是用原色绘制的,基本上没有任何反应。是否可以使用渐变颜色设置 Button 的背景,而不是其他组件?

stack overflow Jetpack Compose Button with gradient background?
原文答案
author avatar

接受的答案

撰写 1.0.0-alpha10

你可以这样做:

@Composable
fun GradientButton(
    text: String,
    gradient : Brush,
    modifier: Modifier = Modifier,
    onClick: () -> Unit = { },
) {
    Button(
        modifier = modifier,
        colors = ButtonDefaults.buttonColors(backgroundColor = Color.Transparent),
        contentPadding = PaddingValues(),
        onClick = { onClick() },
    ) {
        Box(
            modifier = Modifier
                .background(gradient)
                .then(modifier),
            contentAlignment = Alignment.Center,
        ) {
            Text(text = text)
        }
    }
}

使用示例:

@Composable
private fun Content() {

val gradient =
    Brush.horizontalGradient(listOf(Color(0xFF28D8A3), Color(0xFF00BEB2)))

    Column {
        GradientButton(
            text = "Gradient Button - Max Width",
            gradient = gradient,
            modifier = Modifier
                .fillMaxWidth()
                .padding(horizontal = 16.dp, vertical = 8.dp)
        )
        GradientButton(
            text = "Gradient Button - Wrap Width",
            gradient = gradient,
            modifier = Modifier
                .wrapContentWidth()
                .padding(horizontal = 16.dp, vertical = 8.dp)
        )
    }
}

结果样本:

enter image description here


答案:

作者头像

实际上,您不需要按钮...您可以使用简单的 Text 来实现此结果...

Text(
    text = "Click Me",
    style = TextStyle(color = Color.White),
    modifier = Modifier
        .clickable(onClick = {})
        .background(
            Brush.verticalGradient(
                colors = listOf(
                    Color.Blue,
                    Color.Green
                )
            ),
            shape = RoundedCornerShape(4.dp)
        )
        .padding(horizontal = 16.dp, vertical = 8.dp),
)
作者头像

最灵活的方法是将 TextButtonModifier.drawBehind() 一起使用。

TextButton 本身不绘制任何背景,但其行为类似于按钮。

Modifier.drawBehind() 让您可以完全控制要绘制的内容:渐变、几何形状等。

TextButton(modifier = Modifier.drawBehind { }) {
  Text("Help")
}
作者头像

Jetpack Compose 在创建 Button 或任何其他组件方面非常灵活,基本上 ButtonRow 内的 Surface 内容填充为

private val ButtonHorizontalPadding = 16.dp
private val ButtonVerticalPadding = 8.dp

因此,可以将填充设置为 0,并在为 Text 设置渐变背景后设置填充,如下面的代码片段所示。

Button(contentPadding = PaddingValues(0.dp), onClick = {}) {
    Text(
        text = "Vertical Gradient",
        modifier = Modifier
            .preferredHeight(ButtonDefaults.MinHeight)
            .align(Alignment.CenterVertically)
            .background(brush = verticalGradientBrush)
            .padding(8.dp)
    )
}
作者头像

基于可组合所有参数和自定义选项的默认 Button 的实现。

@OptIn(ExperimentalMaterialApi::class)
@Composable
fun GradientButton(
    onClick: () -> Unit,
    gradient: Brush,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    elevation: ButtonElevation? = ButtonDefaults.elevation(),
    shape: Shape = MaterialTheme.shapes.small,
    border: BorderStroke? = null,
    contentColor: Color = MaterialTheme.colors.onSurface,
    disabledContentColor: Color = MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.disabled),
    disabledBackgroundColor: Color = MaterialTheme.colors.onSurface.copy(alpha = 0.12f)
        .compositeOver(MaterialTheme.colors.surface),
    contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
    content: @Composable RowScope.() -> Unit
) {
    val actualElevation = elevation?.elevation(enabled, interactionSource)?.value ?: 0.dp
    val actualContentColor = if (enabled) contentColor else disabledContentColor
    val background = if (enabled) {
        Modifier.background(brush = gradient)
    } else {
        Modifier.background(color = disabledBackgroundColor)
    }

    Surface(
        modifier = modifier
            .shadow(actualElevation, shape, true)
            .then(background),
        shape = shape,
        color = Color.Transparent,
        contentColor = actualContentColor.copy(alpha = 1f),
        border = border,
        elevation = 0.dp,
        onClick = onClick,
        enabled = enabled,
        role = Role.Button,
        interactionSource = interactionSource,
        indication = rememberRipple()
    ) {
        CompositionLocalProvider(LocalContentAlpha provides actualContentColor.alpha) {
            ProvideTextStyle(
                value = MaterialTheme.typography.button
            ) {
                Row(
                    Modifier
                        .defaultMinSize(
                            minWidth = ButtonDefaults.MinWidth,
                            minHeight = ButtonDefaults.MinHeight
                        )
                        .padding(contentPadding),
                    horizontalArrangement = Arrangement.Center,
                    verticalAlignment = Alignment.CenterVertically,
                    content = content
                )
            }
        }
    }
}

Example screenshot with and without Modifier.fillMaxWidth

作者头像

渐变button文件就像:

@Composable
fun GradientButton(
    text: String,
    textColor: Color,
    gradient: Brush,
    onClick: () -> Unit
) {
    Button(
        colors = ButtonDefaults.buttonColors(
            backgroundColor = Color.Transparent
        ),
        contentPadding = PaddingValues(),
        onClick = { onClick() })
    {
        Box(
            modifier = Modifier
                .background(gradient)
                .padding(horizontal = 16.dp, vertical = 8.dp),
            contentAlignment = Alignment.Center
        ) {
            Text(text = text, color = textColor)
        }
    }
}

mainActivity.kt文件

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            // Row is used for align the buttons in center of screen
            Row(
                modifier = Modifier.fillMaxSize(),
                horizontalArrangement = Arrangement.Center,
                verticalAlignment = Alignment.CenterVertically
            ) {
                // this is the first button
                GradientButton(
                    text = "Button1", textColor = Color.Black, gradient = Brush.horizontalGradient(
                        colors = listOf(
                            c1,
                            c2,
                            c1
                        )
                    )
                ) {}

                // Spacer is used to give the space between two buttons
                Spacer(modifier = Modifier.width(10.dp))

                // This is second button
                GradientButton(
                    text = "Button2", textColor = Color.Black, gradient = Brush.horizontalGradient(
                        colors = listOf(
                            c3,
                            c4,
                            c3
                        )
                    )
                ) {}

            }
        }
    }

}

color.kt文件

[val c1 = Color(0xFFE9F190)
val c2 = Color(0xFFF5DB0B)

val c3 = Color(0xFFF79F1E)
val c4 = Color(0xFFFF5722)

输出:

[Output ](https://i.stack.imgur.com/kzx9q.png

作者头像

我创建了一个框作为可点击元素的背景。然后给它添加修饰符.background,画笔+水平渐变,作为参数。

                  Box(contentAlignment = Alignment.Center,
                    modifier = Modifier
                        .background(
                            brush = Brush.horizontalGradient(
                                listOf(Color.Red, Color.Green, Color.Blue),
                                10.0f,
                                20.0f
                            ), shape = CircleShape
                        )