본문 바로가기

[Jetpack Compose] Navigation Drawer 구현하기

꿈꾸는블로그왕 2022. 8. 10.

안녕하세요. 

 

오늘은 TopAppBar에서 만든 네비게이션 아이콘에 Navigation Drawer를 연결 해보도록 하겠습니다.

 

2022.08.08 - [Android/Jetpack] - [Jetpack Compose] TopAppBar(Toolbar) 구현하기

 

[Jetpack Compose] TopAppBar(Toolbar) 구현하기

안녕하세요. 오늘은 Jetpack Compose내 TopAppBar 컴포넌트를 구현해 보도록 하겠습니다. TopAppBar는 이전에 안드로이드 어플리케이션에서 Toolbar/AppBar라고 불리는 컴포넌트입니다. TopAppBar 컴포넌트는 아

android-dev.tistory.com

2022.08.08 - [Android/Jetpack] - [Jetpack Compose] TopAppBar(Toolbar) - 메뉴 클릭 이벤트 (Toast, Alertdialog, Dropdownmenu)

 

[Jetpack Compose] TopAppBar(Toolbar) - 메뉴 클릭 이벤트 (Toast, Alertdialog, Dropdownmenu)

안녕하세요. 이번 시간에는 지난시간에 구현한 TopAppBar 컴포넌트의 메뉴에서 다양한 클릭 이벤트를 구현해보도록하겠습니다. Navigation Icon클릭시에는 간단한 Toast 메시지를(나중에 Drawer Layout 구

android-dev.tistory.com

 

완성된 모습은 아래와 같습니다.

 

 

 

STEP 01 : Drawer 화면 만들기

화면은 아래와 같이 구성해보도록 하겠습니다.

Drawer Header : 프로필 사진, 닉네임

Drawer Body : 화면 이동을 나타내는 네이게이션 아이템

 

 

먼저 NavigationDrawer.kt라는 파일을 하나 만듭니다.

해당 파일에 NavigationDrawer 관련 화면을 만들어서 저장할 예정입니다.

전반적인 파일구조는 아래와 같습니다.

 

@Composable
fun NavigationDrawer(
    currentScreen: Screen,
    itemClick: (String) -> Unit
) {
    val menuList = createDrawerItem(currentScreen)

    LazyColumn(
        modifier = Modifier
            .fillMaxSize()
            .background(brush = Brush.verticalGradient(colors = listOf(Color(255, 81, 47),
                Color(240, 152, 25)))),
        horizontalAlignment = Alignment.CenterHorizontally,
        contentPadding = PaddingValues(vertical = 16.dp)
    ) {
        item {
            DrawerHeader()
        }

        items(menuList) { item ->
            DrawerBody(item, itemClick)
        }
    }
}

NavigationDrawer 전체 화면은 LazyColumn을 통해 Vertical 형태로 만들었고, 

컬럼이기 때문에 메뉴가 많을때 위아래 스크롤이 가능합니다.

변수로는 NavigationDrawer 시작시 현재 화면을 지정하는 currentScreenitemClick 함수를 설정했습니다.

 

먼저, createDrawerItem()을 통해서 Navigation Drawer Item 메뉴를 만듭니다. 

@Composable
private fun createDrawerItem(currentScreen: Screen) = listOf(
    NavigationDrawerItem(
        image = painterResource(id = ic_baseline_home_24),
        isSelected = currentScreen == Screen.Home,
        title = "Home"
    ),
    NavigationDrawerItem(
        image = painterResource(id = ic_baseline_search_24),
        isSelected = currentScreen == Screen.Search,
        title = "Search"
    ),
    NavigationDrawerItem(
        image = painterResource(id = ic_baseline_pin_drop_24),
        isSelected = currentScreen == Screen.Map,
        title = "Map"
    ),
    NavigationDrawerItem(
        image = painterResource(id = ic_baseline_settings_24),
        isSelected = currentScreen == Screen.Settings,
        title = "Settings"
    ),
)

 

NavigationDrawerItem 객체를 만들어 필요한 변수들을 지정합니다.

아이콘 이미지와 이름 그리고 해당 메뉴가 선택되었는지의 변수를 넣었습니다.

data class NavigationDrawerItem(
    val image: Painter,
    val isSelected: Boolean,
    val title: String
)

 

DrawerHeader()는 Image와 Text Compasable를 통해서 레이아웃을 구성합니다.

@Composable
private fun DrawerHeader() {
    Image(
        painter = painterResource(id = ic_baseline_person_24),
        contentDescription = "Person",
        modifier = Modifier
            .padding(top = 16.dp, bottom = 16.dp)
            .size(size = 100.dp)
            .clip(shape = CircleShape),
        colorFilter = ColorFilter.tint(color = Color.White)
    )

    Text(
        text = "안드로이드 개발",
        color = Color.White,
        fontSize = 24.sp,
        fontWeight = FontWeight.Bold,
        modifier = Modifier
            .padding(start = 16.dp, bottom = 16.dp)
    )

    Divider(
        color = Color.White,
        modifier = Modifier
            .padding(start = 16.dp, end = 16.dp, bottom = 12.dp)
    )
}

 

DrawerBody() Composable에서 NavigationMenuItem를 생성합니다.

@Composable
private fun DrawerBody(
    item: NavigationDrawerItem,
    itemClick: (String) -> Unit,
) {
    NavigationMenuItem(item = item) {
        itemClick(item.title)
    }
}

 

@Composable
fun NavigationMenuItem(
    item: NavigationDrawerItem,
    itemClick: () -> Unit
) {
    val texColor = if (item.isSelected) Color.Black else Color.White
    val backgroundColor = if (item.isSelected) Color.Yellow else Color.Transparent

    Surface(
        modifier = Modifier
            .fillMaxWidth()
            .padding(horizontal = 16.dp, vertical = 8.dp),
        color = backgroundColor,
        shape = MaterialTheme.shapes.small
    ) {
        Row(
            modifier = Modifier
                .clickable { itemClick() }
                .fillMaxWidth()
                .padding(8.dp),
            verticalAlignment = Alignment.CenterVertically,
        ) {
            Icon(
                painter = item.image,
                contentDescription = null,
                tint = texColor
            )
            Text(
                text = item.title,
                fontSize = 18.sp,
                fontWeight = FontWeight.Medium,
                color = texColor,
                modifier = Modifier
                    .padding(start = 16.dp)
            )
        }
    }
}

NavigationMenuItem를 통해서 클릭 이벤트가 있는 메뉴들을 그려줍니다. isSelected를 변수를 통해서 현재 화면에 따라서 아이콘과 텍스트 그리고 배경화면의 색깔을 다르게 지정해 줄 수 있습니다. 현재 화면 메뉴는 배경을 노란색으로 그리고 아이콘과 이름을 횐색으로 지정했습니다.

 

STEP 02 : Navigation Icon에서 호출하기

@Composable
fun MyApp() {
    val context = LocalContext.current

    val scaffoldState = rememberScaffoldState()
    val scope = rememberCoroutineScope()

    Scaffold(
        topBar = {
            MyTopAppBar(
                name = "Toolbar Sample",
                scope = scope,
                scaffoldState = scaffoldState,
                context = context
            )
        },
        scaffoldState = scaffoldState,
        drawerContent = {
            NavigationDrawer(
                currentScreen = Screen.Home
            ) {
                showToast(context, it)
                scope.launch {
                    delay(timeMillis = 200)
                    scaffoldState.drawerState.close()
                }
            }
        }
    ) {

    }
}

Scaffold 레이아웃을 통해서 Navigation Drawer 화면을 설정할 수 있습니다. rememberScaffoldState()를 변수 scaffoldState에 지정하고, Scaffold 매개변수로 넘겨줍니다. drawerContent에는 이전에 만든 NaviagtionDrawer Composable을 생성하고, currentScreen에 Home 화면을 지정해줍니다. NaviagtionDrawer의 itemClick 식, 토스트 메시지와 drawerState를 close롤 호출하여 Navigation Drawer를 닫아주는 코드를 만듭니다.

 

@Composable
fun MyTopAppBar(
    name: String,
    scope: CoroutineScope,
    scaffoldState: ScaffoldState,
    context: Context,
) {
    var shouldShowDialog by remember { mutableStateOf(false) }
    var dropdownMenuExpanded by remember { mutableStateOf(false) }

    TopAppBar(
        title = { Text(text = name) },
        contentColor = MaterialTheme.colors.primary,
        backgroundColor = Color.Yellow,
        navigationIcon = {
            IconButton(onClick = {
                scope.launch {
                    scaffoldState.drawerState.open()
                }
            }) {
                Icon(
                    imageVector = Icons.Filled.Menu,
                    contentDescription = "Menu"
                )
            }
        },
        elevation = 12.dp,
        actions = {
            IconButton(onClick = {
                shouldShowDialog = true
            }) {
                Icon(
                    imageVector = Icons.Filled.Share,
                    contentDescription = "Share",
                    tint = MaterialTheme.colors.primary
                )
            }

            AlertDialogSample(shouldShowDialog = shouldShowDialog) {
                shouldShowDialog = false
            }

            IconButton(onClick = {
                dropdownMenuExpanded = true
            }) {
                Icon(
                    imageVector = Icons.Filled.MoreVert,
                    contentDescription = "MoreVert",
                    tint = MaterialTheme.colors.primary
                )
            }

            DropDownMenuSample(context, dropdownMenuExpanded) {
                dropdownMenuExpanded = false
            }
        }
    )
}

 

sealed class Screen {
    object Home: Screen()
    object Search: Screen()
    object Map: Screen()
    object Settings: Screen()
}

 

 

 

댓글