我正在开发使用 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,
)