使用可绘制图案作为按钮背景

Use drawable pattern as button background

我正在尝试将按钮背景从纯色更改为具有透明背景的可绘制图像,以确保我可以看到图案

我搬到了喷气背包,所以我创造了

Button(onClick = { /*TODO*/ },
            colors = ButtonDefaults.buttonColors(
                backgroundColor = colorResource(id = R.color.gainsboro_00)),
            modifier = Modifier
                .fillMaxWidth()
                .height(60.dp),
            shape = RoundedCornerShape(0.dp)) {
            Text(text = stringResource(id = R.string.login),
                color = colorResource(id = R.color.gainsboro_05),
                style = MaterialTheme.typography.body1)
        }

此按钮的背景为灰色。

我想应用下面的可绘制对象:

<?xml version="1.0" encoding="UTF-8" ?>
<bitmap
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/pattern_stripe_loose_gainsboro_05"
    android:tileMode="repeat"/>

作为背景而不是彩色背景,并显示图案。上面的xml只是重复一个模式来创建背景

所以我希望这样:

使用模式:

当使用传统的布局方式时,它可以工作,但我不能让它在 Jetpack 上工作

有什么想法吗?

为什么不直接创建一个具有该背景的框并放置文本,同时使整个框可点击?该框将充当整个按钮。我的意思是这就是按钮的本质,不是吗?一个包含一些文字的盒子?哦,如果你想不出一种方法来将 drawable 设置为你的 Box 上的背景,只需使用 Image 之类的东西结合 fillMaxSize() 修饰符。

类似

Box(Modifier.fillMaxWidth().height(...), 
 horizontalArrangement = Arrangement.CenterHorizontally){
 Image(painter = painterResource(R.drawable.b_pattern), 
contentDescription = "Lorem Ipsum")
 Text(modifier = Modifier.align(Alignment.CenterVertically), 
 text = "Lorem Ipsum")
}

试试看,请告诉我。

Compose 还没有这样的功能。您可以在 issue tracker.

上创建功能请求

在此实现之前,您可以创建一个绘制大量图像的纯 Compose 解决方案,但我认为当 ImageView 已经由工程师优化时,这样做没有意义。在这种情况下,您可以使用 AndroidView 与旧视图互操作。

@Composable
fun TileAndroidImage(
    @DrawableRes drawableId: Int,
    contentDescription: String,
    modifier: Modifier = Modifier,
) {
    val context = LocalContext.current
    val drawable = remember(drawableId) {
        BitmapDrawable(
            context.resources,
            BitmapFactory.decodeResource(
                context.resources,
                drawableId
            )
        ).apply {
            tileModeX = Shader.TileMode.REPEAT
            tileModeY = Shader.TileMode.REPEAT
        }
    }
    AndroidView(
        factory = {
            ImageView(it)
        },
        update = { imageView ->
            imageView.background = drawable
        },
        modifier = modifier
            .semantics {
                this.contentDescription = contentDescription
                role = Role.Image
            }
    )
}

下一部分,将它放在按钮的背景中。在 compose 中,我们使用容器来做到这一点。您可以创建您的 TiledButton。我将零填充传递给容器按钮并手动添加实际填充,这样它就不会影响背景:

@Composable
fun TiledButton(
    onClick: () -> Unit,
    @DrawableRes backgroundDrawableId: Int,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    shape: Shape = MaterialTheme.shapes.small,
    border: BorderStroke? = null,
    contentColor: Color = MaterialTheme.colors.primary,
    contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
    content: @Composable RowScope.() -> Unit
) {
    Button(
        onClick = onClick,
        contentPadding = PaddingValues(0.dp),
        enabled = enabled,
        shape = shape,
        border = border,
        elevation = null,
        colors = ButtonDefaults.buttonColors(
            backgroundColor = Color.Transparent,
            contentColor = contentColor,
            disabledBackgroundColor = Color.Transparent,
            disabledContentColor = contentColor.copy(alpha = ContentAlpha.disabled),
        ),
        modifier = modifier
    ) {
        Box(
            contentAlignment = Alignment.Center,
        ) {
            TileAndroidImage(
                drawableId = backgroundDrawableId,
                contentDescription = "...",
                modifier = Modifier.matchParentSize()
            )
            Row(
                horizontalArrangement = Arrangement.Center,
                verticalAlignment = Alignment.CenterVertically,
                modifier = Modifier.padding(contentPadding),
                content = content,
            )
        }
    }
}

用法:

TiledButton(
    onClick = { /*TODO*/ },
    backgroundDrawableId = R.drawable.tile,
    border = BorderStroke(1.dp, Color.Blue),
) {
    Text("Apple")
}