Jetpack Composeでアコーディオン(Accordion)を作ってみた!
Jetpack Composeでアプリを作りながら、ふと「マテリアルデザインにアコーディオンってあるのかな?」と思い調べたところ、メニュー(Menus)しかありませんでした。。。
なので作ってみました
上記の内容がすべてですが、一応この下に使い方としてプレビューを載せておきます
@Preview(
name = "DefaultPreviewDark",
apiLevel = 33,
showBackground = true,
uiMode = Configuration.UI_MODE_NIGHT_NO,
)
@Preview(
name = "DefaultPreviewDark",
apiLevel = 33,
showBackground = true,
uiMode = Configuration.UI_MODE_NIGHT_YES,
)
@Composable
private fun AccordionPreview() {
YourAppTheme { // ご自身のThemeに変更してください
Surface(
modifier = Modifier
.fillMaxSize(),
color = MaterialTheme.colorScheme.background,
) {
val elevation = 8.dp
val cornerRadius = 8.dp
val cornerShape = RoundedCornerShape(
size = cornerRadius
)
val baseModifier = Modifier
.shadow(
elevation = elevation,
shape = cornerShape,
)
.clip(
shape = cornerShape,
)
.background(
color = MaterialTheme.colorScheme.surface
)
var isHeaderClicked by rememberSaveable { mutableStateOf(false) }
val accordionHeaderProp = AccordionHeaderProp(
modifier = baseModifier,
onClick = {
isHeaderClicked = !isHeaderClicked
},
leadingIcon = {
val dropArrowIconRotation by animateFloatAsState(
targetValue = if (isHeaderClicked) 0f else -90f,
label = "Drop to up and up to drop arrow animation",
)
Icon(
imageVector = Icons.Filled.ArrowDropDown,
modifier = Modifier
.rotate(
degrees = dropArrowIconRotation,
),
contentDescription = null,
tint = MaterialTheme.colorScheme.onSurface,
)
},
trailingIcon = {
val iconContainerSize = 48.dp
Box(
modifier = modifier
.size(
size = iconContainerSize
),
contentAlignment = Alignment.Center
) {
Icon(
imageVector = Icons.Filled.Delete,
contentDescription = null,
tint = MaterialTheme.colorScheme.onSurface,
)
}
},
) {
TextField(
value = "",
onValueChange = {},
enabled = false,
modifier = Modifier
.fillMaxWidth(),
placeholder = {
Text(
text = "ヘッダー click=${isHeaderClicked}",
modifier = Modifier
.fillMaxWidth(),
)
},
)
}
val accordionVisibilityAnimation = AccordionVisibilityAnimation(
modifier = Modifier
.padding(
start = 8.dp,
end = 8.dp,
),
enter = scaleIn(),
exit = scaleOut(),
)
var isItemClicked by remember { mutableStateOf(false) }
val accordionItemProp = AccordionItemProp(
visible = isHeaderClicked,
modifier = Modifier
.padding(
start = 32.dp,
)
.then(baseModifier),
accordionVisibilityAnimation = accordionVisibilityAnimation,
onClick = {
isItemClicked = !isItemClicked
},
leadingIcon = {
Icon(
imageVector = Icons.Filled.ArrowDropDown,
contentDescription = null,
tint = MaterialTheme.colorScheme.onSurface,
)
},
trailingIcon = {
val iconContainerSize = 48.dp
Box(
modifier = modifier
.size(
size = iconContainerSize
),
contentAlignment = Alignment.Center
) {
Icon(
imageVector = Icons.Filled.Delete,
contentDescription = null,
tint = MaterialTheme.colorScheme.onSurface,
)
}
},
) {
TextField(
value = "",
onValueChange = {},
placeholder = {
Text(
text = "アイテム click=${isItemClicked}",
modifier = Modifier
.fillMaxWidth(),
)
},
)
}
val accordionItemProps = listOf(
accordionItemProp,
accordionItemProp,
)
Accordion(
modifier = Modifier
.padding(8.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
accordionHeaderProp = accordionHeaderProp,
accordionItemProps = accordionItemProps,
)
}
}
質問や疑問点・改善点などありましたら、お気軽にご連絡ください🙇♂️