사용자가 설정한 장소에 도착하면 알아서 체크해주는 투두리스트 두두
스토어 출시하면 많은 관심 부탁드립니다! 🐥
과거 Compose를 사용할 때면, 구글맵, 네이버 맵 등 지도 API가 Compose를 지원하지 않아 AndroidView를 통해 개발하거나, 개발시 제약사항이 매우 많았다. 하지만 최근에는 대부분의 지도 API가 Compose를 공식적으로 지원하면서 개발이 조금 더 수월해졌다. 두두에서는 BottomSheet에 네이버 지도를 사용하게 되었는데, 어떤 문제가 있었고, 어떻게 해결했는지 알아보자.
Naver Map Compose와 ModalBottomSheetLayout(Compose Material Design에 포함 된 항목)을 사용하여 개발했다.
implementation "io.github.fornewid:naver-map-compose:<version>"
Compose
버전마다 맞는 Naver Map Compose
버전이 있으니 참고하자.
네이버 클라우드 플랫폼에서 클라이언트 키를 발급받아야 한다. (설명대로 따라하면 금방 발급받음)
발급받은 클라이언트 키를 앱에 지정해줘야 한다. 그러나 앱에 그냥 클라이언트 키를 넣어서 사용하면 큰일난다. 반드시 숨겨야 우리 모두가 행복해진다. 😙 아래의 방법을 통해서 클라이언트 키를 숨겨보자.
local.properties는 직접 프로젝트를 열어서 보지 않는 이상 확인할 수 없다. (Github에는 .gitignore에 이미 포함되어 있음)
sdk.dir=SDK 경로
naver_api_key=발급받은 클라이언트 ID
local.properties에 클라이언트 키를 넣었다면, build.gradle에서 설정이 필요하다.
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
def naver_client_id = properties.getProperty('naver_client_id')
defaultConfig {
...
//Manifest에서 사용할 수 있도록 함
manifestPlaceholders = [NAVER_CLIENT_ID: naver_client_id]
}
Build.gradle 설정까지 마쳤다면, 마지막으로 Manifest에 지정하면 끝이다.
<application>
...
<meta-data
android:name="com.naver.maps.map.CLIENT_ID"
android:value="${NAVER_CLIENT_ID}"/>
</application>
이번에도 Compose BottmSheet
에 대한 자료가 진짜 없다. (항상 없네? 그래도 공식적으로 바텀싯을 제공해줬으니 감사하다..)
sheetContent
: BottomSheet에 보여지는 UI (바텀싯을 구성하는 콘텐츠)
sheetState
: ModalBottomSheetLayout의 상태
sheetGesture
: BottomSheet가 제스처로 상호작용이 가능한지의 여부
개인적으로 중요한 내용은 이 세 가지라고 생각한다. (나머지는 UI관련이기 때문에)
ModalBottomSheetLayout
과 Naver Map
을 이용하여 개발해보자.
@Composable
fun MapBottomSheet(
modifier: Modifier = Modifier
) {
val coroutineScope = rememberCoroutineScope()
val sheetState = rememberModalBottomSheetState(
initialValue = ModalBottomSheetValue.Hidden,
skipHalfExpanded = true
)
// BottomSheet가 보이는 상태에서 BackPressed시 BottomSheet를 닫음
BackHandler(sheetState.isVisible) {
coroutineScope.launch { sheetState.hide() }
}
ModalBottomSheetLayout(
sheetContent = { HomeTodoLocationBottomSheet(modifier = Modifier.padding(20.dp)) },
sheetState = sheetState,
sheetBackgroundColor = gray09,
sheetShape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp),
) {
Box(modifier = modifier) {
NaverMap(modifier = Modifier.fillMaxSize())
...
}
}
}
initialValue
를 Hidden으로 설정해 처음에 BottomSheet가 표시되지 않음 skipHalfExpanded
를 true로 설정하여 HalfExpanded
상태를 무시함BottomSheet가 터치 이벤트를 다 가져가서 지도를 움직일 수 없다.... 🫠🫠🫠
NaverMap
터치 이벤트가 BottomSheet
의 터치 이벤트에 막혀 지도 이동이 불가능하다는 사실을 잊어버리고 있었다. 그래서 어떻게 해결할까 고민하다가, cameraPositionState.isMoving == true
일 때 BottomSheet
를 비활성화 시켜 터치 이벤트를 온전히 지도가 가져가는 방법을 시도하려 했으나, 해당 BottomSheet
에는 enabled
관련 설정을 할 수가 없어서 구현하지 못했다.
엄청난 삽질을 하다가 Modifier
속성 중 pointerInput
을 찾게 되었다. Compose
에서 제스처를 감지하기 위해 사용한다. PointerInputScope.detectDragGestures
를 통해 사용자의 드래그 입력을 감지하고 처리할 수 있게 도와준다.
NaverMap(
modifier = Modifier
.fillMaxSize()
.pointerInput(Unit) {
detectDragGestures { _, dragAmount ->
cameraPositionState.move(CameraUpdate.scrollBy(
PointF(dragAmount.x, dragAmount.y)
))
}
},
cameraPositionState = cameraPositionState
) {
...
}
cameraPositionState.move()
에 사용자가 드래그중인 x, y값을 가져와 설정해준다.
Compose로 두두를 개발 하면 할 수록 머리카락이 다 빠질 것만 같다. 지도를 굳이 바텀시트에 올려서 사용할 사람은 많지 않을 것이라 생각하지만, 그래도 쓰는 사람이 있다면 이 글을 통해 나와 같은 이슈를 삽질하지 않고 편하게 해결하길 바란다. 다음에는 어떤 기능이 말썽을 부릴지 모르지만 도움이 될 수 있는 내용을 들고 찾아오겠다.
다음 삽질도 정말 기대된다. 스토어 랭킹에 두두가 보이는 그날까지 💪
이거 집어넣으면 아래 에러 발생하는데 어떻게 해결하나요?
A build operation failed.
Could not create task ':app:createDebugVariantModel'.
Could not create task ':app:createDebugVariantModel'.