Reputation: 37721
I mean a Drawable generated dynamically, not a file from res/drawable.
I tried setting it as a background of the modifier, but it doesn't accept a Drawable
instance object. In Java, it was done like this: layout.setBackground(bg.getDrawable())
.
In this case, I have a LazyColumn
, and it haves some items. Ok, I need the drawable to be the background of the LazyColumn
. The background must fit the height and the width of the LazyColumn
I thought a possibility is to do it using a Box
, placing a Image
with the Drawable
inside the Box
, and over it, the LazyColumn
, but the drawable must be the exact size of the LazyColumn
.
What can I try next?
Upvotes: -1
Views: 91
Reputation: 4276
You could use drawBehind
modifier which provides access to the the underlying Canvas with DrawScope.drawIntoCanvas
. It's important to also add clipToBounds
to avoid drawing outside of the element.
.clipToBounds()
.drawBehind {
drawIntoCanvas { canvas ->
drawable.bounds = canvas.nativeCanvas.clipBounds
drawable.draw(canvas.nativeCanvas)
}
}
Full example:
@Composable
fun DrawableBackground() {
val drawable = object : Drawable() {
val paint: Paint = Paint().apply { setARGB(255, 0, 255, 0) }
override fun draw(canvas: Canvas) {
val top = bounds.top.toFloat()
val bottom = bounds.bottom.toFloat()
val left = bounds.left.toFloat()
val right = bounds.right.toFloat()
canvas.drawLine(right, top, left, bottom, paint)
canvas.drawLine(left, top, right, bottom, paint)
}
override fun setAlpha(alpha: Int) {}
override fun setColorFilter(colorFilter: ColorFilter?) {}
override fun getOpacity(): Int = PixelFormat.OPAQUE
}
Column {
var items by remember { mutableIntStateOf(5) }
Row {
Button(onClick = { ++items }) { Text("+") }
Button(onClick = { --items }) { Text("-") }
}
LazyColumn(modifier = Modifier
.fillMaxWidth()
.clipToBounds()
.drawBehind {
drawIntoCanvas { canvas ->
drawable.bounds = canvas.nativeCanvas.clipBounds
drawable.draw(canvas.nativeCanvas)
}
}
) {
items(items) { Text("Item $it") }
}
}
}
Upvotes: 1
Reputation: 2214
To set a dynamically generated drawable as the background, you'll have to convert that drawable into a format that compose can use, such as a Bitmap. Then, you can use an Image composable with a BitmapPainter.
Here is the sample implementation: Updated
// convert drawable to bitmap
fun drawableToBitmap(drawable: Drawable, width: Int, height: Int): Bitmap {
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, width, height)
drawable.draw(canvas)
return bitmap
}
@Composable
fun LazyColumnWithDynamicBg(
drawable: Drawable,
items: List<String>
) {
var contentHeight by remember {
mutableStateOf(20.dp)
}
var contentWidth by remember {
mutableStateOf(20.dp)
}
Box(modifier = Modifier.wrapContentSize(), contentAlignment = Alignment.TopCenter) {
// get bitmap
val bitmap = drawableToBitmap(drawable, width = contentWidth.value.toInt(), height = contentHeight.value.toInt()) // considering full screen size
Image(
painter = BitmapPainter(bitmap.asImageBitmap()),
contentDescription = null,
modifier = Modifier.matchParentSize()
)
LazyColumn(
modifier = Modifier.fillMaxWidth().wrapContentHeight().onGloballyPositioned {
contentHeight = it.size.height.dp
contentWidth = it.size.width.dp
}
) {
items(items) { item ->
Text(
text = item,
modifier = Modifier.padding(16.dp),
color = Color.White,
fontWeight = FontWeight.Bold
)
}
}
}
}
@Preview
@Composable
fun PreviewComposable() {
// a simple dynamic Drawable for sample
val dynamicDrawable = object : Drawable() {
override fun draw(canvas: Canvas) {
canvas.drawColor(android.graphics.Color.CYAN) // Example: fill the background with cyan color
}
override fun setAlpha(alpha: Int) {}
override fun getOpacity(): Int = android.graphics.PixelFormat.OPAQUE
override fun setColorFilter(colorFilter: android.graphics.ColorFilter?) {}
}
val dummyItems = List(3) { "Item ${it + 1}" }
LazyColumnWithDynamicBg(
drawable = dynamicDrawable,
items = dummyItems
)
}
Output:
Upvotes: 0