Android / Kotlin / Programming

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,
            )
        }
    }

質問や疑問点・改善点などありましたら、お気軽にご連絡ください🙇‍♂️

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です