Align Box/Column to bottom of screen Jetpack Compose - android

I essentially want cards pinned to the top with a group of buttons pinned to the bottom (on screen keyboard)
Using Column with a modifier like so only leads to the buttons covering the top cards:
fun HomeScreen() {
Column(
modifier = Modifier
.fillMaxWidth(),
verticalArrangement = Arrangement.SpaceAround
) {
WordGrid()
}
Column(
modifier = Modifier
.fillMaxWidth(),
verticalArrangement = Arrangement.Bottom
) {
Keyboard()
}
I have tried using all the different Arrangements, using a row and using Boxes, but can't seem to get it to work.
Curiously, in the #Preview it looks as though the above code works, but when ran on an emulator they are both at the top of the screen.
Using a spacer is another option, but would this cause issues in other ways? maybe with screen sizes etc?

If you want your buttons row to be pinned to the bottom, you have to set the Column to have a weight of 1f, something like this
MyTheme {
Surface(color = MyTheme.colors.background) {
// Cards content
Column(
modifier = Modifier.fillMaxWidth()
) {
Column(
modifier = Modifier.fillMaxWidth().weight(1f)
) {
Card(
modifier = Modifier.fillMaxWidth().height(80.dp).padding(all = 16.dp),
backgroundColor = Color.Red,
) {
Text(text = "Card 1")
}
Card(
modifier = Modifier.fillMaxWidth().height(80.dp).padding(all = 16.dp),
backgroundColor = Color.Green,
) {
Text(text = "Card 2")
}
Card(
modifier = Modifier.fillMaxWidth().height(80.dp).padding(all = 16.dp),
backgroundColor = Color.Blue,
) {
Text(text = "Card 3")
}
}
// Buttons content
Row(
modifier = Modifier.fillMaxWidth()
) {
Button(
onClick = {},
modifier = Modifier.padding(horizontal = 8.dp)
) {
Text(text = "Button 1")
}
Button(
onClick = {},
modifier = Modifier.padding(horizontal = 8.dp)
) {
Text(text = "Button 3")
}
Button(
onClick = {},
modifier = Modifier.padding(horizontal = 8.dp)
) {
Text(text = "Button 2")
}
}
}
}
}

Related

Why is floating action button ttransparent even though it is colored and showing the list behind it Jetpack Compose

I have lazy list and a floating action button in the bottom end, the FAB has a color. But the floating action button in jetpack compose is showing the list in the background even thought it has a color. Even after adding the elevation it is not working. How to solve it?
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.fillMaxSize()
) {
androidx.compose.material3.FloatingActionButton(
containerColor = appColors.primary,
contentColor = appColors.primary,
elevation = FloatingActionButtonDefaults.elevation(8.dp),
shape = CircleShape,
onClick = {},
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(16.dp),
) {
Icon(Icons.Filled.Add, null, tint = Color.White)
}
if (viewModel.state.value.patientsList.isEmpty()) {
Text(
text = "No Patients Available",
style = FontLibrary.regularBody16(textAlign = TextAlign.Center)
)
} else {
LazyColumn(
modifier = Modifier
.padding(start = 8.dp, end = 8.dp)
.fillMaxSize()
) {
items(
items = viewModel.state.value.patientsList,
key = { patient ->
patient.id
}
) { patient ->
PatientCard(patient)
Divider(color = appColors.secondary, thickness = 1.dp)
}
}
}
}
In Jetpack compose UI components are placed in the order as you place them, so in box you have first placed Floating action button, and then the list.
You should place FAB in the end, i.e., move its code to the bottom.
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.fillMaxSize()
) {
if (viewModel.state.value.patientsList.isEmpty()) {
Text(
text = "No Patients Available",
style = FontLibrary.regularBody16(textAlign = TextAlign.Center)
)
} else {
LazyColumn(
modifier = Modifier
.padding(start = 8.dp, end = 8.dp)
.fillMaxSize()
) {
items(
items = viewModel.state.value.patientsList,
key = { patient ->
patient.id
}
) { patient ->
PatientCard(patient)
Divider(color = appColors.secondary, thickness = 1.dp)
}
}
}
androidx.compose.material3.FloatingActionButton(
containerColor = appColors.primary,
contentColor = appColors.primary,
shape = CircleShape,
onClick = {},
modifier = Modifier
.align(BottomEnd)
.padding(16.dp),
) {
Icon(Icons.Filled.Add, null, tint = Color.White)
}
}

