Skip to content

Instantly share code, notes, and snippets.

@maxfie1d
Created March 31, 2023 06:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maxfie1d/70a5713bc74e2fa2cb5e0c76375b4060 to your computer and use it in GitHub Desktop.
Save maxfie1d/70a5713bc74e2fa2cb5e0c76375b4060 to your computer and use it in GitHub Desktop.
Custom list arrangement (LazyColumn, sticky footer)
package com.example.custom_list_arrangement
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.dp
import com.example.custom_list_arrangement.ui.theme.CustomlistarrangementTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
CustomlistarrangementTheme {
var isMany by remember { mutableStateOf(false) }
val itemCount = if (isMany) 20 else 3
var selectedType by remember { mutableStateOf(ArrangementType.Normal) }
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
LazyColumn(
verticalArrangement = CustomArrangement(selectedType)
) {
item {
Box(
modifier = Modifier.padding(4.dp)
) {
Row(
verticalAlignment = Alignment.CenterVertically
) {
Text(text = "アイテムいっぱい")
Switch(checked = isMany, onCheckedChange = { isMany = !isMany })
TypeSelector(
selectedType = selectedType,
onTypeClick = {
selectedType = it
}
)
}
}
}
items(itemCount) { index ->
Text(
text = "Item ${index + 1}",
modifier = Modifier
.clickable { }
.padding(16.dp)
.fillMaxWidth()
)
}
item {
Text(
text = "footer",
modifier = Modifier
.clickable { }
.fillMaxWidth()
.background(Color.Yellow)
.padding(16.dp)
)
}
}
}
}
}
}
}
class CustomArrangement(
private val type: ArrangementType
) : Arrangement.Vertical {
override fun Density.arrange(
totalSize: Int, // LazyColumnの高さ?
sizes: IntArray, // それぞれのアイテムの高さ?
outPositions: IntArray // 描画位置の設定?
) {
when (type) {
ArrangementType.Normal -> {
var y = 0
sizes.forEachIndexed { index, size ->
outPositions[index] = y
y += size
}
}
ArrangementType.HalfSticky -> {
var y = 0
sizes.forEachIndexed { index, size ->
outPositions[index] = y
y += size
}
if (y < totalSize) {
val lastIndex = outPositions.lastIndex
outPositions[lastIndex] = totalSize - sizes.last()
}
}
ArrangementType.Sticky -> {
var y = 0
sizes.forEachIndexed { index, size ->
outPositions[index] = y
y += size
}
val lastIndex = outPositions.lastIndex
outPositions[lastIndex] = totalSize
}
ArrangementType.Spaced -> {
var y = 0
sizes.forEachIndexed { index, size ->
outPositions[index] = y
y += size + (20.dp.roundToPx())
}
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TypeSelector(
selectedType: ArrangementType,
onTypeClick: (ArrangementType) -> Unit
) {
val options = ArrangementType.values().toList()
var expanded by remember { mutableStateOf(false) }
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = { expanded = !expanded },
) {
TextField(
modifier = Modifier.menuAnchor(),
readOnly = true,
value = selectedType.toString(),
onValueChange = {},
colors = ExposedDropdownMenuDefaults.textFieldColors(),
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
label = { Text("Label") },
)
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
) {
options.forEach { selectionOption ->
DropdownMenuItem(
text = { Text(selectionOption.toString()) },
onClick = {
onTypeClick(selectionOption)
expanded = false
},
contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
)
}
}
}
}
enum class ArrangementType {
Normal,
HalfSticky,
Sticky, // Not working
Spaced;
}
@maxfie1d
Copy link
Author

maxfie1d commented Apr 2, 2023

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment