Provide different alignments to composables within 'Column' - android

I have a 'Text' and another composable within a Column. I want to put the Text to the top and the layout defined by the composable to the bottom. I am not able to find a way to provide different alignments to the 'elements' within Column, as the alignment/arrangement specified in the 'Modifier' of Column works for all the 'elements' within it. My current code aligns both to the bottom. This is my code:
#Composable
fun SignUpDetails(navController: NavController) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Bottom,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "First Screen\n" +
"Click me to go to Second Screen",
color = Color.Green,
style = TextStyle(textAlign = TextAlign.Center),
modifier = Modifier
.padding(24.dp)
.clickable(onClick = {
// this will navigate to second screen
navController.navigate("second_screen")
})
)
ProgressBar1UI()
}
}
How do I achieve my requirement?

You can use the verticalArrangement = Arrangement.SpaceBetween:
Place children such that they are spaced evenly across the main axis, without free space before the first child or after the last child
Something like:
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceBetween
) {
Text( /*...*/ )
ProgressBar1UI()
}
Otherwise you can use something different like a Box and the Modifier.align:
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier
.align(Alignment.TopCenter)
)
ProgressBar1UI(Modifier.align(Alignment.BottomCenter))
}

The other way you can achieve such behavior (one view top second view bottom) is to add the Spacer component with a weight modifier between items.
#Composable
fun Example() {
Column {
Text("FirstText")
Spacer(modifier = Modifier.weight(1f))
Text("SecondText")
}
}

Related

How to show semi-transparent loading overlay above full Composable

I am trying to create a Composable that wraps another content Composable and displays a CircularProgressBar as an overlay on top of it, covering the whole content Composable.
I almost got it working as wished, see the following to images:
Initial state
Loading state
But as you can see, the overlay fills the complete screen instead of just the gray LazyRow item and the text field. Thus, the button is pushed off screen.
This is my current code:
#Composable
fun LoadingBox(
modifier: Modifier = Modifier,
isLoading: Boolean = false,
loadingText: String,
content: #Composable() () -> Unit
) {
Box(modifier = modifier
.fillMaxWidth()
.wrapContentHeight()
) {
content()
if (isLoading) {
Surface(
modifier = Modifier
.fillMaxSize()
.alpha(0.5f),
) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
CircularProgressIndicator()
Text(text = loadingText)
}
}
}
}
}
On the screenshots, I am providing the gray box and the text field as the content parameter. So the overlay should only cover the gray LazyRow item and the text field.
I already stumbled across instrinsic measures, however I cannot use them as the App crashes when I provide a LazyRow as content due to following error:
java.lang.IllegalStateException: Asking for intrinsic measurements of SubcomposeLayout layouts is not supported. This includes components that are built on top of SubcomposeLayout, such as lazy lists, BoxWithConstraints, TabRow, etc. To mitigate this:
- if intrinsic measurements are used to achieve 'match parent' sizing,, consider replacing the parent of the component with a custom layout which controls the order in which children are measured, making intrinsic measurement not needed
You should:
add contentAlignment = Alignment.Center in the parent Box
Remove the Surface
remove the verticalArrangement in the Column
Add an other Box which you can fill with a translucent background
Something like:
Box(modifier = modifier
.fillMaxWidth(),
contentAlignment = Alignment.Center,
) {
content()
if (isLoading) {
Box(
Modifier
.matchParentSize()
.background(Color.Gray.copy(alpha = 0.5f))
)
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
androidx.compose.material.CircularProgressIndicator()
Text(text = loadingText)
}
}
}

Kotlin Jetpack compose Center text in Column inside a LazyColum

I'am new to jetpack compose and i really liked it. But ran into a problem : I want to create a card and inside of it, i would like to display a list of item with divider between them. I was almost able to achieved it here is my code :
Box(modifier = Modifier.background(Color(0xFFf4f4f4))
.fillMaxSize()
.padding(top = 20.dp)) {
Card(
modifier = Modifier
.fillMaxWidth(),
shape = RoundedCornerShape(20.dp),
elevation = 5.dp
) {
val colorNamesList = listOf("Red", "Green", "Blue", "Indigo")
LazyColumn() {
itemsIndexed(
colorNamesList,
) { index, item ->
Column(
modifier = Modifier
.background(
color = Color(0xFFf2f2f2),
)
.clickable {
println(item)
},
horizontalAlignment = Alignment.CenterHorizontally,//those 2 does nothing
verticalArrangement = Arrangement.Center //when i change it nothing change
) {
println(item + index)
Text(
text = "Item at $item",
modifier = Modifier
.fillMaxWidth()
.height(50.dp),
//textAlign = TextAlign.Center, without it image 1, with it image 2
color = Color.Black,
)
if (index < colorNamesList.lastIndex) {
Divider(
color = Color.Black.copy(alpha = 0.2f),
modifier = Modifier
.padding(horizontal = 80.dp),
)
}
}
}
}
}
}
It's almost good but i didn't managed to align the text inside it, i searched some answer but Alignment and Arrangement doesn't change anything in my situation.
I was able to align horizontally by adding textAlign = TextAlign.Center as i commented in my code but, i couldn't align vertically, the text stay on the top of his cell :
What i want to do is text center in every cell of the column. Thanks for the help.
You can achieve this by adding similar xml attribute like "wrap_content" as height in compose too.
Add "wrapContentHeight()" to modifier and you will get it to align to centre of the page.
Text(
text = "Item at $item",
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.wrapContentHeight(),
textAlign = TextAlign.Center
color = Color.Black,
)

