Reputation: 199
I have defined approx. 20 GenericShape from SVG path and I wanted to expose them as clickable, independents but consistant (relatively positionned) buttons.
Each GenericShape is define as follow:
val shape_0 = GenericShape { size, layoutDirection ->
val width: Float = size.width // not used here
val height: Float = size.height // not used here
moveTo(147.5f, 320f)
cubicTo(150f, 335f, 170f, 335f, 172.5f, 320f)
cubicTo(180f, 245f, 186f, 213f, 175f, 180f)
cubicTo(165f, 140f, 155f, 140f, 145f, 180f)
cubicTo(134f, 213f, 140f, 245f, 147.5f, 320f)
close()
}
And each button like this:
Button(
colors = ButtonDefaults.buttonColors(backgroundColor = Color.Red, ),
border = BorderStroke(1.dp, Color.Black),
onClick = {},
shape = shape_0
) {}
for a single button, it look like this:
First of all, Border are not applied consistently, whatever the elevation (any advice appreciated).
But most of all, If I try to put all buttons (all of them correctly positioned, in absolute) in a Box and try to fillMaxSize like this:
Box(
// =============> Modifier:
modifier = Modifier
.background(Color.Cyan)
.fillMaxSize()
) {
val shape_0 = GenericShape { size, layoutDirection ->
moveTo(147.5f, 320f)
...same path...
close()
}
Button(
// =============> Modifier:
modifier = Modifier.fillMaxSize(),
colors = ButtonDefaults.buttonColors(backgroundColor = Color.Red),
border = BorderStroke(1.dp, Color.Black),
onClick = {},
shape = shape_0
) {}
val shape_1 = GenericShape { size, layoutDirection ->
moveTo(155f, 140f)
cubicTo(115f, 70f, 145f, 70f, 160f, 70f)
cubicTo(175f, 70f, 205f, 70f, 165f, 140f)
quadraticBezierTo(160f, 145f, 155f, 140f)
close()
}
Button(
// =============> Modifier:
modifier = Modifier.fillMaxSize(),
colors = ButtonDefaults.buttonColors(backgroundColor = Color.Blue),
border = BorderStroke(1.dp, Color.Black),
onClick = {},
shape = shape_1
) {}
// and so on for the next 18 shapes + buttons
}
It does not change anything for any buttons size (except the Cyan background of course):
two button defined with shapes not expected size
I would really appreciate avoid having to readjust the path depending on width and height of parent as I need to adjust hundreds of parameters with the correct ratio.
Is it possible to adjust the size of all buttons in the same Box (or other component) to adjust them all together?
I have tried to use a Surface, to play with modifier or clipToBounds but the only change was that from time to time, buttons behaviours were broken
Upvotes: 1
Views: 908
Reputation: 67218
You need to draw into Path instead of shape and get Outline from path. Paths can be scaled using matrix from their intrinsic sizes to Composable size you want to draw inside.
You can refer this answer for details. Clipping to this shape makes all the size modifiers ineffective
val path = Path().apply {
// Add your drawings here
// cubicTo()
// quadraticBezierTo()
}
val pathSize = path.getBounds().size
val shape = object : Shape {
override fun createOutline(
size: Size,
layoutDirection: LayoutDirection,
density: Density
): Outline {
val matrix = android.graphics.Matrix()
matrix.postScale(
size.width / pathSize.width, size.height / pathSize.height
)
path.asAndroidPath().transform(matrix)
return Outline.Generic(path)
}
}
Upvotes: 2