Unable to change Elevation Color For Card in Jetpack Compose

I am using a Card in-order create different buttons.
I want my card to look exactly like shown in the image, and I tried many solutions online but none of that worked.
Just want to change Card elevation color, but can't find a way to do it.
Card(
elevation = 4.dp,
backgroundColor = Color.White,
modifier = Modifier
.fillMaxSize()
.padding(10.dp)
) {
Column(modifier = Modifier.padding(10.dp)) {
Text("Subscription", fontWeight = FontWeight.W700, color = brc_red)
Card(
backgroundColor = Color(0xFFBDFCBB).compositeOver(brc_green_color),
elevation = 6.dp,
modifier = Modifier
.fillMaxWidth()
.padding(20.dp)
.clickable {
Toast
.makeText(context, "Suiiiii", Toast.LENGTH_SHORT)
.show()
}
.drawWithContent {
val paddingPx = with(density) { 5.dp.toPx() }
clipRect(
left = -paddingPx,
top = 0f,
right = size.width + paddingPx,
bottom = size.height + paddingPx,
) {
this#drawWithContent.drawContent()
}
}
// backgroundColor = Color(0xFF4CB849).compositeOver(brc_green_color)
) {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier.padding(10.dp)
) {
Text(text = "Yearly")
Text(text = "$ 10 Per Year")
}
}
Card(
elevation = 6.dp,
backgroundColor = Color(0xFFFD6459).compositeOver(brc_green_color),
modifier = Modifier
.fillMaxWidth()
.padding(20.dp)
.clickable {
Toast
.makeText(context, "Duiii", Toast.LENGTH_SHORT)
.show()
}
.drawWithContent {
val paddingPx = with(density) { 5.dp.toPx() }
clipRect(
left = -paddingPx,
top = 0f,
right = size.width + paddingPx,
bottom = size.height + paddingPx,
) {
this#drawWithContent.drawContent()
}
},
) {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier.padding(10.dp)
) {
Text(text = "Monthly")
Text(text = "$ 1 Per Month")
}
}
Row(
horizontalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxWidth()
) {
Text(text = "OR", fontWeight = FontWeight.Bold)
}
Card(
modifier = Modifier
.fillMaxWidth()
.clickable {
Toast
.makeText(context, "Nuiii", Toast.LENGTH_SHORT)
.show()
}
.padding(20.dp),
elevation = 4.dp,
backgroundColor = brc_green_color
// backgroundColor = Color(0xFF4CB849).compositeOver(brc_green_color)
) {
Row(
horizontalArrangement = Arrangement.Center,
modifier = Modifier.padding(10.dp)
) {
Text(text = "Start your 30 days Free Trail", color = Color.White)
}
}
}
}
This is current Ui
This is what i want.
Please guide me one this, it will be really helpful.
Thanks in advance.
You can use the shadow modifier. For instance:
Card(backgroundColor = Color.White,
modifier = Modifier
.fillMaxSize().padding(10.dp)
.shadow(ambientColor = Color.Blue, elevation = 6.dp)
) {...}
You can use spotColor attribute of Modifier's shadow extension. You just have to make sure both the shadow and the Card have the same shape like having it instantiated outside, otherwise you'll end up having a sharp cornered shadow. You can also define the Card's elevation in the shadow without having the Card doing it.
val cardShape = RoundedCornerShape(16.dp)
Card(
modifier = Modifier
.shadow(
shape = cardShape,
spotColor = Color.Green,
elevation = 8.dp
),
shape = cardShape
) { ... }

Is there a way to process like a dialog without Dialog Composable?

