탐색 창

탐색 창 구성요소는 사용자가 앱의 다양한 섹션으로 이동할 수 있는 슬라이드 인 메뉴입니다. 사용자는 측면에서 스와이프하거나 메뉴 아이콘을 탭하여 활성화할 수 있습니다.

탐색 창을 구현하기 위한 다음 세 가지 사용 사례를 고려해 보세요.

  • 콘텐츠 구성: 사용자가 뉴스 또는 블로그 앱과 같이 여러 카테고리 간에 전환할 수 있도록 합니다.
  • 계정 관리: 사용자 계정이 있는 앱에서 계정 설정 및 프로필 섹션으로 연결되는 빠른 링크를 제공합니다.
  • 기능 검색: 단일 메뉴에 여러 기능과 설정을 정리하여 복잡한 앱에서 사용자 검색 및 액세스를 용이하게 합니다.

Material Design에는 두 가지 유형의 탐색 창이 있습니다.

  • 표준: 화면 내 공간을 다른 콘텐츠와 공유합니다.
  • 모달: 화면 내 다른 콘텐츠 위에 표시됩니다.
그림 1. 탐색 창의 예

ModalNavigationDrawer 컴포저블을 사용하여 탐색 창을 구현할 수 있습니다.

다음 예와 같이 drawerContent 슬롯을 사용하여 ModalDrawerSheet를 제공하고 창의 콘텐츠를 제공합니다.

ModalNavigationDrawer(
    drawerContent = {
        ModalDrawerSheet {
            Text("Drawer title", modifier = Modifier.padding(16.dp))
            HorizontalDivider()
            NavigationDrawerItem(
                label = { Text(text = "Drawer Item") },
                selected = false,
                onClick = { /*TODO*/ }
            )
            // ...other drawer items
        }
    }
) {
    // Screen content
}

ModalNavigationDrawer는 다양한 추가 창 매개변수를 허용합니다. 예를 들어 다음 예와 같이 gesturesEnabled 매개변수를 사용하여 창이 드래그에 응답하는지 여부를 전환할 수 있습니다.

ModalNavigationDrawer(
    drawerContent = {
        ModalDrawerSheet {
            // Drawer contents
        }
    },
    gesturesEnabled = false
) {
    // Screen content
}

동작 제어

서랍이 열리고 닫히는 방식을 제어하려면 DrawerState를 사용하세요. drawerState 매개변수를 사용하여 DrawerStateModalNavigationDrawer에 전달해야 합니다.

DrawerState를 통해 현재 드로어 상태와 관련된 속성뿐만 아니라 openclose 함수에도 액세스할 수 있습니다. 이러한 정지 함수에는 CoroutineScope가 필요하며 rememberCoroutineScope를 사용하여 인스턴스화할 수 있습니다. UI 이벤트에 대한 응답으로 일시중지 함수를 호출할 수도 있습니다.

val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
val scope = rememberCoroutineScope()
ModalNavigationDrawer(
    drawerState = drawerState,
    drawerContent = {
        ModalDrawerSheet { /* Drawer content */ }
    },
) {
    Scaffold(
        floatingActionButton = {
            ExtendedFloatingActionButton(
                text = { Text("Show drawer") },
                icon = { Icon(Icons.Filled.Add, contentDescription = "") },
                onClick = {
                    scope.launch {
                        drawerState.apply {
                            if (isClosed) open() else close()
                        }
                    }
                }
            )
        }
    ) { contentPadding ->
        // Screen content
    }
}

탐색 창 내에 그룹 만들기

다음 스니펫은 섹션과 구분자로 세부적인 탐색 창을 만드는 방법을 보여줍니다.

@Composable
fun DetailedDrawerExample(
    content: @Composable (PaddingValues) -> Unit
) {
    val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
    val scope = rememberCoroutineScope()

    ModalNavigationDrawer(
        drawerContent = {
            ModalDrawerSheet {
                Column(
                    modifier = Modifier.padding(horizontal = 16.dp)
                        .verticalScroll(rememberScrollState())
                ) {
                    Spacer(Modifier.height(12.dp))
                    Text("Drawer Title", modifier = Modifier.padding(16.dp), style = MaterialTheme.typography.titleLarge)
                    HorizontalDivider()

                    Text("Section 1", modifier = Modifier.padding(16.dp), style = MaterialTheme.typography.titleMedium)
                    NavigationDrawerItem(
                        label = { Text("Item 1") },
                        selected = false,
                        onClick = { /* Handle click */ }
                    )
                    NavigationDrawerItem(
                        label = { Text("Item 2") },
                        selected = false,
                        onClick = { /* Handle click */ }
                    )

                    HorizontalDivider(modifier = Modifier.padding(vertical = 8.dp))

                    Text("Section 2", modifier = Modifier.padding(16.dp), style = MaterialTheme.typography.titleMedium)
                    NavigationDrawerItem(
                        label = { Text("Settings") },
                        selected = false,
                        icon = { Icon(Icons.Outlined.Settings, contentDescription = null) },
                        badge = { Text("20") }, // Placeholder
                        onClick = { /* Handle click */ }
                    )
                    NavigationDrawerItem(
                        label = { Text("Help and feedback") },
                        selected = false,
                        icon = { Icon(Icons.AutoMirrored.Outlined.Help, contentDescription = null) },
                        onClick = { /* Handle click */ },
                    )
                    Spacer(Modifier.height(12.dp))
                }
            }
        },
        drawerState = drawerState
    ) {
        Scaffold(
            topBar = {
                TopAppBar(
                    title = { Text("Navigation Drawer Example") },
                    navigationIcon = {
                        IconButton(onClick = {
                            scope.launch {
                                if (drawerState.isClosed) {
                                    drawerState.open()
                                } else {
                                    drawerState.close()
                                }
                            }
                        }) {
                            Icon(Icons.Default.Menu, contentDescription = "Menu")
                        }
                    }
                )
            }
        ) { innerPadding ->
            content(innerPadding)
        }
    }
}

코드 관련 핵심 사항

  • 섹션, 구분자, 탐색 항목이 포함된 ColumndrawerContent를 채웁니다.
  • ModalDrawerSheet는 창에 Material Design 스타일을 제공합니다.
  • HorizontalDivider: 섹션을 구분합니다.
  • ModalNavigationDrawer는 창을 만듭니다.
  • drawerContent은 드로어의 콘텐츠를 정의합니다.
  • ModalDrawerSheet 내에서 Column는 드로어 요소를 세로로 정렬합니다.
  • NavigationDrawerItem 컴포저블은 드로어의 개별 항목을 나타냅니다.
  • ScaffoldTopAppBar를 비롯한 화면의 기본 구조를 제공합니다.
  • TopAppBarnavigationIcon는 드로어의 열림 닫힘 상태를 제어합니다.

결과

다음 이미지는 섹션과 항목이 표시된 상태로 열려 있는 드로어의 모습을 보여줍니다.

라벨이 지정된 여러 항목과 아이콘이 각각 있는 두 섹션으로 구성된 세부적인 탐색 창
그림 2. 중첩된 두 그룹이 있는 탐색 창이 열려 있습니다.

추가 리소스