What I have is a column with vertical scroll, as components in it can be added/removed dynamically. What I am trying to achieve is position the button on the bottom of the screen, if the components don't fill it, and position it below them in the scrollable column if they do. I have implemented a solution, but it doesn't work perfectly at the threshold where the content height is near the screen height. I am wondering if there is a better way to achieve this effect. Any help is greatly appreciated!
BoxWithConstraints {
val screenHeight = constraints.maxHeight
val contentHeight = remember { mutableStateOf(0) }
val bottomLayoutHeight = remember { mutableStateOf(0) }
Column(
Modifier
.fillMaxWidth()
.verticalScroll(rememberScrollState())
.onGloballyPositioned { coordinates ->
contentHeight.value = coordinates.size.height
}
.padding(horizontal = Constants.HORIZONTAL_PADDING)
) {
// Indefinite views here
// ...
// If content does not fit within the screen, place the button inside the scrollable column
if (contentHeight.value + bottomLayoutHeight.value >= screenHeight) {
Column(Modifier.onGloballyPositioned { bottomLayoutHeight.value = it.size.height }) {
BottomLayout(viewModel)
}
}
}
// If content fits within the screen, place the button outside the scrollable column
if (contentHeight.value + bottomLayoutHeight.value < screenHeight) {
Column(Modifier
.fillMaxSize()
.padding(horizontal = Constants.HORIZONTAL_PADDING),
verticalArrangement = Arrangement.Bottom
) {
Column(Modifier.onGloballyPositioned { bottomLayoutHeight.value = it.size.height }) {
BottomLayout(viewModel)
}
}
}
}
** UPDATE Code is modified to work perfectly even at thresholds. What I was missing was calculating the bottom layout height and adding it to the content height, to determine if its more or less than the screen height! ^^
You can detect whether the LazyColumn
is scrollable or not. Then, if it is scrollable, display the button as the last element in the LazyColumn
, otherwise display it at the bottom of the screen.
Please try the following code:
Column(
horizontalAlignment = Alignment.End
) {
val scrollState = rememberLazyListState()
val canScroll by remember {
derivedStateOf { scrollState.canScrollForward || scrollState.canScrollBackward }
}
LazyColumn(
modifier = Modifier.weight(1f),
horizontalAlignment = Alignment.End,
state = scrollState
) {
items(50) {
Text(modifier = Modifier
.padding(16.dp)
.fillMaxWidth(), text = "ITEM $it");
}
item {
if (canScroll) {
Button(onClick = { /*TODO*/ }) {
Text(text = "BUTTON")
}
}
}
}
if (!canScroll) {
Button(onClick = { /*TODO*/ }) {
Text(text = "BUTTON")
}
}
}
Output with a short list on the left and a long list on the right: