Jetpack Compose : Scrollable column with fractions - android

I have 3 elements in a column.
I want the 1st element to take 50% of screen and the remaining to take rest of space or scroll if needed.
I have tried the following:
Using verticallScroll() with fractions is not working. If i disable verticallScroll() then the 1st element takes 50% of the screen but the screen does not scrolls if needed.
Column(
modifier = Modifier
.background(color = Color.Black)
.padding(horizontal = 15.dp)
.verticalScroll(state = rememberScrollState(), enabled = true)
.fillMaxSize()
) {
QuickTipsCard(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(0.5f),
backgroundColor = LightBlue,
title = "Good morning!",
description = "0 out of 10 task today",
titleStyle = Typography.h1
)
}

You can wrap the Column in a BoxWithConstraints component and use the maxHeight property to calculate the desired heights for the elements in the column.

Related

How to set Box(contentAlignment=CenterVertically40%DownThePage)? Need advanced alignment option for Box

I'm building this screeen from the Android Jetpack Compose lessons, and I want to somewhat-center-vertically the middle / 'Full Name' red box -- but I don't want it fully centered (i.e. 50% down the page), I want it 40% down the page, but the built-in 'contentAlignment' modifiers only cover 'Top', 'Center', and 'Bottom' -- I want something in between.
This is my current code, and it looks fine-ish, but I want to know how to manipulate the vertical alignment of the contents of the Box more fine-grained.
#Composable
fun Profile(){
Box(
modifier = Modifier
.padding(16.dp)
.fillMaxSize(),
contentAlignment = Alignment.Center
,
) {
Column() {
// icon
Text("aslkjdf",
fontSize = 48.sp)
// Full Name
Text("aslkjdf",
fontSize = 48.sp)
// Title
Text("aslkjdf",
fontSize = 48.sp)
}
}
}
You can use the BiasAlignment.
A bias of -1 represents alignment to the start/top, a bias of 0 will represent centering, and a bias of 1 will represent end/bottom.
Just note that the Alignment.Center is defined as:
val Center: Alignment = BiasAlignment(0f, 0f)
You can use something like:
Box(
modifier = Modifier
.padding(16.dp)
.fillMaxSize(),
contentAlignment = BiasAlignment(
horizontalBias = 0f,
verticalBias = -0.2f
)
) {
Column(
modifier = Modifier.fillMaxWidth().border(1.dp,Red),
horizontalAlignment = Alignment.CenterHorizontally
){
// icon
Icon(Icons.Default.Email,"", modifier = Modifier.size(64.dp))
// Full Name
Text("FullName",
fontSize = 36.sp)
// Title
Text("Title",
fontSize = 24.sp)
}
}
Inside the -1, 1 range, the obtained alignment will position the aligned size fully inside the available space, using as center
val y = centerY * (1 + verticalBias)

Jetpack compose Grid with adaptive numbers of columns based on size

I am trying to make a grid of text items, witch can vary in size, and I would like for as many items to fix in one row as the size allows.
This is what I got so far
For example in this case, Ias you see the first row has space for additional items, while climbing should be Climbing and mountaineering
I have been trying to use LazyVerticalGrid, is there any way to automatically calculate span based on item size?
`
LazyVerticalGrid(columns = GridCells.Adaptive(120.dp),
horizontalArrangement = Arrangement.spacedBy(12.dp),
verticalArrangement = Arrangement.spacedBy(14.dp)){
items(selected.size){i->
ItemHobbySelected(text = selected[i])
}
}
#Composable
fun ItemHobbySelected(text: String, onClick: () -> Unit={}){
Box(modifier = Modifier
.wrapContentWidth()
.clip(RoundedCornerShape(8.dp))
.background(Color.White)) {
Text(
modifier = Modifier
.background(Color.Transparent)
.padding(16.dp, 8.dp, 16.dp, 8.dp)
.align(Alignment.Center)
.clickable(onClick = onClick),
text = text,maxLines =1,
color = Color(0xFF3D3D3D)
)
}
}
`
For such designs you can use Google Accompanist's FlowLayout. Add the version based on the Compose version you are using.
implementation "com.google.accompanist:accompanist-flowlayout:<version>"
It has two Composables. FlowRow and FlowColumn. You need FlowRow:
FlowRow(
mainAxisSpacing = 10.dp,
crossAxisSpacing = 10.dp,
modifier = Modifier
.fillMaxWidth()
.padding(4.dp),
mainAxisAlignment = MainAxisAlignment.Center
) {
selected.forEach{ item ->
ItemHobbySelected(text = "//Whatever you want")
}
You can modify the spacings to get your desired layout.

Jetpack Compose - how to adjust the padding depending on the height of another component?

I have a component set with Modifier.wrapContentHeight() which height has different height depending on its content. I want to adjust other component's padding to the first component height dynamically. I tried something like this:
var height = 0
val resourceContentBottomPadding = height + 16
LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(start = 16.dp, end = 16.dp, bottom = height.dp),
) { /.../ }
Column(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.onGloballyPositioned {
height = it.size.height
}
) {
if (something)
SomeComposeElement()
Button()
}
Unfortunately it changes nothing.
If you put your LazyColumn and Column inside an ancestor Column and set modifier = Modifier.fillMaxWidth().weight(1f) for your LazyColumn it will only occupy space after Column is laid out which is total height - height of the Column

