I want to draw this shape in jetpack compose, anybody has idea how we can achieve this?
You can simply draw a shape inside a Box.
Something like:
Box(
Modifier
.fillMaxWidth()
.height(200.dp)
.background(Color.DarkGray)
.padding(10.dp)
.background(Red)
) {
Canvas(
modifier = Modifier
.fillMaxSize()
) {
val canvasWidth = size.width
val arcHeight = 200f
drawArc(
color = Color.DarkGray,
startAngle = 0f,
sweepAngle = 180f,
useCenter = false,
topLeft = Offset(0f, -arcHeight/2),
size = Size(canvasWidth, arcHeight)
)
}
}
Related
I'm trying to add a left/start vertical border to view (Column), Not able to get the solution. as of now was trying to achieve using a divider inside the column it also need a height, but it depends on the contents inside the column, sometime it may grow.
Column(modifier = Modifier.padding(start = 34.dp)) {
Divider(
color = Color.Red,
modifier = Modifier
.height(100.dp)
.padding(end = 34.dp).width(2.dp)
)
You can use the drawWithCache modifier using the drawLine function.
Something like:
Column(modifier =
Modifier
.padding(start = 34.dp)
.size(100.dp, 75.dp)
.drawWithCache {
onDrawWithContent {
// draw behind the content the vertical line on the left
drawLine(
color = Color.Red,
start = Offset.Zero,
end = Offset(0f, this.size.height),
strokeWidth= 1f
)
// draw the content
drawContent()
}
}
){
//...content
}
If you want to use a Divider you can use fillMaxHeight() applying an intrinsic measurements to its parent container.
Something like:
Row(modifier = Modifier.height(IntrinsicSize.Min)) {
Divider(
color = Color.Red,
modifier = Modifier
.fillMaxHeight() //important
.width(2.dp)
)
Box(Modifier.fillMaxWidth().height(100.dp).background(Yellow))
}
You can achive this with Modifier.drawBehind and drawLine
Code
TextButton(
onClick = {
//Click Functions
},
modifier = Modifier.drawBehind {
val strokeWidth = 1 * density
//Draw line function for left border
drawLine(
Color.LightGray,
Offset(0f, strokeWidth),
Offset(0f, size.height),
strokeWidth
)
}
)
{
Text("Left Border")
}
Output
Descript
I want to draw a line at the compose with the compose canvas inside a compose widget,but it's just show at the preview!
If just copy the canvas part code,it can Correct display!
The compose code
Card(
elevation = 6.dp,
shape = RoundedCornerShape(15.dp),
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 12.dp, vertical = 8.dp)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.background(color = backgroundColor),
) {
AsyncImage(modifier = Modifier
.height(180.dp)
.width(120.dp)
.padding(12.dp)
... )
Row(
modifier = Modifier.fillMaxSize()
) {
Column(
modifier = Modifier
.fillMaxHeight()
.weight(0.7f)
) {
...
}
Canvas(
modifier = Modifier
.weight(0.3f)
.fillMaxHeight()
.padding(start = 6.dp)
) {
// NOT SHOW !!!
drawLine(
color = Color.White,
start = Offset(0f, 0f),
end = Offset(0f, size.height),
strokeWidth = 2f,
pathEffect = PathEffect.dashPathEffect(floatArrayOf(20f, 20f), 0f),
)
}
}
}
}
SceenShot
It might be an issue related to size of Canvas. Check if it doesn't return width or height zero in your Composable.
In Jetpack Compose Canvas is nothing other than Spacer with Modifier.drawBehind{}
#Composable
fun Canvas(modifier: Modifier, onDraw: DrawScope.() -> Unit) =
Spacer(modifier.drawBehind(onDraw))
Which you can use Modifier.drawWithContent{} on your own Composable instead using Box and Canvas Composabble
you can use Modifier.drawWithContent for instance such as
Column {
val drawModifier = Modifier
.drawWithContent {
drawContent()
drawLine(
color = Color.White,
start = Offset(size.width*.8f, 0f),
end = Offset(size.width*.8f, size.height),
strokeWidth = 2f,
pathEffect = PathEffect.dashPathEffect(floatArrayOf(20f, 20f), 0f),
)
}
.width(200.dp)
.height(100.dp)
Box(modifier = drawModifier.background(Color.Red)) {
Text("Hello World")
}
}
I am trying to create a semicircle speed progress bar in Jetpack Compose. Unless the view is square the semicircle will not look as expected, if I use 1:2 width: height it will be flattened. I want a Composable representing half of the circle where I don't have unusable bottom half of the view.
Box(
modifier = modifier
.background(Color.Red)
) {
Canvas(modifier = Modifier.size(300.dp)) {
drawArc(
color = Color.LightGray,
-180f,
180f,
useCenter = false,
style = Stroke(8.dp.toPx(), cap = StrokeCap.Round)
)
}
Text(
modifier = Modifier.align(alignment = Alignment.Center),
text = "20 Mbps",
color = Color.White,
fontSize = 20.sp
)
}
The expected outcome would be a reusable semicircle composable with a height of the actual semicircle so I can easily position other content against it. The expected view size is marked by a dotted green line.
As i mentioned in comments arc uses rectangle if you want a semi arc that covers whole hight just double the height you draw arc with
#Composable
private fun ArcComposable(modifier: Modifier) {
Box(
modifier = modifier
.background(Color.Red)
) {
Canvas(modifier = Modifier
.size(300.dp)
.clipToBounds()) {
drawArc(
color = Color.LightGray,
-180f,
180f,
useCenter = false,
size = Size(size.width, size.height * 2),
style = Stroke(8.dp.toPx(), cap = StrokeCap.Round)
)
}
Text(
modifier = Modifier.align(alignment = Alignment.Center),
text = "20 Mbps",
color = Color.White,
fontSize = 20.sp
)
}
}
I added Modifier.clipToBounds() because of strokeCap round which is added to length of the line by default. You can just reduce size and height few px to match inside the canvas. Canvas by default even if you don't set a modifier with size it draws anything out of its bounds unless you use Modifier.clipToBounds()
private fun ArcComposable(modifier: Modifier) {
Box(
modifier = modifier
.background(Color.Red)
) {
Canvas(
modifier = Modifier
.size(300.dp)
// .clipToBounds()
) {
drawArc(
color = Color.LightGray,
-180f,
180f,
useCenter = false,
topLeft = Offset(4.dp.toPx(), 6.dp.toPx()),
size = Size(size.width - 8.dp.toPx(), size.height * 2 - 20.dp.toPx()),
style = Stroke(8.dp.toPx(), cap = StrokeCap.Round)
)
}
Text(
modifier = Modifier.align(alignment = Alignment.Center),
text = "20 Mbps",
color = Color.White,
fontSize = 20.sp
)
}
}
Im just learning jetpack compose, an I got a problem to make a border..
so I wanna make a border just in partial side like border bottom, border top etc. only
so how to make like that
Row(horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp)
.defaultMinSize(minHeight = 56.dp)) {}
thanks
You can try this code & draw lines,
Row(
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically,
modifier =
Modifier
.fillMaxWidth()
.wrapContentHeight()
.wrapContentWidth()
.padding(horizontal = 16.dp, vertical = 8.dp)
.drawBehind {
val strokeWidth = 2f
val x = size.width - strokeWidth
val y = size.height - strokeWidth
//top line
drawLine(
color = Color.Green,
start = Offset(0f, 0f), //(0,0) at top-left point of the box
end = Offset(x, 0f), //top-right point of the box
strokeWidth = strokeWidth
)
//left line
drawLine(
color = Color.Magenta,
start = Offset(0f, 0f), //(0,0) at top-left point of the box
end = Offset(0f, y),//bottom-left point of the box
strokeWidth = strokeWidth
)
//right line
drawLine(
color = Color.Red,
start = Offset(x, 0f),// top-right point of the box
end = Offset(x, y),// bottom-right point of the box
strokeWidth = strokeWidth
)
//bottom line
drawLine(
color = Color.Cyan,
start = Offset(0f, y),// bottom-left point of the box
end = Offset(x, y),// bottom-right point of the box
strokeWidth = strokeWidth
)
}) {
Column(modifier = Modifier.padding(2.dp)) {
Text(text = "testing", color = Color.Black)
Text(text = "another testing")
}
}
I am learning Jetpack Compose and would like to build something like this
I have tried using Box layout by stacking CircularProgressIndicator but requires hardcoding the circle sizes. I want the rings to be size agnostic.
How do I achieve this using Compose?
You can try to do with Canvas. I did this and could give you a start point to achieve what you want...
#Composable
fun DrawGradientCircles() {
Canvas(
modifier = Modifier
.size(300.dp)
.background(Color.Gray)
) {
drawCircle(
brush = Brush.sweepGradient(listOf(Color.Magenta, Color.Red)),
radius = 300f,
style = Stroke(90f)
)
drawCircle(
brush = Brush.sweepGradient(listOf(Color.Green, Color.Yellow)),
radius = 200f,
style = Stroke(90f)
)
drawCircle(
brush = Brush.sweepGradient(listOf(Color.Cyan, Color.Blue)),
radius = 100f,
style = Stroke(90f)
)
}
}
This is the result:
EDIT: I posted an updated version here:
https://gist.github.com/nglauber/e947dacf50155fb72408e83f6595e430
Hope it helps.
I was able to accomplish it using CircularProgressIndicator
#Composable
fun ringView(){
var sz by remember { mutableStateOf(Size.Zero)}
Box(
Modifier
.aspectRatio(1f)
.fillMaxSize()
.background(Color.Blue)
.onGloballyPositioned { coordinates ->
sz = coordinates.size.toSize()
}
, contentAlignment = Alignment.Center){
Box(Modifier.aspectRatio(1f), contentAlignment = Alignment.Center){
Text(text = pxToDp(sz.height.toInt()).toString())
CircularProgressIndicator(progress = 0.9F, Modifier.size(pxToDp(sz.width.toInt()).dp), strokeWidth = (pxToDp(sz.width.toInt())/15).dp,color = Color.Green)
CircularProgressIndicator(progress = 0.9F, Modifier.size((pxToDp(sz.width.toInt())-(2*(pxToDp(sz.width.toInt())/15))).dp), strokeWidth = (pxToDp(sz.width.toInt())/15).dp, color = Color.Black )
CircularProgressIndicator(progress = 0.9F, Modifier.size((pxToDp(sz.width.toInt())-(4*(pxToDp(sz.width.toInt())/15))).dp), strokeWidth = (pxToDp(sz.width.toInt())/15).dp, color = Color.Gray )
CircularProgressIndicator(progress = 0.9F, Modifier.size((pxToDp(sz.width.toInt())-(6*(pxToDp(sz.width.toInt())/15))).dp), strokeWidth = (pxToDp(sz.width.toInt())/15).dp, color = Color.Cyan )
CircularProgressIndicator(progress = 0.9F, Modifier.size((pxToDp(sz.width.toInt())-(8*(pxToDp(sz.width.toInt())/15))).dp), strokeWidth = (pxToDp(sz.width.toInt())/15).dp, color = Color.Magenta )
}
}
}
fun pxToDp(px: Int): Int {
return (px / Resources.getSystem().displayMetrics.density).toInt()
}