[안드로이드]네비게이션 드로어(Navigation Drawer) JetPack 제대로 쓰자!

2021. 1. 17. 21:03개발/[Kotlin] 안드로이드 개발

반응형

안녕하세요 ! 계속 해서 프로젝트를 하다가 조금씩 까먹는 일이 발생해서 역시 공부한 것을 정리해야한다고 생각해서 블로그 다시 시작합니다 !

이번엔 네비게이션 드로어 구현에 대해 포스팅 해보려구 합니다!

결과물 먼저 보고 가실게요 ! 오늘은 NavigationView를 사용을 해 탐색 하는 방법에 대해 포스팅 후 내일부터는 navigation으로 화면 전환 및 데이터 전달에 대해 알아보려고 합니다 !

우선 build.gradle 앱 수준에 인젝션 해주고 sync를 해줍니다.

    def nav_version = "2.3.2"
    implementation "androidx.drawerlayout:drawerlayout:1.1.1"
       
    // Kotlin
    implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
    implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
    implementation 'com.google.android.material:material:1.2.1'
    
   

네비게이션 드로어를 만들기 위해서는

1. res-navigation Directory를 만든 후 resource파일 navigation을 만들어 줍니다. (프래그먼트 2개를 만들어주세요)

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/navigation"
    app:startDestination="@id/main">

    <fragment
        android:id="@+id/main"
        android:name="com.cookandroid.navdrawer.MainFragment"
        android:label="메인화면"
        tools:layout="@layout/fragment_main">
        <action
            android:id="@+id/action_blankFragment_to_secondFragment"
            app:destination="@id/second" />
    </fragment>
    <fragment
        android:id="@+id/second"
        android:name="com.cookandroid.navdrawer.SecondFragment"
        android:label="두번재 화면"
        tools:layout="@layout/fragment_second" />
</navigation>

프래그먼트 2개를 만들어서 네비게이션 서랍 탐색하는걸 구현할 겁니다 !!

화살표를 끌어당기면 action이 생기게 되고 main->second로  이동한다는 action입니다.

2. res-menu directory를 만든후 main_drawer_navigation Menu resource파일을 만들어줍니다.

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id = "@+id/main"
        android:title="메인화면"></item>
<item android:id = "@+id/second"
    android:title="두번재 프래그먼트"></item>
</menu>

※ 주의해야할 점은 메뉴 xml와 navigation xml의 아이디가 같아야 별도의 이벤트 처리 없이 화면전환을 할 수 있습니다.

ex) item "@+id/main = fragment "@+id/main

3. 액션바를 없애고 툴바 사용 후 MainActivity 작업

res - values - themes를 누르시면 이 테마 리소스 파일을 보실 수 있습니다. 액션바가 나타나지 않게 NoActionBar로 바꿔줍니다.

1. activity_main.xml로 이동 후 최상위 부모 레이아웃을 DrawerLayout으로 바꿔줍니다.

2. 추가로 toolbar를 actionBar높이로 만들고 navHostFragment를 검색 후 툴바아래쪽에 위치 시켜줍니다.

3. nav_host_fragment는 액티비티에 프래그먼트를 붙이고 화면이 보이는 객체라고 생각하시면 됩니다.

  • defaultNavHost를 true로 설정하면 Back key를 눌렀을 때 이전 화면으로 전환됩니다. 만약 false로 설정하고 Back key를 누르면 앱을 종료합니다.
  • navGraph는 graph를 정의한 파일을 의미합니다.

4. NavigationView를 추가해줍니다. 네비게이션뷰는 아래 사진을 말합니다 ㅎㅎ 평소에는 안보이지만 스와이프 혹은 툴바 버튼 클릭으로 나왔다가 들어갔다가 합니다.

  • NavigationView에 아까 만든 menu를 포함시킵니다.
  • headerLayout을 사용해 네비게이션뷰 상단에 노출 시킬 수도 있습니다. (간단 코드)
더보기

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/login_layout"
android:layout_width="match_parent"
android:layout_height="200dp"
android:padding="20dp"
android:orientation="vertical">

<ImageView
android:id="@+id/header_icon"

android:background="yourScreenShot"

android:layout_width="100dp"
android:layout_height="100dp" />

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20dp"
android:textStyle="bold"
android:textColor="#000000"
android:text="YangDroid"/>

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="15dp"
android:textColor="#EB554C4C"
android:text="yang-droid.tistory.com"/>
</LinearLayout>

 

activity_main.xml 전체코드

더보기

