Here is something that many applications end up adding: an options screen.
Sample program:
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Switch
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.singleWindowApplication
fun main() = singleWindowApplication {
MaterialTheme {
val (showSwitch1, setShowSwitch1) = remember { mutableStateOf(false) }
val (showSwitch2, setShowSwitch2) = remember { mutableStateOf(true) }
val (showSwitch3, setShowSwitch3) = remember { mutableStateOf(true) }
Column(modifier = Modifier.padding(8.dp)) {
@Composable
fun booleanSettingsItem(text: String, value: Boolean, valueSetter: (Boolean) -> Unit) {
Row(verticalAlignment = Alignment.CenterVertically) {
Text(text)
Switch(value, valueSetter)
}
}
booleanSettingsItem(
"A switch",
showSwitch1, setShowSwitch1
)
booleanSettingsItem(
"Another switch",
showSwitch2, setShowSwitch2
)
booleanSettingsItem(
"A third switch with an even longer label",
showSwitch3, setShowSwitch3
)
}
}
}
The result:
But as you can see, the switches don't line up.
What's the proper way to get a two-column layout so that all the value fields align? (Over in Swing, you can lean heavily on GroupLayout
, and forms become fairly simple, if verbose.)
I did try some of the "grid" layouts provided by Compose, but they really seem more tailored to situations where every cell is the same size..? If that makes any sense.
Attempt 1: @JakubMroziński 's answer suggests putting two columns inside the row. That does sound logical as far as how you would lay it out on paper, so here we go, new sample program:
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Switch
import androidx.compose.material.Text
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.window.singleWindowApplication
fun main() = singleWindowApplication {
MaterialTheme {
val (showSwitch1, setShowSwitch1) = remember { mutableStateOf(false) }
val (showSwitch2, setShowSwitch2) = remember { mutableStateOf(true) }
val (showSwitch3, setShowSwitch3) = remember { mutableStateOf(true) }
Row {
Column {
Text("A switch")
Text("Another switch")
Text("A third switch with an even longer label")
}
Column {
Switch(showSwitch1, setShowSwitch1)
Switch(showSwitch2, setShowSwitch2)
Switch(showSwitch3, setShowSwitch3)
}
}
}
}
But now the result is:
This makes sense, because now there is no row to align the labels and the switches.
Attempt 2: The other similar question had an answer which suggested using LazyVerticalGrid
. So here is a version using that.
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Switch
import androidx.compose.material.Text
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.singleWindowApplication
fun main() = singleWindowApplication {
MaterialTheme {
val (showSwitch1, setShowSwitch1) = remember { mutableStateOf(false) }
val (showSwitch2, setShowSwitch2) = remember { mutableStateOf(true) }
val (showSwitch3, setShowSwitch3) = remember { mutableStateOf(true) }
LazyVerticalGrid(
modifier = Modifier.padding(16.dp),
columns = GridCells.Fixed(2)
) {
item { Text("A switch") }
item { Switch(showSwitch1, setShowSwitch1) }
item { Text("Another switch") }
item { Switch(showSwitch2, setShowSwitch2) }
item { Text("A third switch with an even longer label") }
item { Switch(showSwitch3, setShowSwitch3) }
}
}
}
The result:
It's nearly good enough, but I want the first column to take as much space as possible, and the second column to take only what's necessary. Is there a way? Or do I have to resort to custom layout?
For simple layouts in Compose it is enough to use only
Row
andColumn
functions.If you want to create two columns, you simply create a
Row
and put twoColumn
s inside, like that:If you want your layout to take whole window size, you can put
Modifier.fillMaxSize()
asRow
's modifier. You can also adjust each column's width usingModifier.fillMaxWidth(screenPercentage)
.To align content in column you should use
horizontalAlignment
parameter ofColumn
function. If you want it to be centered, just useAlignment.CenterHorizontally
.