Box doesn't fill max size - Jetpack Compose

My PersonalDataBox() doesn't fill max available space even if there is .fillMaxSize()
There is a empty space between my box and the bottom of the screen. I want to fill my whole screen with Box(). It looks like my box has .fillWrapHeight(). Parent of the box is also .fillMaxSize() and it works correctly - fills max height.
#Composable
private fun PersonalDataBox(user: User) {
Box(
modifier = Modifier
.fillMaxSize()
.padding(vertical = 10.dp)
.clip(RoundedCornerShape(topStart = 10.dp, topEnd = 10.dp))
.background(Color.Red)
.padding(horizontal = 25.dp, vertical = 15.dp)
) {
Column(modifier = Modifier.fillMaxSize()) {
Text(
text = stringResource(R.string.personal_data),
modifier = Modifier
.fillMaxWidth()
.padding(top = 10.dp),
fontSize = 16.sp,
fontWeight = FontWeight.SemiBold,
color = MaterialTheme.colors.primary
)
listOf(
Pair(stringResource(R.string.name), user.name),
Pair(stringResource(R.string.surname), user.surname),
Pair(stringResource(R.string.e_mail), user.email),
).forEach {
InputField(it)
}
}
}
}
I pulled down your code and it actually renders in the whole screen just fine--so I'm assuming you have your PersonalDatabox in a compose view with infinite height such as a LazyColumn.
Check out the documentation about constraints here
Specifically:
Most commonly, when measured with unbounded Constraints, these children will fallback to size themselves to wrap their content, instead of expanding to fill the available space (this is not always true as it depends on the child layout model, but is a common behavior for core layout components).
In other words, if the constraint is infinite, then .fillMaxSize will default to wrapping content.
To get around this, you can make the constraint equal to the height of the Lazy Column by using fillParentMaxHeight.
This only works if you're using a LazyColumn, though. Otherwise, if you set the height specifically or measure the screen you can accomplish the same thing.
Here's an example of what that might look like.
LazyColumn() {
item {
Column(modifier = Modifier.fillParentMaxHeight(1f)) {
PersonalDataBox(User(name = "John", surname = "Robless", "coolemail#email.com"))
}
}
}
Your Box has the following modifiers:
modifier = Modifier
.fillMaxSize()
.padding(vertical = 10.dp)
.clip(RoundedCornerShape(topStart = 10.dp, topEnd = 10.dp))
.background(Color.Red)
.padding(horizontal = 25.dp, vertical = 15.dp)
The important ones are
.padding(vertical = 10.dp)
.padding(horizontal = 25.dp, vertical = 15.dp)
There are two padding modifiers adding a total of 25.dp padding to the top and bottom of your Box, remove these and it should fix your issue

What is the difference between `fillMaxSize()` and `matchParentSize()` in a component inside a Box in Jetpack Compose?

I'm creating a component in Jetpack Compose and realized that when I'm making a Composable inside a Box it's possible that this component assumes 2 maximum fill possibilities: Modifier.fillMaxSize() and Modifier.matchParentSize(). As shown below:
Box(
modifier = modifier // This modifier is received by parameter of another composable function
) {
Canvas(modifier = Modifier.matchParentSize()) {
// Using match parent size
}
}
and
Box(
modifier = modifier // This modifier is received by parameter of another composable function
) {
Canvas(modifier = Modifier.fillMaxSize()) {
// Using fill max size
}
}
What is the practical difference between these 2 modes? And why can't I set Modifier.matchParentSize() to a Column or a Row?
From official doc
Modifier.fillMaxSize modifier, which makes an element occupy all available space, will take part in defining the size of the Box.
So it specifies the size of the element.
But if you use Modifier.matchParentSize() in an element inside of a box it has nothing to do with specifying the size of the box.
The size of the box will be measured by other children element of the box. Then the element with the Modifier.matchParentSize() will match and occupy that size.
You can't use .matchParentSize() in Row or Column because this modifier is part of the BoxScope interface. So it works only with boxscope.
For example, if you use fillMaxSize with something like the below.
Box() {
Text(
modifier = Modifier
.fillMaxSize()
.background(Color.Green),
text = ""
)
Text(
modifier = Modifier
.size(100.dp)
.background(Color.Blue),
text = "Hello",
)
}
You will get this. It will fill the entire screen because of that .fillMaxSize() modifier in the first child.
But if you use this
Box() {
Text(
modifier = Modifier
.matchParentSize()
.background(Green),
text = ""
)
Text(
modifier = Modifier
.size(100.dp),
text = "Hello",
)
}
It will take only 100.dp for the Hello text and then the green background will fill that 100.dp because of that .matchParentSize() modifier in the first child.
I could have used Box instead of Text but more Box can make it confused.

Categories

Resources