如何让 menuFAB Composable 在 FAB 之上?

问题描述 投票:0回答:0

我正在开发使用 Jetpack Composable 放置多菜单 Composable。
当我点击 Floating Action Button 时,我尝试将 menuFAB 放在 Floating Action Button 上方,但是对齐错位为中心,而不是终点。
单击浮动操作按钮以更改 menuFAB 的外观。当处于 Expanded 状态时,menuFAB 会尝试浮动在 Floating Action Button 上,而当处于 Collapsed 状态时,menuFAB 会尝试消失。 我该如何解决?

代码:

@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@ExperimentalMaterialApi
@ExperimentalMaterial3Api
@Composable
fun CalendarScreen(routeAction: RouteAction) {

    val states = listOf("월간", "주간")
    var selectedOption by remember { mutableStateOf(states[0]) }

    val onSelectionChange = { text: String -> selectedOption = text }

    var isVisible by remember { mutableStateOf(false) }

    var multiFloatingState by remember {
        mutableStateOf(FloatingStateType.Collapsed)
    }

    val colorFAB = if (multiFloatingState == FloatingStateType.Expanded) {
        Color(0xff9E9E9E)
    } else {
        Color(0xffFFDAB9)
    }

  

    var items = listOf(
        menuFABitem(
            icon = ImageBitmap.imageResource(id = R.drawable.lottie),
            label = "test1",
            identifier = "test1"
        ),
        menuFABitem(
            icon = ImageBitmap.imageResource(id = R.drawable.appname),
            label = "test2",
            identifier = "test2"
        ),
        menuFABitem(
            icon = ImageBitmap.imageResource(id = R.drawable.apptitle),
            label = "test3",
            identifier = "test3"
        ),
    )
    var todoList = remember {
        mutableStateListOf<RToDoResponse>()
    }

    Scaffold(topBar = {
        TopAppBar(title = {
            Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
                Row(
                    modifier = Modifier
                        .width(115.dp)
                        .height(35.dp)
                        .clip(shape = RoundedCornerShape(24.dp))
                        .background(Color(0xffe9e9ed))
                        .padding(start = 10.dp, end = 5.dp, top = 6.dp, bottom = 5.dp)
                ) {
                    states.forEach { text ->
                        Text(text = text,
                            fontSize = 10.sp,
                            lineHeight = 16.sp,
                            color = if (text == selectedOption) {
                                Color.Black
                            } else {
                                Color.Gray
                            },
                            fontWeight = FontWeight.Medium,
                            modifier = Modifier
                                .clip(shape = RoundedCornerShape(24.dp))
                                .clickable {
                                    onSelectionChange(text)
                                    isVisible = (text == states[1])
//                                            isVisible = !isVisible
                                }
                                .background(
                                    if (text == selectedOption) {
                                        Color.White
                                    } else {
                                        Color(0xffe9e9ed)
                                    }
                                )
                                .padding(
                                    vertical = 5.dp,
                                    horizontal = 16.dp,
                                ))
                    }
                }
            }
        }, actions = {
            IconButton(onClick = {
                goDetailProfile(NAV_ROUTE.PROFILE, routeAction)
            }) {
                Icon(imageVector = Icons.Filled.Menu, contentDescription = "profile")
            }
        }, colors = TopAppBarDefaults.smallTopAppBarColors(
            containerColor = Color.White, titleContentColor = Color.Black
        )
        )
    }) {
        Column(
            modifier = Modifier
                .fillMaxSize()
                .background(Color(0xfff0f0f0))
                .imePadding()
        ) {
            if (isVisible) {
                Kalendar(modifier = Modifier
                    .fillMaxWidth()
                    .padding(top = 45.dp)
                    .clip(
                        shape = RoundedCornerShape(
                            bottomStart = 30.dp, bottomEnd = 30.dp
                        )
                    ),
                    kalendarHeaderConfig = KalendarHeaderConfig(
                        kalendarTextConfig = KalendarTextConfig(
                            kalendarTextColor = KalendarTextColor(Color.Black),
                            kalendarTextSize = KalendarTextSize.SubTitle
                        )
                    ),
                    kalendarType = KalendarType.Oceanic(),
                    kalendarDayColors = KalendarDayColors(Color.Black, Color.Black),
                    kalendarThemeColor = KalendarThemeColor(
                        backgroundColor = Color.White,
                        dayBackgroundColor = Color(0xffFBE3C7),
                        headerTextColor = Color.Black
                    ),
                    onCurrentDayClick = { kalendarDay: KalendarDay, kalendarEvents: List<KalendarEvent> ->

                        year = kalendarDay.localDate.year
                        month = kalendarDay.localDate.monthNumber
                        day = kalendarDay.localDate.dayOfMonth

                        readTodo(token, year, month, day, response = {

                            todoList.clear()
                            for (i in it!!.data) {
                                todoList.add(i)
                            }
                        })
                    })
            } else {
                Kalendar(modifier = Modifier
                    .fillMaxWidth()
                    .padding(top = 25.dp)
                    .clip(
                        shape = RoundedCornerShape(
                            bottomStart = 30.dp, bottomEnd = 30.dp
                        )
                    ),
                    kalendarHeaderConfig = KalendarHeaderConfig(
                        kalendarTextConfig = KalendarTextConfig(
                            kalendarTextColor = KalendarTextColor(Color.Black),
                            kalendarTextSize = KalendarTextSize.SubTitle
                        )
                    ),
                    kalendarType = KalendarType.Firey,
                    kalendarDayColors = KalendarDayColors(Color.Black, Color.Black),
                    kalendarThemeColor = KalendarThemeColor(
                        backgroundColor = Color.White,
                        dayBackgroundColor = Color(0xffFBE3C7),
                        headerTextColor = Color.Black
                    ),
                    onCurrentDayClick = { kalendarDay: KalendarDay, kalendarEvents: List<KalendarEvent> ->

                        year = kalendarDay.localDate.year
                        month = kalendarDay.localDate.monthNumber
                        day = kalendarDay.localDate.dayOfMonth

                        readTodo(token, year, month, day, response = {

                            todoList.clear()
                            for (i in it!!.data) {
                                todoList.add(i)
                            }
                        })
                    })
            }

            Row(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(start = 21.dp, end = 21.dp, top = 30.dp),
                horizontalArrangement = Arrangement.Center,
                verticalAlignment = Alignment.CenterVertically
            ) {
                Text(
                    text = day.toString(),
                    fontSize = 26.sp,
                    fontWeight = FontWeight.Bold,
                    modifier = Modifier.padding(end = 5.dp)
                )

                Divider(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(start = 5.dp),
                    color = Color(0xffD8D8D8)
                )
            }

            Box(
                modifier = Modifier
                    .fillMaxSize()
                    .padding(top = 15.dp),
                contentAlignment = Alignment.TopCenter
            ) {
                TodoItemList(Todo = todoList)

                AddTodoFloatingButton(
                    multiFloatingState = multiFloatingState,
                    onMultiFloatingStateChange = {
                        multiFloatingState = it
                    },
                    position = Modifier
                        .align(alignment = Alignment.BottomEnd)
                        .padding(all = 16.dp),
                    backgroundColor = colorFAB,
                    items = items
                )
            }
        }
    }
}