With Jetpack Compose, I'm trying to implement a function to switch between items with flick actions, like the ViewPager in Android JetPack.
At first I tried to get it to work using a dialog as shown in the code below. However, I found that the dialog cannot be moved horizontally with flick actions.
#OptIn(ExperimentalPagerApi::class)
#Composable
fun ContentDisplayWindow(
openDialog: MutableState<Boolean>,
contentList: List<Content>,
) {
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
IconButton(
modifier = Modifier.align(Alignment.End),
onClick = { openDialog.value = false }
) {
Icon(
painter = painterResource(R.drawable.ic_arrow_back),
contentDescription = ""
)
}
HorizontalPager(
count = contentList.size
) { index ->
Dialog(
onDismissRequest = { openDialog.value = false },
properties = DialogProperties(dismissOnClickOutside = false)
) {
Column(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.border(2.dp, Color.Red)
.background(color = MaterialTheme.colors.surface)
) {
Text(
text = contentList[index].title,
modifier = Modifier.padding(
top = 10.dp,
bottom = 10.dp,
start = 20.dp
)
)
Spacer(modifier = Modifier.padding(vertical = 10.dp))
Text(
text = contentList[index].description,
modifier = Modifier.padding(
top = 10.dp,
bottom = 10.dp,
start = 20.dp
)
)
}
}
}
}
}
implementaton:
implementation "com.google.accompanist:accompanist-pager:0.25.1"
So I tried to find a way to perform the process of dimming the screen and disabling other buttons or input fields such as a dialog, but was not able to find it. Is there any other way to make it work like a dialog?

Expandable FAB going through bottom nav bar - Jetpack Compose

I made an expandable floating action button like
here
i want to make it expand verticly and reveal to more buttons, when its note docked to bottom navigation bar, every thing is ok but when i make it docked it's going through bottom nav bar,
When not expanded looking like this
but when expanded like this
How can i make it expand properly
and i also want to align all 3 circle buttons horizontaly.
Thank you so much!
Code:
#Composable
fun ExpandableFAB(
modifier: Modifier = Modifier,
onFabItemClicked: (fabItem: ExpandableFABMenuItem) -> Unit,
menuItems: List<ExpandableFABMenuItem> = ExpandableFABMenuItem.expandableFabMenuItems
) {
var expandedState by remember { mutableStateOf(false) }
val rotationState by animateFloatAsState(
targetValue = if (expandedState) 45f else 0f
)
Column(
modifier = modifier.wrapContentSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
AnimatedVisibility(
visible = expandedState,
enter = fadeIn() + expandVertically(),
exit = fadeOut()
) {
LazyColumn(
modifier = Modifier.wrapContentSize(),
horizontalAlignment = Alignment.End,
verticalArrangement = Arrangement.spacedBy(15.dp)
) {
items(menuItems.size) { index ->
ExpandableFABItem(
item = menuItems[index],
onFabItemClicked = onFabItemClicked
)
}
item {}
}
}
FloatingActionButton(
onClick = { expandedState = !expandedState },
backgroundColor = Blue
) {
Icon(
imageVector = Icons.Outlined.Add,
contentDescription = "FAB",
modifier = Modifier.rotate(rotationState),
)
}
}
}
#Composable
fun ExpandableFABItem(
item: ExpandableFABMenuItem,
onFabItemClicked: (item: ExpandableFABMenuItem) -> Unit
) {
Row(
modifier = Modifier
.wrapContentSize()
.padding(end = 10.dp),
horizontalArrangement = Arrangement.spacedBy(10.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = item.label,
fontSize = 12.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier
.background(MaterialTheme.colors.surface)
.padding(horizontal = 6.dp, vertical = 4.dp)
)
Box(
modifier = Modifier
.clip(CircleShape)
.size(42.dp)
.clickable { onFabItemClicked }
.background(Blue),
contentAlignment = Alignment.Center
) {
Icon(
imageVector = item.icon,
contentDescription = "Create New Note",
tint = White
)
}
}
}

How to optimise laggy JetPack Compose layout

