how to align button bottom center in jetpack compose?

6.1k Views Asked by At

I've been trying to align a button in Column from the bottom to the center for a while, but I couldn't succeed.

hear is my code:

NutritionHabitsScreen

@Composable
fun NutritionHabitsRoute(
    navHostController: NavHostController,
    sharedViewModel: SharedViewModel,
    viewModel: NutritionHabitsViewModel = hiltViewModel()
) {

    val state by viewModel.state.collectAsState()

    NutritionHabit(
        navHostController = navHostController,
        sharedViewModel = sharedViewModel,
        state = state,
        buttonEnabled = viewModel::buttonEnabled
    )
}

@Composable
fun NutritionHabit(
    navHostController: NavHostController,
    sharedViewModel: SharedViewModel,
    state: NutritionHabitsScreenState,
    buttonEnabled: (MutableList<Int>, MutableList<Int>) -> Unit
) {


    val firstChoicesItems = sharedViewModel.registerItems?.choices?.get(0)?.items
    val secondChoicesItems = sharedViewModel.registerItems?.choices?.get(1)?.items

    var firstSelectedIndexes = remember { mutableListOf<Int>() }
    var secondSelectedIndexes = remember { mutableListOf<Int>() }

    Scaffold(
        topBar = { BackPopUp(navController = navHostController, route = null) },
        backgroundColor = Color.Transparent
    ) {

        Column(
            modifier = Modifier
                .fillMaxSize()
                .verticalScroll(rememberScrollState())
        ) {

            CustomText(
                padding = 15.dp,
                text = sharedViewModel.registerItems!!.choices[0].title ?: "",
                textStyle = MaterialTheme.typography.h3
            )

            firstChoicesItems?.let {
                it.forEachIndexed { index, element ->
                    CustomButton(
                        selectedIndexes = firstSelectedIndexes,
                        index = index,
                        borderDp = 2.dp,
                        textPadding = 15.dp,
                        topPadding = 5.dp,
                        bottomPadding = 5.dp,
                        startPadding = 15.dp,
                        endPadding = 15.dp,
                        text = firstChoicesItems[index].key ?: "",
                        selectedBorderColor = DefaultDYTColor,
                        unselectedBorderColor = MaterialTheme.colors.grayColor,
                        onSelected = { list ->
                            firstSelectedIndexes = list
                            buttonEnabled(firstSelectedIndexes, secondSelectedIndexes)
                        }
                    )
                }
            }
            
            CustomText(
                padding = 15.dp,
                text = sharedViewModel.registerItems!!.choices[1].title ?: "",
                textStyle = MaterialTheme.typography.h3
            )

            secondChoicesItems?.let {
                it.forEachIndexed { index, items ->
                    CustomButton(
                        selectedIndexes = secondSelectedIndexes,
                        index = index,
                        borderDp = 2.dp,
                        textPadding = 15.dp,
                        topPadding = 5.dp,
                        bottomPadding = 5.dp,
                        startPadding = 15.dp,
                        endPadding = 15.dp,
                        text = secondChoicesItems[index].key ?: "",
                        selectedBorderColor = DefaultDYTColor,
                        unselectedBorderColor = MaterialTheme.colors.grayColor,
                        onSelected = { list ->
                            secondSelectedIndexes = list
                            buttonEnabled(firstSelectedIndexes, secondSelectedIndexes)
                        }
                    )
                }
            }

            DYTLoginAndContinueButton(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(16.dp),
                text = stringResource(id = R.string.devam),
                navController = navHostController,
                route = null,
                enabled = state.buttonEnabled
            ) {}
        }
    }
}

My Custom button

@Composable
fun DYTLoginAndContinueButton(
    modifier:Modifier,
    text: String,
    navController: NavController?,
    route: String?,
    enabled: Boolean,
    onClick: () -> Unit
) {

    Button(
        onClick = {
            onClick()
            if(navController != null && route !=null)
                navController.navigate(route)
        },
        modifier = modifier,
        enabled = enabled,
        elevation = ButtonDefaults.elevation(0.dp, 0.dp),
        colors = ButtonDefaults.buttonColors(backgroundColor = DefaultDYTColor),
        shape = RoundedCornerShape(25.dp)
    ) {
        Text(
            modifier = Modifier.padding(8.dp),
            text = text,
            textAlign = TextAlign.Center,
            style = MaterialTheme.typography.button,
            color = Color.White
        )
    }
}

As you can see, there are multiple components in the column and there is a custom button I created at the bottom DYTLoginAndContinueButton, I want to align it to the bottom center of the screen. I tried some things and it happened when I succeeded, but for some reason the button was not visible on small screens, I couldn't understand why. This is the latest version of my code. At the moment, it does not appear aligned in the center at the bottom of the screen on large screens, and on small screens, it seems to be localized to the very end because the screen is already small. I want it to appear properly in the center at the bottom of the screen on both small screens and large screens. Anyone have a suggestion?

2

There are 2 best solutions below

1
Gabriele Mariotti On BEST ANSWER

You have to use something different. You can't put the Button in the Column with a verticalScroll. Move the Button outside the Column and just apply a weight modifier to the same Column.

Something like:

    Column(
        Modifier.fillMaxHeight(),
        verticalArrangement = Arrangement.SpaceBetween
    ) {

        Column(
            modifier = Modifier
                .verticalScroll(rememberScrollState())
                .weight(1f, false)
        ) {
            //...
        }

        Button(
            onClick = {},
            modifier = Modifier
                .padding(vertical = 2.dp)
                .fillMaxWidth()
        ) {
            Text("Button")
        }
    }

}

enter image description here

3
Adam Pałkowski On

Adding

 Spacer(modifier = Modifier.weight(1f))

in the column above the DYTLoginAndContinueButton will make the button go to the bottom of the screen on large screen. The issue with it not being visible on the smaller screens is probably that the firstChoicesItem and secondChoicesItem fill most of the screen and to see the button you have to scroll down. If you want it aligned at the bottom without scrolling, you could do something like.

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun NutritionHabit(
) {

    Scaffold(
        topBar = { },
    ) { it->
        Box(modifier=Modifier.fillMaxSize()){
            Column(
                modifier = Modifier
                    .align(Alignment.TopCenter)
                    .padding(it)
                    .fillMaxSize()
                    .verticalScroll(rememberScrollState())
            ) { 
                // column content goes here
                
            }
            
            DYTLoginAndContinueButton(
                modifier = Modifier
                    .align(Alignment.BottomCenter)
                    .fillMaxWidth()
                    .padding(16.dp),
                text ="Button",
                route = null,
                enabled = true, navController = null) {}
        }


    }
}