I have this composable :
#Composable
fun MyApp() {
var isSelected by remember { mutableStateOf(false) }
val backgroundColor by animateColorAsState(if (isSelected) Color.Red else Color.Transparent)
Column(
modifier = Modifier
.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "Hello",
modifier = Modifier.background(color = backgroundColor)
.clickable(onClick = { isSelected = !isSelected })
.width(100.dp)
.height(40.dp),
textAlign = TextAlign.Center,
)
}
}
I expect TextAlign.Center centerlize Text of TextView, but it will be just centerlize horizontally. How can I make it center vertically as well?
TextAlign.Center can only center your content horizontally.
To center it vertically you need to place it inside a container, like Box, and apply content alignment and your size modifiers to this container:
Column(
modifier = Modifier
.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.width(100.dp)
.height(40.dp)
.background(color = backgroundColor)
.clickable(onClick = { isSelected = !isSelected })
) {
Text(
text = "Hello",
textAlign = TextAlign.Center
)
}
}
Also I'd say that generally this is a bad practice, because when user increase text size in the phone accessibility settings, your Text may no longer fit your box. Consider using padding instead.
Related
I have some Column with Icon and Text inside. Column is wrap the size of Text but i want to Column wrap Icon and long text move to another line
How It's looks now
How I want it to look like
#Composable
fun ServiceItem(
service: Service,
onItemClick: (service: Service) -> Unit
) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Card(
modifier = Modifier.padding(horizontal = 16.dp),
shape = RoundedCornerShape(itemBackgroundCornerSize),
backgroundColor = colorResource(id = R.color.gray)
) {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.size(itemSize)
.clickable(onClick = {
onItemClick(service)
})
) {
Image(
painter = rememberAsyncImagePainter(service.imageUrl),
contentDescription = null,
modifier = Modifier.padding(iconPadding)
)
}
}
Text(
text = service.title,
textAlign = TextAlign.Center,
style = itemTitleTextDefaultStyle(),
modifier = Modifier.padding(top = textTopPadding)
)
}
}
Why the width of red circle equal to with of gray area?
Here are my code and result, Hope someone answers.
#Preview
#Composable
fun testContent() {
Scaffold { paddingValues ->
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Column(
modifier = Modifier
.fillMaxWidth(1f)
.aspectRatio(0.8f)
.clip(RoundedCornerShape(size = 6.dp))
.background(Color.Gray)
.fillMaxWidth(0.8f)
.aspectRatio(ratio = 1f)
.clip(CircleShape)
.background(Color.Red),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
text = "I am text",
color = Color.White,
)
Text(
text = "I am text too",
color = Color.White,
)
}
}
}
}
result is here: https://i.stack.imgur.com/qUUNM.png
Because in Column Composable (which draws/clips red circle) you have a parameter Modifier.fillMaxWidth(1f), thus it takes the maximum width of the parent
1f is is a fraction parameter and if you make it less it will take less width
I want to split my screen in half horizontally in Jetpack Compose like this:
#Composable
fun Splash(alpha: Float) {
val configuration = LocalConfiguration.current
val screenHeight = configuration.screenHeightDp.dp
val screenWidth = configuration.screenWidthDp.dp
val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.cat2))
Box(
modifier = Modifier
.background(Blue)
.height(screenHeight / 2)
.padding(8.dp),
contentAlignment = Alignment.TopCenter
) {
Column() {
Text(text = "Example", fontSize = 44.sp)
}
}
Box(
modifier = Modifier
.background(Red)
.height(screenHeight / 2)
.padding(8.dp),
contentAlignment = Alignment.BottomCenter
){
Column {
Text(text = "Example", textAlign = TextAlign.End, color = Grey, fontSize = 12.sp)
}
}
}
I can get screen height with LocalConfiguration.current in dp and I set my top box and bottom box alignments as Alignment.TopCenter and Alignment.BottomCenter respectively but it didn't work. Second box(Red one) stays on top of the blue one.
You can wrap your Boxes with a Column and set Modifier.weight(1f) for each box to set both of them at same height with
#Composable
fun Splash() {
Column(modifier =Modifier.fillMaxSize()) {
Box(
modifier = Modifier
.fillMaxWidth()
.background(Blue)
.weight(1f)
.padding(8.dp),
contentAlignment = Alignment.TopCenter
) {
Column() {
Text(text = "Example", fontSize = 44.sp)
}
}
Box(
modifier = Modifier
.fillMaxWidth()
.background(Red)
.weight(1f)
.padding(8.dp),
contentAlignment = Alignment.Center
){
Column {
Text(text = "Example", textAlign = TextAlign.End, color = DarkGray, fontSize = 12.sp)
}
}
}
}
or wrap with a BoxWithConstraints which returns Contraints, maxWidth, maxHeight and use Modifier.align to one Box to top and other one to Bottom. BoxWithConstraints is useful for getting measurement parameters and set them as children Modifiers.
#Composable
fun Splash2() {
BoxWithConstraints(modifier = Modifier.fillMaxSize()) {
Box(
modifier = Modifier
.fillMaxWidth()
.background(Blue)
.height(maxHeight/2)
.align(Alignment.TopStart)
.padding(8.dp),
contentAlignment = Alignment.TopCenter
) {
Column() {
Text(text = "Example", fontSize = 44.sp)
}
}
Box(
modifier = Modifier
.fillMaxWidth()
.background(Red)
.align(Alignment.BottomStart)
.height(maxHeight/2)
.padding(8.dp),
contentAlignment = Alignment.Center
){
Column {
Text(text = "Example", textAlign = TextAlign.End, color = DarkGray, fontSize = 12.sp)
}
}
}
}
The simplest way to set a height equal to the half-screen height is with a fractional in the modifier.
Column(
modifier = Modifier
.padding(10.dp)
.fillMaxHeight(0.5f)
){ //Content}
The best way to implement your image is this way:
Column(
Modifier
.fillMaxSize()
.padding(8.dp)
) {
Row(
Modifier
.fillMaxWidth()
.weight(1f)
.background(Blue),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center,
) {
Text(text = "Example", fontSize = 44.sp)
}
Row(
Modifier
.fillMaxWidth()
.weight(1f)
.background(Red),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center,
) {
Text(text = "Example", fontSize = 44.sp)
}
}
My Problem:
I want to place my Text() content to center of the page in Scaffold.
I tried "textAlign = TextAlign.Center" - It align the text in horizontal area alone. Not align the text in vertical area.
My code:
#Composable
fun ScaffoldWithTopBar() {
Scaffold(
topBar = {
TopAppBar(
title = {
Text(text = "Top App Bar")
},
navigationIcon = {
IconButton(onClick = {}) {
Icon(Icons.Filled.ArrowBack, "backIcon")
}
},
backgroundColor = MaterialTheme.colors.primary,
contentColor = Color.White,
elevation = 10.dp
)
}, content = {
Column(
modifier = Modifier
.fillMaxSize()
.background(Color(0xff8d6e63)),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
}
Text(
text = "Content of the page",
fontSize = 30.sp,
color = Color.White
)
})
}
Note: I haven't place this text into Column. I used directly.
My output:
Question:
How to place the text into the center of the parent?
Assign the fillMaxSize() to the parent container, not to the Text:
Box(Modifier.fillMaxSize(),
contentAlignment = Center
) {
Text(
text = "Content of the page",
fontSize = 30.sp,
modifier = Modifier
.background(Color(0xffb3e5fc)),
)
}
or:
Column(Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "Content of the page",
fontSize = 30.sp,
modifier = Modifier
.background(Color(0xffb3e5fc)),
)
}
You need to place it inside a Box, and specify contentAlignment
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.fillMaxSize()
) {
Text(
text = "Content of the page",
fontSize = 30.sp,
modifier = Modifier
.background(Color(0xffb3e5fc)),
)
}
If you wanna align different Box children differently, you can use .align modifier for each item. Note that it's only available inside BoxScope, also there's same modifier for Column and Row.
Box(
modifier = Modifier
.fillMaxSize()
) {
Text(
text = "Content of the page", textAlign = TextAlign.Center,
fontSize = 30.sp,
modifier = Modifier
.background(Color(0xffb3e5fc))
.align(Alignment.Center)
)
}
Box(
modifier = Modifier
.fillMaxSize()
) {
Text(
text = stringResource(id = R.string.social_list_empty),
style = TextStyle(fontSize = 16.sp),
modifier = Modifier
.padding(8.dp)
.align(Alignment.Center),
textAlign = TextAlign.Center
)
}
Reference : For more sample codes of Jetpack Compose, check this
The content in Scaffold is a Composable function in which there is no position info for items by default. In your case, the default position of Text is the top left of its parent view. The solutions putting the Text inside the Box/Colum works, as now Text is put in the center of the Box or Colum, which takes the whole screen. We see Text is in the center of the screen, while the truth is Text is in the center of Box or Colum.
I'm trying to use the new Jetpack Compose UI framework, but I'm running into an issue. I'd like to achieve this layout, which in xml is pretty easy to achieve:
But I can't figure out how to make the vertical divider take up the available vertical space, without specifying a fixed height. This code that I've tried doesn't seem to work:
#Composable
fun ListItem(item: PlateUI.Plate) {
Surface(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(8.dp),
elevation = 2.dp
) {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
Column(
modifier = Modifier
.padding(8.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Code")
Text(text = item.code)
}
Spacer(
modifier = Modifier
.preferredWidth(1.dp)
.background(color = MaterialTheme.colors.onSurface.copy(0.12f))
)
Spacer(modifier = Modifier.weight(1f))
Text(
modifier = Modifier
.padding(horizontal = 8.dp, vertical = 34.dp),
text = item.name
)
Spacer(modifier = Modifier.weight(1f))
}
}
}
I keep getting this result:
I also tried with ConstraintLayout, but it still didn't work
#Composable
fun ListItem(item: PlateUI.Plate) {
Surface(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(8.dp),
elevation = 2.dp
) {
ConstraintLayout(
modifier = Modifier.fillMaxWidth(),
) {
val(column, divider, text) = createRefs()
Column(
modifier = Modifier
.padding(8.dp)
.constrainAs(column){
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
start.linkTo(parent.start)
},
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Code")
Text(text = item.code)
}
Spacer(
modifier = Modifier
.preferredWidth(1.dp)
.background(color = MaterialTheme.colors.onSurface.copy(0.12f))
.constrainAs(divider){
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
start.linkTo(column.end)
}
)
Text(
modifier = Modifier
.padding(horizontal = 8.dp, vertical = 34.dp)
.constrainAs(text){
start.linkTo(divider.end)
end.linkTo(parent.end)
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
},
text = item.name
)
}
}
}
But nothing seems to work. Is this a bug, a missing feature or am I just missing something?
EDIT: Apparently the real problem is that the divider doesn't know how to measure when the Surface doesn't have a fixed height, setting height equal to some number solves the issue, but then the view doesn't adapt to the content height anymore, so this can't be the solution
You can apply:
the modifier .height(IntrinsicSize.Max) to the Row
the modifiers .width(1.dp).fillMaxHeight() to the Spacer
You can read more about the Intrinsic measurements here.
Something like:
Row(
modifier = Modifier.fillMaxWidth().height(IntrinsicSize.Max),
verticalAlignment = Alignment.CenterVertically
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
....
) {
Text(text = "....")
}
Spacer(
modifier = Modifier
.width(1.dp)
.fillMaxHeight()
.background(color = MaterialTheme.colors.onSurface.copy(0.12f))
)
Text(...)
}
You can set Intrinsic.Max for the preferredHeight of the Row, then set the Spacer to fill max height. You can read more on Intrinsics in this codelab section.
#Composable
fun ListItem() {
Surface(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(8.dp),
elevation = 2.dp
) {
Row(
modifier = Modifier.fillMaxWidth().preferredHeight(IntrinsicSize.Max),
verticalAlignment = Alignment.CenterVertically
) {
Column(
modifier = Modifier
.padding(8.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Code")
Text(text = "2456")
}
Spacer(
modifier = Modifier
.preferredWidth(1.dp)
.fillMaxHeight()
.background(color = Color.Black.copy(0.12f))
)
Spacer(modifier = Modifier.weight(1f))
Text(
modifier = Modifier
.padding(horizontal = 8.dp, vertical = 34.dp),
text = "Some name"
)
Spacer(modifier = Modifier.weight(1f))
}
}
}
I've solved it using constraint layout:
Box(modifier = Modifier.padding(Dp(50f))) {
ConstraintLayout(
modifier = Modifier
.border(width = Dp(1f), color = Color.Black)
.fillMaxWidth()
) {
val (left, divider, right) = createRefs()
Column(
modifier = Modifier
.padding(horizontal = Dp(20f))
.constrainAs(left) {
width = Dimension.wrapContent
start.linkTo(parent.start)
top.linkTo(parent.top)
end.linkTo(divider.start)
bottom.linkTo(parent.bottom)
}
) {
Text(text = "Code")
Text(text = "A12")
}
Box(
modifier = Modifier
.width(Dp(1f))
.background(Color.Black)
.constrainAs(divider) {
width = Dimension.wrapContent
height = Dimension.fillToConstraints
start.linkTo(left.end)
top.linkTo(parent.top)
end.linkTo(right.start)
bottom.linkTo(parent.bottom)
}
)
Box(
modifier = Modifier
.constrainAs(right) {
width = Dimension.fillToConstraints
start.linkTo(divider.end)
top.linkTo(parent.top)
end.linkTo(parent.end)
bottom.linkTo(parent.bottom)
}
) {
Text(
text = "Test",
modifier = Modifier
.padding(vertical = Dp(100f))
.align(Alignment.Center)
)
}
}
}
The key part is using that modifier height = Dimension.fillToConstraints
There are plenty of solutions here, but I thought I could demonstrate the ConstraintLayout approach and add a helpful usage of the IntrinsicSize enum that solves one of the issues (needing an adaptive height for the composable). Interestingly, either IntrinsicSize.Max or IntrinsicSize.Min will yield the desired behavior.
I used most of your code. The key differences are:
declares a guideline (my value passed in for the fraction does not produce the exact result you were looking for, but can be adjusted easily (use a fraction slightly smaller than .2) This can be useful if you expect wrapContent to alter your left Text to vary the location of a spacer, but would prefer a consistent spacer location across a list of these items.
others have mentioned, spacer modifier should include .fillMaxHeight()
define the height of the surface wrapper to be .height(IntrinsicSize.Min) docs ref here: https://developer.android.com/jetpack/compose/layout#intrinsic-measurements
divider start is constrained to the guideline
had to change the Spacer modifier to access the width, instead of preferredWidth
#Composable
fun ListItem(item: Plate) {
Surface(
modifier = Modifier.fillMaxWidth().height(IntrinsicSize.Min),
shape = RoundedCornerShape(8.dp),
elevation = 2.dp
) {
ConstraintLayout(
modifier = Modifier.fillMaxWidth(),
) {
val guideline = createGuidelineFromStart(0.2f)
val(column, divider, text) = createRefs()
Column(
modifier = Modifier
.padding(8.dp)
.constrainAs(column){
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
start.linkTo(parent.start)
end.linkTo(guideline)
},
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Code")
Text(text = item.code)
}
Spacer(
modifier = Modifier
.constrainAs(divider){
top.linkTo(column.top)
bottom.linkTo(column.bottom)
start.linkTo(guideline)
}
.width(1.dp)
.fillMaxHeight()
.background(color = MaterialTheme.colors.onSurface.copy(0.12f))
)
Text(
modifier = Modifier
.padding(horizontal = 8.dp, vertical = 34.dp)
.constrainAs(text){
start.linkTo(divider.end)
end.linkTo(parent.end)
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
},
text = item.name
)
}
}
}
I think Row layout is enough.
#Preview(showBackground = true, heightDp = 100)
#Composable
fun ListItem(item: PlateUI.Plate = PlateUI.Plate()) {
Card(
shape = RoundedCornerShape(8.dp)
) {
Row(
modifier = Modifier
.fillMaxSize(),
verticalAlignment = Alignment.CenterVertically
) {
Text(
modifier = Modifier.padding(8.dp),
text = "Code\n${item.code}",
textAlign = TextAlign.Center
)
Box(
Modifier
.fillMaxHeight()
.width(1.dp)
.background(color = MaterialTheme.colors.onSurface.copy(0.12f))
)
Text(
modifier = Modifier
.weight(1f)
.padding(8.dp),
text = item.name,
textAlign = TextAlign.Center
)
}
}
}