컴포저블의 포지션은 어떻게 구할 수 있나
Android View로 애플리케이션 UI를 구현할 때는 root 에서 하위에 있는 view의 포지션을 구할 수 있었다. 하지만 컴포즈로 UI를 구현시에는 View는 ComposeView 하나만 존재하고, 캔버스에 필요한 Element들을 그리는 방식이다.
위의 이미지와 같이 특정 버튼(컴포저블) 위치에 맞춰 어떠한 팝업을 띄운다고 가정할 때 어떻게 포지션을 구할 수 있을까?
사실 컴포즈에서도 ConstraintLayout으로만 UI를 구성한다면, 특별한 솔루션이 필요 없을지도 모른다. 그렇지 않은 경우에는 컴포저블의 포지션을 알아야 한다.
OnGloballyPositionedModifier 사용하기
interface OnGloballyPositionedModifier : Modifier, Modifier.Element
OnGloballyPositionedModifier는 Modifier의 일종으로, 콘텐츠의 전역 포지션이 변경되었을 때 레이아웃의 최종 LayoutCoordinates와 함께 onGloballyPositioned 콜백을 호출한다. 좌표를 포함하고 있는 이 콜백은 Composition(구성)이 끝났을 때 호출 됨을 명심하자.
좌표 구하기 예제
Column(
Modifier.onGloballyPositioned { coordinates ->
// Column의 사이즈
coordinates.size
// 애플리케이션 윈도우에 상대적인 Column의 포지션
coordinates.positionInWindow()
// 컴포즈 최상위에 상대적인 Column의 포지션
coordinates.positionInRoot()
// 레이아웃에 제공되는 정렬 라인 (Column의 경우 비어있음)
coordinates.providedAlignmentLines
// Column의 부모에 해당하는 LayoutCoordinates 인스턴스
coordinates.parentLayoutCoordinates
}
) {
...
}
버튼 위치에 맞게 팝업 띄우기
좌표를 구하고자 하는 컴포저블에 OnGloballyPositionedModifier를 추가하여 상대적인 포지션을 먼저 구할 수 있다.
@Composable
fun InformationButton(
...,
onGloballyPositioned:(LayoutCoordinates) -> Unit,
) {
Column(
modifier = modifier.onGloballyPositioned(onGloballyPositioned)
) {
...
}
}
state hoisting 기법으로 전역 포지션 정보(LayoutCoordinates) 이벤트를 상위로 전달한다.
@Composable
private fun RequestPaymentScreen(
...
) {
...
var infomationBtnOffset by remember { mutableStateOf(Offset.Zero) }
Scaffold(
topBar = {...},
content = {
...
InformationButton(
// boundsInRoot는 해당 컴포저블을 감싸는 정보를 반환한다.
// Rect의 bottomCenter를 중앙 하단부 포지션(Offset)을 반환한다.
// 이 정보를 informationBtnOffset에 저장하자.
onGloballyPositioned = { layoutCoordinates->
layoutCoordinates.boundsInRoot().bottomCenter
}
)
},
bottomBar = {...}
)
}
전달 받은 전역 포지션의 상태를 저장하고 State로 저장(remember)한다.
@Composable
private fun RequestPaymentScreen(
...
) {
...
var infomationBtnOffset by remember { mutableStateOf(Offset.Zero) }
Scaffold(...)
// 화면위에 나타내고 싶은 팝업을 보여주고, offset 정보를 기반으로
PopupGuide(
isShowing = ...,
offset = infomationBtnOffset,
onCloseClick = ...
)
}
@Composable
fun PopupGuide(
isShowing: Boolean,
offset: Offset,
onCloseClick: () -> Unit
) {
val paddingStart = ... // offset 기반으로 시작 패딩값을 결정
val paddingTop = ... // offset 기반으로 상단 패딩값을 결정
if (isShowing) {
Surface{
Column(
modifier = Modifier
.padding(
start = paddingStart,
top = paddingTop
)
) { ... }
}
}
}
컴포저블의 위치정보를 기반으로 팝업의 위치를 적절하게 배치할 수 있다.
0개의 댓글