I'm using a HorizontalPager from accompanist package. The pager will have 1 page for each exercise stored by the user.
Each page in the pager has a LazyColumn which contain multiple cards with controls such as IconButtons and BasicTextField. The number of cards depends on number of sets configured by the user. I expect the typical number to be between 1 to 8 but only 3 to 5 would be visible on the screen at any given time (depending on the screen size and resolution).
The issue is that when this layout produces noticeable lag (animations skip frames) every time the HorizontalPager needs to build a new page that has more than 3 cards. This happens when swapping between pages. The same happens in debug and release versions running on a real device (Galaxy S10e) and emulator.
I'm trying to optimise this layout, so each frame renders in no more than 16ms regardless of the number of cards shown on the screen.
I've previously tried to solve this issue by setting fixed heights to some composables but that didn't help much. I've also tried using Text instead of BasicTextField, which would be then replaced with BasicTextField when users taps on the text but this hasn't helped much, therefore I removed this implementation.
Do you have some suggestions how performance of this layout could be improved to eliminate the lag?
Below is my code, screen shoot of the app screen and profiler:
#ExperimentalPagerApi
#Composable
fun WorkoutSessionScreen(
navHostController: NavHostController,
) {
val pagerState = rememberPagerState()
Scaffold(
topBar = { MyTopAppBar(navHostController = navHostController) }
) {
Box(
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth()
.background(MaterialTheme.colors.background)
.imePadding()
) {
HorizontalPager(
count = 10, state =
pagerState,
itemSpacing = 16.dp
) {
Log.e("==>", "Building horizontal pager")
TrackingControls()
}
Box(
modifier = Modifier
.height(70.dp)
.fillMaxWidth()
.background(Color(0xFAF7F7FF))
.align(Alignment.BottomCenter)
) {
Column(
Modifier.fillMaxWidth()
) {
Divider(color = Color(0x2A5C5C5C))
BottomControls()
}
}
}
}
}
#Composable
private fun TrackingControls() {
LazyColumn(
Modifier
.fillMaxHeight()
.fillMaxWidth(),
contentPadding = PaddingValues(vertical = 8.dp)
) {
items(6) { item ->
SetsAndRepsTrackingControls(
modifier = Modifier
)
}
}
}
#Composable
private fun BottomControls() {
Text(text = "Bottom Controlls")
}
#Composable
fun SetsAndRepsTrackingControls(modifier: Modifier = Modifier) {
val add = painterResource(id = R.drawable.ic_round_add_24)
val remove = painterResource(id = R.drawable.ic_round_remove_24)
Card(
modifier
.fillMaxWidth()
.height(200.dp)
.padding(vertical = 16.dp, horizontal = 8.dp),
backgroundColor = MaterialTheme.colors.surface,
shape = RoundedCornerShape(12.dp),
) {
Column() {
ControlsHeader()
TrackingInput(label = "REPS", add, remove)
Divider(color = Color.LightGray)
TrackingInput(label = "WEIGHT (KG)", add, remove)
}
}
}
#Composable
private fun ControlsHeader() {
Row(
modifier = Modifier
.height(56.dp)
.fillMaxWidth()
.background(MaterialTheme.colors.primary, RoundedCornerShape(12.dp))
.padding(horizontal = 16.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(text = "Set 1")
Text(text = "CheckBox")
}
}
#Composable
private fun TrackingInput(label: String = "Preview", add: Painter, remove: Painter) {
Row(
modifier = Modifier
.fillMaxWidth()
.height(60.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
IconButton(onClick = {}) {
Icon(
painter = painterResource(id = R.drawable.ic_round_remove_24),
contentDescription = "Minus",
tint = MaterialTheme.colors.onSurface
)
}
Column(
horizontalAlignment = Alignment.CenterHorizontally
) {
BasicTextField(
singleLine = true,
value = "8",
onValueChange = {},
textStyle = TextStyle(
textAlign = TextAlign.Center,
color = MaterialTheme.colors.onSurface
),
)
Spacer(modifier = Modifier.height(4.dp))
Text(
text = label,
style = MaterialTheme.typography.overline.copy(color = MaterialTheme.colors.onSurface)
)
}
IconButton(onClick = { Log.d("==>", "tada") }) {
Icon(
painter = painterResource(id = R.drawable.ic_round_add_24),
contentDescription = "Minus",
tint = MaterialTheme.colors.onSurface
)
}
}
}
This profiler print screen shows rendering of a single card called SetsAndRepsTrackingControls

Categories

Resources