카테고리 없음
Android 배워보자 Compose! -(6) Spinner 를 Compose 에서
wannagohome97
2024. 3. 18. 16:18
Spinner -> DropdownMenu!
Spinner 라는 레이아웃 요소는 기존 XML 에서 드롭다운 형태의 메뉴를 구현할 때 많이 사용되었는데
Compose 로 넘어오면서 "DropdownMenu" 라는 개념으로 바뀌어 들어왔습니다.
이전 ProgressBar 같은 요소들과는 또 다르게 구현 방식 자체가 좀 많이 바뀌었다고 느껴졌던 요소였습니다.
DropdwonMenu?
@Composable
fun DropdownMenu(
expanded: Boolean,
onDismissRequest: () -> Unit,
modifier: Modifier = Modifier,
offset: DpOffset = DpOffset(0.dp, 0.dp),
scrollState: ScrollState = rememberScrollState(),
properties: PopupProperties = PopupProperties(focusable = true),
content: @Composable ColumnScope.() -> Unit
) {
val expandedState = remember { MutableTransitionState(false) }
expandedState.targetState = expanded
if (expandedState.currentState || expandedState.targetState) {
val transformOriginState = remember { mutableStateOf(TransformOrigin.Center) }
val density = LocalDensity.current
val popupPositionProvider = remember(offset, density) {
DropdownMenuPositionProvider(
offset,
density
) { parentBounds, menuBounds ->
transformOriginState.value = calculateTransformOrigin(parentBounds, menuBounds)
}
}
Popup(
onDismissRequest = onDismissRequest,
popupPositionProvider = popupPositionProvider,
properties = properties
) {
DropdownMenuContent(
expandedState = expandedState,
transformOriginState = transformOriginState,
scrollState = scrollState,
modifier = modifier,
content = content
)
}
}
}
라이브러리 상 DropdownMenu 의 구현입니다.
Dialog 와 같이 Boolean State 를 통해 화면에 Composed 여부가 결정되고
디바이스의 Back 에 반응해서 Dismiss 됩니다.
그리고 ColumnScope 인 후행 람다 내부에 Item 들을 넣어주는 형태인데
기존에 ArrayList 를 인자로 받고 ViewType 을 별도로 구현하던 Spinner 와 비교하면 비슷한 듯 다릅니다.
내부 아이템 = DropdownMenuItem
@Composable
fun DropdownMenuItem(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
contentPadding: PaddingValues = MenuDefaults.DropdownMenuItemContentPadding,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable RowScope.() -> Unit
) {
DropdownMenuItemContent(
onClick = onClick,
modifier = modifier,
enabled = enabled,
contentPadding = contentPadding,
interactionSource = interactionSource,
content = content
)
}
이걸 DropdownMenu 의 후행 람다로 오는 ColumnScope 에 배열해주는게 일반적입니다.
쉽게 설명하자면 Button 과 유사합니다.(후행 람다로 Rowscope 를 가지고 , onClick 을 Parameter 로 받습니다.)
var isExpanded by remember {
mutableStateOf(false)
}
Button(
modifier = Modifier.width(180.dp),
onClick = { isExpanded = true }) {
Text(text = "Click to show Menu")
}
DropdownMenu(
modifier = Modifier.width(180.dp),
expanded = isExpanded,
onDismissRequest = { isExpanded = false }) {
DropdownMenuItem(onClick = {
Toast.makeText(context, "Clicked Item = 1", Toast.LENGTH_SHORT).show()
}) {
Text(text = "Menu Item 1")
}
DropdownMenuItem(onClick = {
Toast.makeText(context, "Clicked Item = 2", Toast.LENGTH_SHORT).show()
}) {
Text(text = "Menu Item 2")
}
}
대략 이런 식으로 구현해주면
이 버튼을 눌렀을때
이렇게 나옵니다(다른 글들 보면 움짤로 보여드렸었는데 이상하게 PC 렉이 심해서 추후 수정 예정..)