<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
>
<data>
<variable
name="main"
type="com.cookandroid.navdrawer.MainActivity" />
</data>
<androidx.drawerlayout.widget.DrawerLayout
android:id="@+id/drawer"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">

<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<fragment
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar"
app:navGraph="@navigation/navigation" />


</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.navigation.NavigationView
android:id="@+id/navigationView"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:menu="@menu/main_drawer_navigation"
app:headerLayout = "@layout/nav_header"
>
</com.google.android.material.navigation.NavigationView>
</androidx.drawerlayout.widget.DrawerLayout>
</layout>

자 이제 리소스 파일 관리는 끝났습니다 !

이제 MainActivity로 돌아와서 연결해주는 작업을 해야합니다.

1. navController와 appBarConfiguration 정의 하기

navController = findNavController(R.id.nav_host_fragment)로 보여줄 화면의 view를 가져옵니다

appBarConfiguration = AppBarConfiguration(setOf(R.id.main,R.id.second),binding.drawer)

appBarConfiguration은 현재 보여지고 있는 화면의 Label을 AppBar에 보여주고 싶을 수 있습니다. AppBarConfiguration을 이용하면 네비게이션 그래프에 정의된 Label을 AppBar에 출력할 수 있습니다. 더불어 AppBar에 뒤로가기(<-) 버튼까지 보여줍니다. 뒤로가기 버튼은 startDestination로 정의된 처음 화면이 아닐 때만 보여줍니다.

setOf(R.id.main,R.id.second) 이렇게 main과 second를 지정해주면 main과 second일 때는 뒤로가기(<-)가 나오지 않습니다. TopLevel로 지정하는거라 생각하시면 됩니다. 그리고 drawer와 연결해주면 됩니다.

라벨을 앱바에 보여주고 싶으면 res-navigation-navigation.xml의 프래그먼트의 label을 바꿔주시면 됩니다.

2. initNavigationView()

with(binding) {
navigationView.setupWithNavController(navController)
}

-> NavigationView를 NavController가 사용할 수 있도록 설정해준다.

(NavigationView의 item 클릭 시 fragment가 변경되도록 설정해줌)

3. initToolbar()

setSupportActionBar(binding.toolbar)
setupActionBarWithNavController(navController, appBarConfiguration)

-> 툴바를 사용한다 선언 후 NavController와 AppBarConfiguration에 맞춰 ActionBar를 설정해준다.

(destination, 즉 부분 화면이 바뀔 때마다 ActionBar의 title을 변경해줌)

4. override fun onSupportNavigateUp(): Boolean 

override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}

->AppBar에 생성되는 뒤로가기 버튼을 눌렀을 때, 뒤로 이동하려면 onSupportNavigateUp를 오버라이드 한다

5. override fun onBackPressed()

with(binding) {
if (drawer.isDrawerOpen(navigationView)) {
drawer.closeDrawer(navigationView)
} else {
super.onBackPressed()
}
}

-> BackPressed버튼을 누르면 navigationView가 열려있으면 드로어를 닫고 아니면 원래대로 뒤로가기 버튼이 작동 되도록 한다.

MainActivity 전체코드

더보기

package com.cookandroid.navdrawer

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.databinding.DataBindingUtil
import androidx.navigation.NavController
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.navigateUp
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import com.cookandroid.navdrawer.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
lateinit var navController: NavController
lateinit var appBarConfiguration: AppBarConfiguration
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

binding = DataBindingUtil.setContentView(this,R.layout.activity_main )
binding.main = this
navController = findNavController(R.id.nav_host_fragment)
appBarConfiguration = AppBarConfiguration(setOf(R.id.main,R.id.second),binding.drawer)
initToolbar()
initNavigationView()

}

private fun initNavigationView() {
with(binding) {
navigationView.setupWithNavController(navController)
}
}

private fun initToolbar() {
setSupportActionBar(binding.toolbar)
setupActionBarWithNavController(navController, appBarConfiguration)
}

override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}

override fun onBackPressed() {
with(binding) {
if (drawer.isDrawerOpen(navigationView)) {
drawer.closeDrawer(navigationView)
} else {
super.onBackPressed()
}
}
}
}

이상으로 기본적인 navigationdrawer의 사용방법을 알아보았습니다. 

컴파일 해보시면 잘 작동되시는 것을 볼 수 있습니다 ㅎㅎㅎㅎ

다음엔 safe args를 활용한 데이터 전달 및 화면 이동등을 알아볼게요 감사합니다 ~~

반응형