I've been trying to build a list with a Card in it formatted like this:
The difficulty here is that the title e.g. "Bread" and ingredient name e.g. "Flour" can be very long and thus I want to have an ellipsis to keep things manageable i.e. "My Long Flour name" will be displayed as "My Long Flou..." or as much space as is allowed.
The picture size and the gram and percent widths are constant .dp values.
Ellipsis worked fine when it was in a Column but with ConstraintLayout it doesn't seem to work and I get this:
here's my code
#Composable
fun BakeItem(
modifier: Modifier = Modifier,
bake: Bake,
cardClicked: () -> Unit,
ingredeints: List<Ingredient>
) {
Card(
modifier = modifier
.padding(start = 16.dp, end = 16.dp, top = 8.dp, bottom = 8.dp)
.clickable { cardClicked() }
.fillMaxSize()
.wrapContentHeight(),
border = BorderStroke(4.dp, MaterialTheme.colorScheme.secondary),
shape = RoundedCornerShape(14.0.dp),
colors = cardColors(
containerColor = MaterialTheme.colorScheme.background
)
) {
val context = LocalContext.current
val uri = remember(bake.imagePath) { Uri.parse(bake.imagePath) }
// Card Content
ConstraintLayout(
modifier = modifier
.fillMaxSize()
.padding(start = 16.dp, top = 8.dp, end = 8.dp, bottom = 8.dp)
) {
val (titleRef, gramColRef, ingrColRef, percentColRef,
imageRef, dateRef, starsRef) = createRefs()
Text(
modifier = modifier
.padding(4.dp)
.constrainAs(titleRef) {
top.linkTo(parent.top, margin = 8.dp)
// end.linkTo(imageRef.start, margin = 8.dp)
start.linkTo(parent.start, margin = 8.dp)
}
.background(Color(0xffeeeeee)),
// textAlign = TextAlign.Left,
text = if (bake.recipeName.isEmpty()) "<Unnamed>" else bake.recipeName,
style = MaterialTheme.typography.titleLarge,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.primary,
softWrap = false,
overflow = TextOverflow.Ellipsis,
)
Column(
horizontalAlignment = Alignment.End,
modifier = modifier
.width(50.dp)
.constrainAs(gramColRef) {
top.linkTo(titleRef.bottom, margin = 8.dp)
end.linkTo(ingrColRef.start, margin = 8.dp)
start.linkTo(parent.start, margin = 8.dp)
}
) {
ingredeints.forEachIndexed { _, it ->
Text(
text = it.weightGram,
style = MaterialTheme.typography.titleSmall,
softWrap = false,
overflow = TextOverflow.Ellipsis
)
}
}
Column(
modifier = modifier
.constrainAs(ingrColRef) {
top.linkTo(titleRef.bottom, margin = 8.dp)
start.linkTo(gramColRef.end, margin = 8.dp)
end.linkTo(ingrColRef.start, margin = 8.dp)
},
) {
ingredeints.forEachIndexed { _, it ->
Text(
text = it.name,
style = MaterialTheme.typography.titleSmall,
softWrap = false,
overflow = TextOverflow.Ellipsis
)
}
}
Column(
modifier = modifier
.width(50.dp)
.constrainAs(percentColRef) {
top.linkTo(titleRef.bottom, margin = 8.dp)
end.linkTo(imageRef.start, margin = 8.dp)
start.linkTo(ingrColRef.end, margin = 8.dp)
},
horizontalAlignment = Alignment.End
) {
ingredeints.forEachIndexed { i, it ->
Text(
text = if (i == 0) "" else it.bakingPercent,
style = MaterialTheme.typography.titleSmall,
softWrap = false,
overflow = TextOverflow.Ellipsis
)
}
}
Text(
modifier = modifier.padding(
top = 8.dp,
start = 4.dp,
end = 4.dp,
bottom = 4.dp
),
text = bake.notes,
style = MaterialTheme.typography.titleSmall,
color = MaterialTheme.colorScheme.onSurface,
maxLines = 3
)
if (bake.imagePath.isNotEmpty()) {
Image(
modifier = modifier
.constrainAs(imageRef) {
top.linkTo(parent.top, margin = 8.dp)
end.linkTo(parent.end, margin = 8.dp)
}
.padding(4.dp)
.requiredSize(150.dp)
.clip(RoundedCornerShape(14.dp))
.border(
4.dp,
MaterialTheme.colorScheme.primaryContainer,
RoundedCornerShape(14.dp)
),
painter = rememberAsyncImagePainter(
remember(uri) {
ImageRequest.Builder(context)
.data(uri)
// TODO, think of caching improvements
// .diskCacheKey(uri.toString() + key.value)
// .memoryCacheKey(uri.toString() + key.value)
.diskCachePolicy(CachePolicy.DISABLED)
.memoryCachePolicy(CachePolicy.DISABLED)
.build()
}
),
contentScale = ContentScale.Crop,
contentDescription = "Image of your bake"
)
} else {
Spacer(modifier = modifier
.background(Color.Blue)
.width(150.dp)
.height(10.dp)
.constrainAs(imageRef) {
top.linkTo(parent.top, margin = 8.dp)
end.linkTo(parent.end, margin = 8.dp)
})
}
Text(
modifier = modifier
.padding(4.dp)
.constrainAs(dateRef) {
bottom.linkTo(parent.bottom, margin = 8.dp)
top.linkTo(imageRef.bottom, margin = 8.dp)
end.linkTo(parent.end, margin = 8.dp)
},
text = bake.startTime.toString(),
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.onSurface,
// textAlign = Layout.Alignment.ALIGN_CENTER
)
createHorizontalChain(
gramColRef, ingrColRef, percentColRef, imageRef,
chainStyle = ChainStyle.SpreadInside
)
createVerticalChain(
imageRef, dateRef,
chainStyle = ChainStyle.SpreadInside
)
createHorizontalChain(
titleRef, imageRef,
chainStyle = ChainStyle.SpreadInside
)
}
}
}
In the title you have to add as constrain width = Dimension.fillToConstraints, end.linkTo(imageRef.start, margin = 8.dp) and maxLines = 1:
Text(
modifier = Modifier
.padding(4.dp)
.constrainAs(titleRef) {
top.linkTo(parent.top, margin = 8.dp)
end.linkTo(imageRef.start, margin = 8.dp)
start.linkTo(parent.start, margin = 8.dp)
width = Dimension.fillToConstraints
}
.background(Color(0xffeeeeee)),
text = "Recipe Name",
//...
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
For the list instead of using 3 Columns you do can something different.
For the ingredient name add the weight(1f) modifier and the maxLines = 1
Column(
modifier = Modifier
.constrainAs(listRef) {
top.linkTo(titleRef.bottom, margin = 8.dp)
end.linkTo(imageRef.start, margin = 8.dp)
start.linkTo(parent.start, margin = 8.dp)
width = Dimension.fillToConstraints
}
) {
//forEach Row...
Row(Modifier.fillMaxWidth()) {
Text(text = "50g", Modifier.width(xx.dp), textAlign = TextAlign.End)
Text(
text = "Very long text long text",
Modifier
.padding(start=4.dp)
.weight(1f),
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
Text(text = "75%", Modifier.width(xx.dp), textAlign = TextAlign.End)
}
}
Related
When creating an Android app, I put some Composables in a Row of a Card, as shown below, and it did not work as I expected. The Composable that I put "weight(1f)" on was no longer showing up.
data class Test(
val title: String,
val text: String
)
#Composable
fun CardRowSample(
modifier: Modifier = Modifier,
) {
val testList =
listOf(
Test("AAAA", "1,2,3,4,5,6,7,8,9,10"),
Test("BBBB", "11,12,13,14,15,16,17,18,19,20")
)
LazyColumn(
modifier = modifier
) {
items(
items = testList
) {
test ->
Card(
elevation = 12.dp,
backgroundColor = Color.LightGray,
modifier = Modifier
.fillMaxWidth()
.heightIn(min = 50.dp)
.width(40.dp)
.requiredHeight(intrinsicSize = IntrinsicSize.Min)
.padding(
horizontal = 20.dp,
vertical = 20.dp
)
.border(
width = 1.dp,
color = Color.Black,
shape = RectangleShape
)
) {
Row(
modifier = Modifier.fillMaxWidth()
) {
Icon(
modifier = Modifier
.padding(horizontal = 5.dp)
.align(Alignment.CenterVertically),
imageVector = Icons.Filled.Check,
contentDescription = null
)
Text(
text = test.title,
fontSize = 20.sp,
modifier =
Modifier
.width(120.dp)
.padding(horizontal = 10.dp, vertical = 10.dp)
)
Text(
text = test.text,
fontSize = 20.sp,
modifier = Modifier
.weight(1f)//it doesn't work!!
.padding(horizontal = 10.dp, vertical = 10.dp)
)
}
}
}
}
}
My ideal image of the layout:
I wrote the code referring to the following question, Weights in Jetpack compose, but I can't figure out why this is happening. I put "weight" on everything and added fillParentMaxSize to the Row's modifier, but I wasn't able to solve this problem.
What should I do next to solve this problem?
Problem is not with Modifier.weight(1f). It's because of Modifier.requiredHeight(IntrinsicSize.Min)
Card(
elevation = 12.dp,
backgroundColor = Color.LightGray,
modifier = Modifier
.fillMaxWidth()
.heightIn(min = 50.dp)
// .width(40.dp)
// .requiredHeight(intrinsicSize = IntrinsicSize.Min)
.padding(
horizontal = 20.dp,
vertical = 20.dp
)
.border(
width = 1.dp,
color = Color.Black,
shape = RectangleShape
)
)
Also Modifier.width(40.dp) is redundant because you have another width modifier Modifier.fillMaxWidth() before that.
When Modifier.requiredIn with Intrinsic size modifiers act strange. Composable gets measured twice and with Infinity constraints
LAYOUT constraints: Constraints(minWidth = 0, maxWidth = 1080, minHeight = 0, maxHeight = Infinity), width: 1080, height: 235
LAYOUT constraints: Constraints(minWidth = 0, maxWidth = Infinity, minHeight = 235, maxHeight = 235), width: 510, height: 235
That's the second measurement breaks width because of maxWidth = Infinity. 1080px is full width on my device
to see Constrains and Composable width and height you can use
Card(
elevation = 12.dp,
backgroundColor = Color.LightGray,
modifier = Modifier
.fillMaxWidth()
.heightIn(min = 50.dp)
// .width(40.dp)
.requiredHeight(intrinsicSize = IntrinsicSize.Min)
.layout { measurable, constraints ->
val placeable = measurable.measure(constraints)
println("LAYOUT constraints: $constraints, width: ${placeable.width}, height: ${placeable.height}")
layout(placeable.width,placeable.height){
placeable.placeRelative(0,0)
}
}
.padding(
horizontal = 20.dp,
vertical = 20.dp
)
.border(
width = 1.dp,
color = Color.Black,
shape = RectangleShape
)
)
An alternative to the Thracian's answer is to apply Modifier.height(IntrinsicSize.Min) to your Card and fillMaxHeight() to the Icon.
Card(
elevation = 12.dp,
backgroundColor = Color.LightGray,
modifier = Modifier
.fillMaxWidth()
.heightIn(min = 50.dp)
.height(intrinsicSize = IntrinsicSize.Min)
.padding(
horizontal = 20.dp,
vertical = 20.dp
)
.border(
width = 1.dp,
color = Color.Black,
shape = RectangleShape
)
) {
Row(
modifier = Modifier.fillMaxWidth()
) {
Icon(
modifier = Modifier
.fillMaxHeight()
.padding(horizontal = 5.dp)
.align(Alignment.CenterVertically),
imageVector = Icons.Filled.Check,
contentDescription = null
)
Text(
text = test.title,
fontSize = 20.sp,
modifier =
Modifier
.width(120.dp)
.padding(horizontal = 10.dp, vertical = 10.dp)
)
Text(
text = test.text,
fontSize = 20.sp,
modifier = Modifier
.weight(1f)
.padding(horizontal = 10.dp, vertical = 10.dp)
)
}
}
}
I want make a UI like this picture.
What I want:
Now my result:
My code:
Row(
verticalAlignment = Alignment.CenterVertically
) {
Image(
imageVector = Icons.Rounded.CheckCircle,
contentDescription = null,
modifier = Modifier
.size(16.dp)
.onGloballyPositioned {
topOffset = it.boundsInRoot().bottomCenter
}
)
Spacer(modifier = Modifier.size(8.dp))
Text(
text = "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
fontSize = 16.sp,
)
}
Spacer(modifier = Modifier.size(8.dp))
Row(
verticalAlignment = Alignment.CenterVertically
) {
Image(
imageVector = Icons.Rounded.CheckCircle,
contentDescription = null,
modifier = Modifier
.size(16.dp)
.onGloballyPositioned {
bottomOffset = it.boundsInRoot().bottomCenter
}
)
Spacer(modifier = Modifier.size(8.dp))
Text(
text = "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
fontSize = 16.sp,
)
}
I want draw a vertical line between the CheckCircle icons.
You can have a fixed height and then draw a line behind. You should also have another icon with white arrow.
An example:
#Composable
fun checkComposable() {
// padding between rows
val padding = 50.dp
Row {
Box(Modifier.height(intrinsicSize = IntrinsicSize.Min)) {
Box(modifier = Modifier
.width(4.dp)
.padding(top = padding / 2, bottom = padding / 2)
.fillMaxHeight()
.background(Color.Black)
.align(Alignment.Center))
Column {
Box(Modifier.height(padding)) {
Image(
imageVector = Icons.Rounded.CheckCircle,
contentDescription = null,
modifier = Modifier
.size(16.dp)
.align(Alignment.Center)
)
}
Box(Modifier.height(padding)) {
Image(
imageVector = Icons.Rounded.CheckCircle,
contentDescription = null,
modifier = Modifier
.size(16.dp)
.align(Alignment.Center)
)
}
}
}
Spacer(modifier = Modifier.width(8.dp))
Column{
Box(Modifier.height(padding)) {
Text(
modifier = Modifier.align(Alignment.CenterStart),
text = "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
fontSize = 16.sp,
)
}
Box(Modifier.height(padding)) {
Text(
modifier = Modifier.align(Alignment.CenterStart),
text = "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
fontSize = 16.sp,
)
}
}
}
}
A workaround, could be this:
Row {
Vector() // Complete Icon, ticks and line
Column {
Text(...)
Text(...)
}
}
Me and my team are new to Compose and we're trying to build a TopUp screen for a client. The screen consists of a Column that contains some Padding (in the form of a Composable) for the TopAppBar, two Card composables, a button, then a footer composable which I need to constraint to the bottom of the column, and finally, some padding (again in the form of a composable) to give us some space between the content and the bottom navbar.
Right now we're using a spacer with a fixed dp value but obviously, this won't scale so that it is constrained to the bottom on all devices. What would be the best way to go about achieving such a look?
screen composable:
#OptIn(ExperimentalComposeUiApi::class)
#Composable
fun TopUpScreen() {
Column(
horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
.padding(horizontal = 16.dp)
) {
val viewModel = getViewModel<TopUpViewModel>()
TopBarPadding()
TopUpCardView(title = stringResource(id = R.string.choose_topup_amount)) {
var selectedCardIndex by remember { mutableStateOf(-1) }
Row(
horizontalArrangement = Arrangement.SpaceAround,
modifier = Modifier
.fillMaxWidth()
) {
Card(
shape = RoundedCornerShape(11.dp),
elevation = if (selectedCardIndex == 0) 1.dp else 0.dp,
backgroundColor = if (selectedCardIndex == 0) colorResource(id = R.color.bottom_modal_drawer_background) else colorResource(
id = R.color.more_screen_item_background
),
modifier = Modifier
.width(71.dp)
.height(56.dp)
.shadow(
if (selectedCardIndex == 0) 8.dp else 0.dp,
shape = RoundedCornerShape(11.dp)
)
.clickable {
selectedCardIndex = 0
viewModel.topUpAmount = 20.0
}
) {
Text(
"€20",
fontSize = 16.sp,
fontWeight = FontWeight.Normal,
textAlign = TextAlign.Center,
modifier = Modifier.wrapContentHeight()
)
}
Card(
shape = RoundedCornerShape(11.dp),
elevation = if (selectedCardIndex == 1) 1.dp else 0.dp,
backgroundColor = if (selectedCardIndex == 1) colorResource(id = R.color.bottom_modal_drawer_background) else colorResource(
id = R.color.more_screen_item_background
),
modifier = Modifier
.width(71.dp)
.height(56.dp)
.shadow(
if (selectedCardIndex == 1) 8.dp else 0.dp,
shape = RoundedCornerShape(11.dp)
)
.clickable {
selectedCardIndex = 1
viewModel.topUpAmount = 40.0
}
) {
Text(
"€40",
fontSize = 16.sp,
fontWeight = FontWeight.Normal,
textAlign = TextAlign.Center,
modifier = Modifier.wrapContentHeight()
)
}
Card(
shape = RoundedCornerShape(11.dp),
elevation = if (selectedCardIndex == 2) 1.dp else 0.dp,
backgroundColor = if (selectedCardIndex == 2) colorResource(id = R.color.bottom_modal_drawer_background) else colorResource(
id = R.color.more_screen_item_background
),
modifier = Modifier
.width(71.dp)
.height(56.dp)
.shadow(
if (selectedCardIndex == 2) 8.dp else 0.dp,
shape = RoundedCornerShape(11.dp)
)
.clickable {
selectedCardIndex = 2
viewModel.topUpAmount = 70.0
}
) {
Text(
"€70",
fontSize = 16.sp,
fontWeight = FontWeight.Normal,
textAlign = TextAlign.Center,
modifier = Modifier.wrapContentHeight()
)
}
Card(
shape = RoundedCornerShape(11.dp),
elevation = if (selectedCardIndex == 3) 1.dp else 0.dp,
backgroundColor = if (selectedCardIndex == 3) colorResource(id = R.color.bottom_modal_drawer_background) else colorResource(
id = R.color.more_screen_item_background
),
modifier = Modifier
.width(71.dp)
.height(56.dp)
.shadow(
if (selectedCardIndex == 3) 8.dp else 0.dp,
shape = RoundedCornerShape(11.dp)
)
.clickable {
selectedCardIndex = 3
viewModel.topUpAmount = 100.0
}
) {
Text(
"€100",
fontSize = 16.sp,
fontWeight = FontWeight.Normal,
textAlign = TextAlign.Center,
modifier = Modifier.wrapContentHeight()
)
}
}
}
Spacer(modifier = Modifier.padding(16.dp))
val focusManager = LocalFocusManager.current
val keyboardController = LocalSoftwareKeyboardController.current
TopUpCardView(title = stringResource(id = R.string.enter_custom_topup_amount)) {
var customAmountTxt by remember { mutableStateOf(TextFieldValue()) }
TextField(
value = customAmountTxt,
onValueChange = {
customAmountTxt = it
},
maxLines = 1,
singleLine = true,
leadingIcon = {
Icon(
painter = painterResource(id = R.drawable.ic_euro),
contentDescription = stringResource(
R.string.euro_icon_desc
),
modifier = Modifier.padding(
start = 16.dp,
end = 16.dp,
top = 12.dp,
bottom = 12.dp
)
)
},
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(onDone = {
focusManager.clearFocus()
keyboardController?.hide()
}),
shape = RoundedCornerShape(6.dp),
colors = TextFieldDefaults.textFieldColors(
backgroundColor = colorResource(id = R.color.white),
textColor = colorResource(id = R.color.black),
focusedIndicatorColor = colorResource(id = R.color.white),
unfocusedIndicatorColor = colorResource(id = R.color.white),
disabledIndicatorColor = colorResource(id = R.color.white),
cursorColor = colorResource(id = R.color.black)
),
textStyle = TextStyle(
color = Color.Black,
fontSize = 16.sp,
fontWeight = FontWeight.Normal,
textAlign = TextAlign.Start
),
modifier = Modifier
.height(50.dp)
.fillMaxWidth()
.shadow(8.dp, shape = RoundedCornerShape(6.dp))
)
}
Spacer(modifier = Modifier.padding(32.fixedDp()))
val context = LocalContext.current //todo:sp remove when you remove the toast
MyButton(
text = stringResource(id = R.string.continue_text),
buttonType = MyButtonType.PRIMARY,
onClick = {
Toast.makeText(context, "[TODO] Navigate to card screen", Toast.LENGTH_SHORT).show()
})
//todo:sp replace the spacer implementation with something that will constraint the
// footer to the bottom as it should
Spacer(modifier = Modifier.height(130.dp))
AcceptedCardsFooter()
BottomBarPadding()
}
}
TopUpCardView:
#Composable
fun TopUpCardView(
title: String,
modifier: Modifier = Modifier,
mainBody: #Composable () -> Unit
) {
Card(
shape = RoundedCornerShape(13.dp),
elevation = 10.dp,
modifier = modifier
.fillMaxWidth()
.height(131.dp)
) {
Column(modifier = Modifier.padding(vertical = 20.dp, horizontal = 16.dp)) {
Text(
text = title,
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Start
)
Spacer(modifier = Modifier.padding(9.dp))
mainBody()
}
}
}
Footer:
#Composable
fun AcceptedCardsFooter(isTransparent: Boolean = false) {
Row(modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(10.dp))
.background(
if (isTransparent) {
Color.Transparent
} else {
colorResource(id = R.color.registration_note_background)
}
)
.padding(bottom = 12.dp, top = 12.dp, start = 16.dp, end = 14.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(text = LocalContext.current.getString(R.string.accepted_cards),
fontSize = 12.sp,
color = colorResource(id = R.color.Black_100)
)
Row(verticalAlignment = Alignment.CenterVertically) {
Image(painter = painterResource(id = R.drawable.visa), contentDescription = "")
Spacer(modifier = Modifier.padding(17.fixedDp()))
Image(painter = painterResource(id = R.drawable.mastercard), contentDescription = "")
Spacer(modifier = Modifier.padding(10.fixedDp()))
Image(painter = painterResource(id = R.drawable.american_express), contentDescription = "")
}
}
}
The easiest way is to use weight modifier:
Spacer(modifier = Modifier.height(130.dp).weight(1f))
Add bottom padding to first Column for give space between content and bottombar. After that give weight to second Column for make footer constraint to the bottom.
For example,
Column(
modifier = Modifier.fillMaxSize().padding(bottom = 15.dp, start = 16.dp, end = 16.dp )
) {
Column(
modifier = Modifier.fillMaxSize().weight(1f).padding(horizontal = 16.dp)
) {
// top bar
// two cards
// button
}
// add footer here
}
I would use a ConstraintLayout and wrap the view you need to always be at the bottom of the screen.
ConstraintLayout {
// Create references for the composables to constrain
val id_of_your_footer = createRefs()
YourFooterComposable(
modifier = Modifier.constrainAs(id_of_your_footer) {
bottom.linkTo(parent.bottom)
}
)
}
As long as the parent is the root view, the Footer will be constrained to stay at the bottom of the screen.
Alternatively, you can use a scaffold that has these constraints set automatically:
Scaffold(topBar={//place a top bar composable here},
content={//all your content composables here},
bottomBar={//your footer composable here})
I want to add a vertical line to separate my 2 buttons but when I do this the line goes all the way to the bottom of the screen and I lose the Data content. But I want the line to go just after the button cap (they are not really buttons, they are text boxes).
How can I make the vertical line go to where I mark with the red line?
Scaffold(
topBar = {
TopAppBar( /* Config*/ )
},
content = {
Box(modifier = Modifier.fillMaxSize()) {
Column {
OptionButtons()
Divider()
Data( /* Component with a list with data */ )
}
}
}
)
#Composable
fun OptionButtons() {
Row {
Text(
text = "Option1",
color = OptionButtonText,
textAlign = TextAlign.Center,
modifier = Modifier
.weight(0.50f)
.padding(
PaddingValues(
start = 20.dp,
top = 12.dp,
end = 20.dp,
bottom = 12.dp
)
)
.clickable { }
)
Divide()
Text(
text = "Option2",
color = OptionButtonText,
textAlign = TextAlign.Center,
modifier = Modifier
.weight(0.50f)
.padding(
PaddingValues(
start = 20.dp,
top = 12.dp,
end = 20.dp,
bottom = 12.dp
)
)
.clickable { }
)
}
}
Just add this modifier = Modifier.height(IntrinsicSize.Min) in the Row to get minimum space for Row:
#Composable
fun OptionButtons() {
Row(
modifier = Modifier
.height(IntrinsicSize.Min),
horizontalArrangement = Arrangement.SpaceAround
) {
Text(
text = "Option1",
color = Color.Red,
textAlign = TextAlign.Center,
modifier = Modifier
.weight(0.50f)
.padding(
PaddingValues(
start = 20.dp,
top = 12.dp,
end = 20.dp,
bottom = 12.dp
)
)
.clickable { }
)
Divider(
modifier = Modifier
.width(1.dp)
.fillMaxHeight()
)
Text(
text = "Option2",
color = Color.Red,
textAlign = TextAlign.Center,
modifier = Modifier
.weight(0.50f)
.padding(
PaddingValues(
start = 20.dp,
top = 12.dp,
end = 20.dp,
bottom = 12.dp
)
)
.clickable { }
)
}
}
You have your text divider and text within a Row{ } block.
What you need to do is to structure it like this
Column{
Row{
Text()
Divider()
Text()
}
Divider()
Row{
Text()
Divider()
Text()
}
}
#Composable
fun OptionButtons() {
Column {
Row {
Text(
text = "Option1",
color = OptionButtonText,
textAlign = TextAlign.Center,
modifier = Modifier
.weight(0.50f)
.padding(
PaddingValues(
start = 20.dp,
top = 12.dp,
end = 20.dp,
bottom = 12.dp
)
)
.clickable { },
)
Divider(
modifier = Modifier
.fillMaxHeight()
.width(1.dp)
)
Text(
text = "Option2",
color = OptionButtonText,
textAlign = TextAlign.Center,
modifier = Modifier
.weight(0.50f)
.padding(
PaddingValues(
start = 20.dp,
top = 12.dp,
end = 20.dp,
bottom = 12.dp
)
)
.clickable { },
)
}
Divider(color = Color.Red, thickness = 1.dp)
Row {
Text(
text = ""//whatever value you want to populate with
textAlign = TextAlign . Center,
modifier = Modifier
.weight(0.50f)
.padding(
PaddingValues(
start = 20.dp,
top = 12.dp,
end = 20.dp,
bottom = 12.dp
)
)
)
Divider(
modifier = Modifier
.fillMaxHeight()
.width(1.dp)
)
Text(
text = ""//whatever value you want to populate with
textAlign = TextAlign . Center,
modifier = Modifier
.weight(0.50f)
.padding(
PaddingValues(
start = 20.dp,
top = 12.dp,
end = 20.dp,
bottom = 12.dp
)
)
)
}
}
}
}
I'm using constrainAs with Jetpack Compose to constrain a list of wifi options to the top of the parent and then to the bottom of a text view. As seen from the photo my list isn't being constrained to the top of the parent or to the textview below it, and it is even being pushed off the screen upwards?
For reference 'list' is the list of wifi options, and 'text1' is the textview that starts with "Select your wifi"
#Composable
fun ScanWifiScreen(wifiList: List<WifiOption>, onClick: (WifiOption) -> Unit) {
ConstraintLayout(
modifier = Modifier
.fillMaxSize()
.background(colorResource(id = R.color.background))
) {
val (list, text1, text2, progressIndicator) = createRefs()
WifiList(
wifiOptions = wifiList,
onClick = onClick,
modifier = Modifier
.constrainAs(list) {
top.linkTo(parent.top, margin = 8.dp)
bottom.linkTo(text1.top)
start.linkTo(parent.start)
end.linkTo(parent.end)
}
.background(colorResource(id = R.color.background))
.fillMaxHeight())
Text(
text = stringResource(id = R.string.select_wifi),
modifier = Modifier
.wrapContentSize()
.padding(bottom = 16.dp)
.constrainAs(text1) {
bottom.linkTo(text2.top)
start.linkTo(parent.start)
end.linkTo(parent.end)
},
style = TextStyle(
fontFamily = FontFamily(Font(R.font.quicksand_regular)),
fontSize = 20.sp,
color = colorResource(id = R.color.main_text),
letterSpacing = 0.22.sp,
textAlign = TextAlign.Center,
lineHeight = 32.sp
)
)
Text(
text = stringResource(id = R.string.cant_see_network),
modifier = Modifier
.wrapContentSize()
.padding(bottom = 32.dp)
.constrainAs(text2) {
bottom.linkTo(progressIndicator.top)
start.linkTo(parent.start)
end.linkTo(parent.end)
},
style = TextStyle(
fontFamily = FontFamily(Font(R.font.quicksand_regular)),
fontSize = 16.sp,
color = colorResource(id = R.color.sub_text),
letterSpacing = 0.18.sp,
textAlign = TextAlign.Center,
lineHeight = 24.sp
)
)
ProgressIndicator2(
progression = 3,
modifier = Modifier.constrainAs(progressIndicator) {
bottom.linkTo(parent.bottom)
start.linkTo(parent.start)
end.linkTo(parent.end)
})
}
}
In your List remove the .fillMaxHeight() modifier and add the constraint height = Dimension.fillToConstraints
WifiList(
//....
modifier = Modifier
.constrainAs(list) {
top.linkTo(parent.top, margin = 8.dp)
bottom.linkTo(text1.top)
start.linkTo(parent.start)
end.linkTo(parent.end)
height = Dimension.fillToConstraints
}
)