@Composable
fun AddTodoFloatingButton(
    multiFloatingState: FloatingStateType,
    onMultiFloatingStateChange: (FloatingStateType) -> Unit,
    position: Modifier,
    backgroundColor: Color,
    items: List<menuFABitem>,
) {
    val transition = updateTransition(targetState = multiFloatingState, label = null)
    val rotate by transition.animateFloat(label = "rotate") {
        if (it == FloatingStateType.Expanded) {
            315f
        } else {
            0f
        }
    }

    Column(
        horizontalAlignment = Alignment.End
    ) {
        if (transition.currentState == FloatingStateType.Expanded) {
            items.forEach {
                menuFAB(
                    item = it,
                    onMenuFABitemClick = {}
                )

                Spacer(modifier = Modifier.size(16.dp))
            }
        }
    }

    FloatingActionButton(
        modifier = position,
        containerColor = backgroundColor,
        shape = CircleShape,
        onClick = {

            onMultiFloatingStateChange(
                if (transition.currentState == FloatingStateType.Expanded) {
                    FloatingStateType.Collapsed
                } else {
                    FloatingStateType.Expanded
                }
            )
        }) {
        Icon(
            imageVector = Icons.Filled.Add,
            contentDescription = "todolist 추가",
            modifier = Modifier.rotate(rotate),
        )
    }
}

@Composable
fun menuFAB(
    item: menuFABitem,
    onMenuFABitemClick: (menuFABitem) -> Unit,
) {
    Canvas(
        modifier = Modifier
            .size(32.dp)
            .clickable(
                interactionSource = MutableInteractionSource(),
                onClick = {
                    onMenuFABitemClick.invoke(item)
                },
                indication = rememberRipple(
                    bounded = false,
                    radius = 15.dp,
                    color = Color.LightGray
                )
            )
    ) {
        drawImage(
            image = item.icon,
            topLeft = Offset(
                center.x - (item.icon.width / 2),
                center.y - (item.icon.width / 2),
            )
        )
    }
}

enum class FloatingStateType {
    Expanded,
    Collapsed
}

class menuFABitem(
   val icon: ImageBitmap,
   val label: String,
   val identifier: String,
)

例子:

像这样:

android android-jetpack-compose floating-action-button
© www.soinside.com 2019 - 2024. All rights reserved.