Can I have aligned bottomCenter instead of topLeft for performing animateContentSize?

I have this code that perform "animateContentSize" with text size changes.
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
var message by remember { mutableStateOf("") }
Box (Modifier
.animateContentSize(
animationSpec = tween(2000)
),
contentAlignment = Alignment.BottomCenter){
Text(message)
}
Button(onClick = {
message = newText('O')
}) {
Text("Click Me")
}
}
I'm expecting it to animate with the content aligned BottomCenter. However it is always aligned TopLeft (as you see, when it shrink, the text went up to TopLeft and then slowly moved toward Center.)
Is there a way to make it aligned BottomCenter, so the Text won't fly up as the size shrink.
The API currently doesn't support it. Could you file a feature request for specifying content alignment in animateContentSize?
To align views BottomCenter, you can add verticalArrangement = Arrangement.Bottom to your Column
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Bottom,
horizontalAlignment = Alignment.CenterHorizontally
) {}

Arrange a single item inside a LazyColumn by using weight modifier

I am looking to have a result like this. Two block with 2/3 size and 1/3 size respectively.
I am getting the expected result with this code.
#Preview(showBackground = true)
#Composable
fun LayoutCheck() {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Surface(
modifier = Modifier
.width(200.dp)
.weight(3f),
color = MaterialTheme.colors.primary
) {}
Surface(
modifier = Modifier
.width(200.dp)
.weight(1f),
color = MaterialTheme.colors.secondary
) {}
}
}
But when i put that inside a lazycolumn, nothing seems working. Not even getting a display.
#Preview(showBackground = true)
#Composable
fun LayoutCheck() {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(20.dp)
) {
item {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Surface(
modifier = Modifier
.width(200.dp)
.weight(3f),
color = MaterialTheme.colors.primary
) {}
Surface(
modifier = Modifier
.width(200.dp)
.weight(1f),
color = MaterialTheme.colors.secondary
) {}
}
}
}
}
}
If i remove t he weight and put some height,it works. But i don't want to hardcode there. So how to make it work with weight. Expecting some help..
Thanks
NB: I want scroll functionality, that's why going with LazyColumn
Real World scenario :
A Login Screen, with Logo at the first 2/3 portion and a Text and Button at the bottom 1/3 portion
Scenario 1 : Working Perfectly:
Scenario 2: If users font is bigger or screen is rotated, they wont be able to see the button
Since you have only one item just use a Column with a verticalScroll:
val scrollState = rememberScrollState()
Column(
modifier = Modifier
.verticalScroll(scrollState),
horizontalAlignment = Alignment.CenterHorizontally,
) {
//...
}
Also if you want 2/3 and 1/3, use in the 1st Surface the weight(2f) modififer.
You prevent the text from being resized by applying the weight modifier. Instead, I suggest that you make the element spacing flexible, like this:
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Spacer(Modifier.weight(1f))
Image(
painter = painterResource(id = R.drawable.my_image),
contentDescription = "",
)
Spacer(Modifier.weight(1.35f))
Text(
"Your app is being reviewed",
)
Spacer(Modifier.weight(0.2f))
Button(onClick = { /*TODO*/ }) {
Text("Log out")
}
Spacer(Modifier.weight(0.2f))
}
Spacers explanation:

How to align Text to Top, Bottom and Center Vertically in Jetpack Compose?

How can I align the text using Text composable function vertically. Is there a way to do it without having to add another extra view to contain the Text.
The textAlign parameter of Text only has the following options:
TextAlign.
Left
Right
Center
Justify
Start
End
I have tried using textAlign = TextAlign.Center but it only centers it horizontally. How can I center it vertically without wrapping it in another view?
Text(
text = "Text",
modifier = Modifier.size(100.dp),
textAlign = TextAlign.Center
)
Result:
What I am trying to achieve:
You have to use a parent container and align the composable inside it.
For example a Box:
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Center
) {
Text(
text = "Text",
)
}
or a Column:
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "Text",
)
}
first use .wrapContentHeight() in modifier, then you can use align(CenterVertically) param to center the text.
It is difficult to give an exact answer without seeing your code, but I would say you need to use container's Alignment.CenterVertically instead of TextAlign
Something like:
Row {
Text(
text = "Text",
modifier = Modifier.align(alignment = Alignment.CenterVertically)
)
Image(
...
)
}
or:
Column(
modifier = Modifier
.align(Alignment.CenterVertically)
) {
Text(text = "Text")
Text(text = "Text 2")
}
I asked the same question here which is done with android:gravity param using views, as answered by PhilipDukhov it's not possible only with Text, you need to have another container, preferably Box to align Text component inside.
Create a simple composable function to show anything in center:
#Composable
fun Center(
modifier: Modifier = Modifier,
content: #Composable () -> Unit,
) {
Box(
modifier = modifier,
contentAlignment = Alignment.Center
) {
content()
}
}
Call it from any other function:
#Composable
fun CenterAlignedText() {
Center(Modifier.fillMaxSize()) {
Text("Hello World!")
}
}

Categories

Resources