Compose를 위한 BottomSheetDialog 라이브러리 개발기

이번 글에서는 많은 사람들이 문제를 겼었던 “Compose에서 BottomSheetDialog 구현”에 대해 이야기 해보고자 한다.

Compose를 위한 BottomSheetDialog 라이브러리 개발기
서비스에 적용된 모습

“좋아요 누른 사람 목록은 바텀 시트로 나오게 해주세요”

Compose를 사용하여 제품 개발을 잘 이어나가던 도중 BottomSheetDialog 가 필요한 순간이 찾아왔다. Android View 기반에서는BottomSheetDialogFragment 를 이용하여 동작을 구현했는데 Compose에선 어떤 것들로 대체할 수 있을 지 알아봤다.

Bottom Sheet는 material design에서 정의한 컴포넌트 중 하나로, Bottom Sheet와 관련된 composable을 아래와 같이 찾을 수 있었다.

  • BottomSheetScaffold
  • ModalBottomSheetLayout

그러나 이름에서 알 수 있듯이, 위 Composable들을 이용해 요구사항을 달성할 수 없었다. 저것들은 BottomSheet가 아니라 BottomSheet를 포함한 컴포넌트이기 때문이다. 1개의 BottomSheet만 필요하다면 활용은 할 수 있겠지만, 내 요구사항을 충족할 수 없었다. 이 링크와 같이 어떻게든 사용할 수 있는 형태로 만들어 볼 수는 있었겠지만, 내가 바라는 방향은 아니었다.

내가 원하는 것은 BottomSheet”Dialog”

기술적 어려움으로 인해 iOS, 안드로이드의 디자인을 따로 찍어주신 디자인팀께 감사를…😊

일단 내부 논의 결과 BottomSheet 자체는 우선 순위가 높지 않아 일단 대체 디자인을 사용하고 기술적 요구사항을 정리했다.

  • 한 화면에는 여러 개의 BottomSheetDialog가 올 수 있다.
  • Dialog Composable 처럼 쓰기 쉬워야 한다.

정리를 하고보니 Dialog Composable의 구현으로부터 힌트를 얻을 수 있을 것 같다는 생각이 들었다.

Dialog 대신 BottomSheetDialog

DialogComposable의 코드를 보다 보니 Android View의 Dialog를 상속받은DialogWrapper 가 눈에 띄었다.

private class DialogWrapper(
    private var onDismissRequest: () -> Unit,
    private var properties: DialogProperties,
    private val composeView: View,
    layoutDirection: LayoutDirection,
    density: Density,
    dialogId: UUID
) : Dialog(...) {
  ...
}

DialogWrapper

코드를 읽어보니 Dialog Composable의 구현을 참고하되, Android View Dialog 를 사용하는 부분을 material-components-androidBottomSheetDialog 로 대체하면 되지 않을까 하는 아이디어가 생각났다.

  1. Dialog Composable 코드를 이해한다.
  2. Android View Dialogmaterial-components-androidBottomSheetDialog 로 대체한다.
  3. BottomSheetDialog 와 무관한 코드를 제거한다. ex) usePlatformWidth
  4. BottomSheetDialog 와 관련해 필요한 코드를 추가한다. ex) BottomSheetCallback 추가, cancel 로직 변경

위와 같은 과정을 통해 어느 정도 원하는 방식대로 동작하는 BottomSheetDialog 를 구현할 수 있었다. 🎉

첫 오픈 소스 라이브러리를 배포하다.

내부 디자인 컴포넌트 모듈인 holix-ui-design-componentsHolixBottomSheetDialog Composable을 추가하고 보니, 오픈 소스 라이브러리로 배포해도 좋을 것 같다는 생각이 들었다.

무엇보다 BottomSheetDialog compose 라고 구글에 검색했을 때, 깔끔하게 제시된 해결책이 딱히 없다는 점에서 그 해결책을 제시한 사람이 되고자 했다.

오픈 소스 배포는 어떻게 해야할 지 몰랐지만, 오픈 소스를 사랑하는 getstream.io블로그 글로부터 도움을 받아 첫 배포에 성공할 수 있었다😎

GitHub - workspace/bottomsheetdialog-compose: The most convenient way to use BottomSheetDialog in Jetpack Compose
The most convenient way to use BottomSheetDialog in Jetpack Compose - workspace/bottomsheetdialog-compose
첫 릴리즈!

Dialog Composable과 같은 interface를 가지도록 구현했기 때문에 적응에 어려움 없이 사용할 수 있다.

@Composable
fun SomeComposable() {
  ...
  /*
  Dialog(
    onDismissRequest = { ... },
    properties = DialogProperties(...)
  )
  */
  BottomSheetDialog(
    onDismissRequest = { ... },
    properties = BottomSheetDialogProperties(...)
  )
  ...
}

현재 최신 버전은 1.0.3으로, 몇몇 분들이 이슈를 남겨주시기도 하여

  1. Navigation Bar 색상, 아이콘
  2. BottomSheetBehavior 설정
  3. NestedScroll

와 같은 다양한 개선이 이뤄졌다. Sample app에서 코드 수정없이 property의 값에 따른 동작을 확인할 수 있도록 구현해뒀다. github Release에서 apk를 다운받거나 직접 빌드 하여 확인할 수 있다.👍

Sample app

또한, 구글에서 bottomsheetdialog compose 로 검색을 하면 상위 검색 결과로 노출이 되고 있는 것으로 보아 많은 사람들에게 도달하고 있다는 것을 확인할 수 있었다 👍

star도 눌러주세요…!

마치며

나는 비교적 일찍 Compose를 적용하여 숱한 문제와 씨름해왔다. Compose를 활용하시고자 하는 사람들에게 문제와 해결방법 뿐만 아니라 오픈 소스 라이브러리를 통해 실질적인 도움을 줄 수 있게 되어 기쁘고 뿌듯한 마음이다! 혹시 코드나 동작에 개선할 부분이 보인다면 언제든지 이슈 부탁드린다.

Happy Compose!

Jetpack Compose 사용자 모임 | 홀릭스(HOLIX)
이미 Production에서 사용중인 개발자와 새로 공부하는 뉴비까지, 안드로이드의 새로운 UI 프레임워크에 대한 최신 정보를 얻으세요!

Jetpack Compose 커뮤니티