Skip to content

Commit

Permalink
Replaced nested Column/Row composable tree with LazyVerticalGrid comp…
Browse files Browse the repository at this point in the history
…osable to fix column width issues from Issue #1 and Issue #2.

Defaults to horizontally center within the column.  IconText items are start aligned.

Items are vertically centered within the row.
  • Loading branch information
jpaoneMines committed Jun 8, 2023
1 parent 10fbbc9 commit a8761e0
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import androidx.compose.material3.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.Alignment.Companion.CenterVertically
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
Expand Down Expand Up @@ -38,13 +40,16 @@ fun MultiStateIconTextSwitch(
borderWidth: Dp = 2.dp,
innerPaddingVertical: Dp = 16.dp,
innerPaddingHorizontal: Dp = 16.dp,
contentAlignment: Alignment = Alignment.CenterStart,
onSelect: (selectedIndex: Int) -> Unit
) {
val iconContent: MutableList<@Composable () -> Unit> = mutableListOf()
icons.forEachIndexed { index, iconVector ->
val contentDescription = if(index < contentDescriptions.size) { contentDescriptions[index] } else { null }
iconContent += {
Row {
Row(
verticalAlignment = CenterVertically
) {
Icon(
imageVector = iconVector,
contentDescription = contentDescription,
Expand Down Expand Up @@ -73,6 +78,7 @@ fun MultiStateIconTextSwitch(
borderWidth = borderWidth,
innerPaddingVertical = innerPaddingVertical,
innerPaddingHorizontal = innerPaddingHorizontal,
contentAlignment = contentAlignment,
onSelect = onSelect
)
}
Expand All @@ -95,6 +101,7 @@ fun MultiStateIconTextSwitchRow(
borderWidth: Dp = 2.dp,
innerPaddingVertical: Dp = 16.dp,
innerPaddingHorizontal: Dp = 16.dp,
contentAlignment: Alignment = Alignment.CenterStart,
onSelect: (selectedIndex: Int) -> Unit
) {
MultiStateIconTextSwitch(
Expand All @@ -115,6 +122,7 @@ fun MultiStateIconTextSwitchRow(
borderWidth = borderWidth,
innerPaddingVertical = innerPaddingVertical,
innerPaddingHorizontal = innerPaddingHorizontal,
contentAlignment = contentAlignment,
onSelect = onSelect
)
}
Expand All @@ -137,6 +145,7 @@ fun MultiStateIconTextSwitchColumn(
borderWidth: Dp = 2.dp,
innerPaddingVertical: Dp = 16.dp,
innerPaddingHorizontal: Dp = 16.dp,
contentAlignment: Alignment = Alignment.CenterStart,
onSelect: (selectedIndex: Int) -> Unit
) {
MultiStateIconTextSwitch(
Expand All @@ -157,13 +166,14 @@ fun MultiStateIconTextSwitchColumn(
borderWidth = borderWidth,
innerPaddingVertical = innerPaddingVertical,
innerPaddingHorizontal = innerPaddingHorizontal,
contentAlignment = contentAlignment,
onSelect = onSelect
)
}

@Preview(showBackground = true)
@Composable
private fun PreviewMultiStateIconSwitchTwoOptions() {
private fun PreviewMultiStateIconTextSwitchTwoOptions() {
val selectedIndexState = remember { mutableStateOf(0) }
val icons = arrayOf(Icons.Rounded.Email, Icons.Rounded.AccountBox)
val contentDescriptions = arrayOf("Email", "Account")
Expand All @@ -179,7 +189,7 @@ private fun PreviewMultiStateIconSwitchTwoOptions() {

@Preview(showBackground = true)
@Composable
private fun PreviewMultiStateIconSwitchRowTwoOptions() {
private fun PreviewMultiStateIconTextSwitchRowTwoOptions() {
val selectedIndexState = remember { mutableStateOf(0) }
val icons = arrayOf(Icons.Rounded.Email, Icons.Rounded.AccountBox)
val contentDescriptions = arrayOf("Email", "Account")
Expand All @@ -195,7 +205,7 @@ private fun PreviewMultiStateIconSwitchRowTwoOptions() {

@Preview(showBackground = true)
@Composable
private fun PreviewMultiStateIconSwitchSevenOptionsNoContentDescriptions() {
private fun PreviewMultiStateIconTextSwitchSevenOptionsNoContentDescriptions() {
val selectedIndexState = remember { mutableStateOf(0) }
val icons = arrayOf(Icons.Rounded.Email, Icons.Rounded.AccountBox, Icons.Rounded.Share, Icons.Rounded.Favorite, Icons.Rounded.ShoppingCart, Icons.Rounded.ExitToApp, Icons.Rounded.Face)
val contentDescriptions = arrayOf<String>()
Expand All @@ -211,7 +221,7 @@ private fun PreviewMultiStateIconSwitchSevenOptionsNoContentDescriptions() {

@Preview(showBackground = true)
@Composable
private fun PreviewMultiStateIconSwitchColumnSevenOptions() {
private fun PreviewMultiStateIconTextSwitchColumnSevenOptions() {
val selectedIndexState = remember { mutableStateOf(0) }
val icons = arrayOf(Icons.Rounded.Email, Icons.Rounded.AccountBox, Icons.Rounded.Share, Icons.Rounded.Favorite, Icons.Rounded.ShoppingCart, Icons.Rounded.ExitToApp, Icons.Rounded.Face)
val contentDescriptions = arrayOf("Email", "Account", "Share", "Favorite", "Shopping Cart", "Exit", "Face")
Expand All @@ -227,7 +237,7 @@ private fun PreviewMultiStateIconSwitchColumnSevenOptions() {

@Preview(showBackground = true)
@Composable
private fun PreviewMultiStateIconSwitchColumn3SevenOptions() {
private fun PreviewMultiStateIconTextSwitchColumn3SevenOptions() {
val selectedIndexState = remember { mutableStateOf(0) }
val icons = arrayOf(Icons.Rounded.Email, Icons.Rounded.AccountBox, Icons.Rounded.Share, Icons.Rounded.Favorite, Icons.Rounded.ShoppingCart, Icons.Rounded.ExitToApp, Icons.Rounded.Face)
val contentDescriptions = arrayOf("Email", "Account", "Share", "Favorite", "Shopping Cart", "Exit", "Face")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.itemsIndexed
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.*
Expand All @@ -13,6 +17,7 @@ import androidx.compose.material3.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.draw.clip
import androidx.compose.ui.graphics.Color
Expand Down Expand Up @@ -42,21 +47,20 @@ fun MultiStateSwitch(
borderWidth: Dp = 2.dp,
innerPaddingVertical: Dp = 8.dp,
innerPaddingHorizontal: Dp = 16.dp,
contentAlignment: Alignment = Alignment.Center,
onSelect: (selectedIndex: Int) -> Unit
) {
val numItems = options.size
val numColumns = when (orientation) {
MultiStateSwitchOrientation.HORIZONTAL -> numItems+1
MultiStateSwitchOrientation.HORIZONTAL -> numItems
MultiStateSwitchOrientation.VERTICAL -> 1
MultiStateSwitchOrientation.COLUMNS_2 -> 2
MultiStateSwitchOrientation.COLUMNS_3 -> 3
MultiStateSwitchOrientation.COLUMNS_4 -> 4
MultiStateSwitchOrientation.COLUMNS_5 -> 5
}
val numLastRow = numItems % numColumns
val numRows = (numItems / numColumns) + if(numLastRow > 0) {1} else {0}

Column (
LazyVerticalGrid(
modifier = Modifier
.clip(shape = RoundedCornerShape(roundedCornerShapeSize))
.background(backgroundColor)
Expand All @@ -65,31 +69,29 @@ fun MultiStateSwitch(
color = outlineColor,
shape = RoundedCornerShape(roundedCornerShapeSize)
)
.widthIn(min = 100.dp),
columns = GridCells.Fixed(numColumns),
state = rememberLazyGridState()
) {
for (i in 0 until numRows) {
Row{
for (j in 0 until numColumns) {
if (i == numRows-1 && j > numLastRow-1 && numLastRow > 0) break

val index = i * numColumns + j
val optionComposable = options[index]

Box(
modifier = Modifier
.clip(shape = RoundedCornerShape(roundedCornerShapeSize))
.clickable { onSelect(index) }
.background(
if (index == selectedIndex) {
selectedBackgroundColor
} else {
unselectedBackgroundColor
}
)
.padding(vertical = innerPaddingVertical, horizontal = innerPaddingHorizontal)
) {
optionComposable()
}
}
itemsIndexed(options) { index, optionComposable ->
Box(
modifier = Modifier
.clip(shape = RoundedCornerShape(roundedCornerShapeSize))
.clickable { onSelect(index) }
.background(
if (index == selectedIndex) {
selectedBackgroundColor
} else {
unselectedBackgroundColor
}
)
.padding(
vertical = innerPaddingVertical,
horizontal = innerPaddingHorizontal
),
contentAlignment = contentAlignment
) {
optionComposable()
}
}
}
Expand All @@ -107,6 +109,7 @@ fun MultiStateSwitchRow(
borderWidth: Dp = 2.dp,
innerPaddingVertical: Dp = 8.dp,
innerPaddingHorizontal: Dp = 16.dp,
contentAlignment: Alignment = Alignment.Center,
onSelect: (selectedIndex: Int) -> Unit
) {
MultiStateSwitch(
Expand All @@ -121,6 +124,7 @@ fun MultiStateSwitchRow(
borderWidth = borderWidth,
innerPaddingVertical = innerPaddingVertical,
innerPaddingHorizontal = innerPaddingHorizontal,
contentAlignment = contentAlignment,
onSelect = onSelect
)
}
Expand All @@ -137,6 +141,7 @@ fun MultiStateSwitchColumn(
borderWidth: Dp = 2.dp,
innerPaddingVertical: Dp = 16.dp,
innerPaddingHorizontal: Dp = 8.dp,
contentAlignment: Alignment = Alignment.Center,
onSelect: (selectedIndex: Int) -> Unit
) {
MultiStateSwitch(
Expand All @@ -151,6 +156,7 @@ fun MultiStateSwitchColumn(
borderWidth = borderWidth,
innerPaddingVertical = innerPaddingVertical,
innerPaddingHorizontal = innerPaddingHorizontal,
contentAlignment = contentAlignment,
onSelect = onSelect
)
}
Expand Down Expand Up @@ -232,6 +238,27 @@ private fun PreviewMultiStateSwitchFourTextDifferentLengthsHorizontalOptions() {
)
}

@Preview(showBackground = true)
@Composable
private fun PreviewMultiStateSwitchFourTextDifferentLengthsGridOptions() {
val selectedTextColor: Color = MaterialTheme.colorScheme.onPrimary
val unselectedTextColor: Color = MaterialTheme.colorScheme.outline
val selectedIndexState = remember { mutableStateOf(0) }
val textContent: MutableList<@Composable () -> Unit> = mutableListOf()
textContent += { Text(text = "Alpha", color = if(0 == selectedIndexState.value) { selectedTextColor } else { unselectedTextColor }) }
textContent += { Text(text = "Beta", color = if(1 == selectedIndexState.value) { selectedTextColor } else { unselectedTextColor }) }
textContent += { Text(text = "Epsilon", color = if(2 == selectedIndexState.value) { selectedTextColor } else { unselectedTextColor }) }
textContent += { Text(text = "Gamma", color = if(3 == selectedIndexState.value) { selectedTextColor } else { unselectedTextColor }) }
MultiStateSwitch(
options = textContent.toTypedArray(),
orientation = MultiStateSwitchOrientation.COLUMNS_2,
selectedIndex = selectedIndexState.value,
onSelect = {
selectedIndexState.value = it
}
)
}

@Preview(showBackground = true)
@Composable
private fun PreviewMultiStateSwitchFourTextDifferentLengthsVerticalOptions() {
Expand Down

0 comments on commit a8761e0

Please sign in to comment.