본문 바로가기
개발/안드로이드

Android Jetpack의 Navigation을 이용하여 Drawer 구현

by darksilber 2019. 7. 10.
반응형

 


출처 - https://codechacha.com/ko/android-navigation-drawer/

 

Android Jetpack의 Navigation을 이용하여 Drawer 구현 - codechacha

네비게이션은 Drawer를 지원하는데요. Navigation을 이용하여 Drawer를 구현하는 방법을 알아보겠습니다. 간단히 샘플앱을 만들어보죠. 먼저 프로젝트를 생성하고 의존성 라이브러리를 모두 추가합니다. 이 글은 AndroidX를 사용하기 때문에 그렇지 않다면 마이그레이션이 필요합니다.

codechacha.com

지난 글 Android Jetpack Navigation으로 화면 전환 구현에 이어 Navigation을 이용하여 Drawer를 구현하는 방법을 알아보겠습니다. 지난 번에는 네이게이션 그래프로 순환 구조를 정의하였고, AppBar에 Label을 출력하도록 하였습니다.

네비게이션은 Drawer를 지원하는데요. 이번에는 네비게이션을 이용하여 Drawer를 구현해보겠습니다. 간단히 샘플앱을 만들어보죠.

프로젝트 생성

Basic Activity로 생성합니다.

Kotlin과 Use AndroidX artifacts를 선택해주세요. (Android Studio 버전이 3.4 미만이라면 이 기능이 없습니다. 마이그레이션 기능을 이용하거나 직접 의존성을 변경해줘야 합니다)

AndroidX로 프로젝트를 생성하지 않았다면, 메뉴에서 [Refactor] -> [Migrate to AndroidX...] 를 누르시면 AndroidX를 사용하는 프로젝트로 마이그레이션이 됩니다.

Navigation을 사용하려면 앱 gradle에서 dependency를 추가해야 합니다.

dependencies { .... implementation 'android.arch.navigation:navigation-fragment:1.0.0-alpha07' implementation 'android.arch.navigation:navigation-ui-ktx:1.0.0-alpha07' implementation "com.google.android.material:material:1.0.0" }

 

View 객체 생성

화면의 단위는 fragment입니다. MainFragment와 SubFragment 두개의 화면을 생성하고 Drawer에서 두개의 화면으로 진입할 수 있도록 구현하겠습니다.

MainFragment.kt

class MainFragment : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_main, container, false) return view } }

SubFragment.kt

class SubFragment : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_sub, container, false) return view } }

fragment_main.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="Main fragment" android:textSize="24sp"/> FrameLayout>

fragment_sub.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="Sub fragment" android:textSize="24sp"/> FrameLayout>

Host 설정

Drawer에서 메뉴를 선택했을 때 MainActivity의 화면이 변경되어야 하기 때문에, MainActivity의 fragment를 Host로 설정하려고 합니다. activity_main.xml에서 CoordinatorLayout를 사용하지 않고 DrawerLayout로 변경해야 합니다. 그리고 fragment를 추가하고 호스트로 설정을 해줍니다. 모든 수정이 끝난 코드는 다음과 같습니다.

activity_main.xml

<androidx.drawerlayout.widget.DrawerLayout 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/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <com.google.android.material.appbar.AppBarLayout android:layout_height="wrap_content" android:layout_width="match_parent" android:theme="@style/AppTheme.AppBarOverlay"> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.PopupOverlay"/> com.google.android.material.appbar.AppBarLayout> <fragment android:id="@+id/nav_fragment" android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="match_parent" android:layout_height="match_parent" app:defaultNavHost="true" app:navGraph="@navigation/nav_graph"/> LinearLayout> <com.google.android.material.floatingactionbutton.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|end" android:layout_margin="@dimen/fab_margin" app:srcCompat="@android:drawable/ic_dialog_email"/> androidx.drawerlayout.widget.DrawerLayout>

 

Navigation graph 정의

그래프는 navigation 태그 아래에 MainFragment와 SubFragment를 추가했습니다. 그리고 처음 보여지는 화면은 MainFragment로 하고 싶기 때문에 startDestination는 MainFragment로 설정했습니다.

/res/navigation/nav_graph.xml

<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" app:startDestination="@+id/main_fragment"> <fragment android:id="@+id/main_fragment" android:name="com.codechacha.navi.drawer.MainFragment" android:label="Main fragment" tools:layout="@layout/fragment_main" > fragment> <fragment android:id="@+id/sub_fragment" android:name="com.codechacha.navi.drawer.SubFragment" android:label="Sub fragment" tools:layout="@layout/fragment_sub"/> navigation>

이제 빌드는 가능하겠네요. 실행해보면 MainFragment 화면이 보입니다. 하지만 Drawer가 구현되지 않아 SubFragment로 이동할 수 없네요.

Drawer 구현

Drawer를 구현하려면 activity_main.xml에 NavigationView를 정의해야 합니다. NavigationView를 추가한 activity_main.xml의 코드는 다음과 같습니다.

activity_main.xml

<androidx.drawerlayout.widget.DrawerLayout 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/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <com.google.android.material.appbar.AppBarLayout android:layout_height="wrap_content" android:layout_width="match_parent" android:theme="@style/AppTheme.AppBarOverlay"> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.PopupOverlay"/> com.google.android.material.appbar.AppBarLayout> <fragment android:id="@+id/nav_fragment" android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="match_parent" android:layout_height="match_parent" app:defaultNavHost="true" app:navGraph="@navigation/nav_graph"/> LinearLayout> <com.google.android.material.navigation.NavigationView android:id="@+id/navigation_view" style="@style/Widget.MaterialComponents.NavigationView" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" app:headerLayout="@layout/nav_header" app:menu="@menu/menu_navigation"/> <com.google.android.material.floatingactionbutton.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|end" android:layout_margin="@dimen/fab_margin" app:srcCompat="@android:drawable/ic_dialog_email"/> androidx.drawerlayout.widget.DrawerLayout>

Drawer(NavigationView)에서 보여지는 View로, nav_header와 menu_navigation도 만들어줘야 합니다.

nav_header.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="192dp" android:background="?attr/colorPrimaryDark" android:gravity="bottom" android:orientation="vertical" android:padding="16dp" android:theme="@style/ThemeOverlay.AppCompat.Dark"> <ImageView android:layout_width="100dp" android:layout_height="wrap_content" android:layout_gravity="center" android:src="@mipmap/ic_launcher" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|center_horizontal" android:text="Codechacha" android:textAppearance="@style/TextAppearance.AppCompat.Body1"/> FrameLayout>

menu_navigation.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/main_fragment" android:title="Main fragment"/> <item android:id="@+id/sub_fragment" android:title="Sub fragment"/> menu>

이제 xml은 모두 만들었고 MainActivity.kt에 코드를 조금 추가해주면 됩니다.

지난 글에서 AppBarConfiguration를 사용해보았는데요. drawer와 함께 사용하려면 인자로 drawer_layout도 전달해야 합니다.

navController = Navigation.findNavController(this, R.id.nav_fragment) appBarConfiguration = AppBarConfiguration(navController.graph, drawer_layout)

NavController와 AppBarConfiguration를 생성하고 ActionBar에 등록을 해줍니다. 추가로 navigation_view에 NavController를 설정해줍니다.

setSupportActionBar(toolbar) setupActionBarWithNavController(navController, appBarConfiguration) // Set up navigation menu navigation_view.setupWithNavController(navController)

뒤로가기 버튼과 Back key를 눌렀을 때 이전 화면으로가기 위해 다음과 같은 코드를 추가해야 합니다.

override fun onSupportNavigateUp(): Boolean { return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp() } override fun onBackPressed() { if (drawer_layout.isDrawerOpen(GravityCompat.START)) { drawer_layout.closeDrawer(GravityCompat.START) } else { super.onBackPressed() } }

완성된 MainActivity.kt는 다음과 같습니다.

MainActivity.kt

class MainActivity : AppCompatActivity() { private lateinit var appBarConfiguration: AppBarConfiguration private lateinit var navController: NavController override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) navController = Navigation.findNavController(this, R.id.nav_fragment) appBarConfiguration = AppBarConfiguration(navController.graph, drawer_layout) // Set up ActionBar setSupportActionBar(toolbar) setupActionBarWithNavController(navController, appBarConfiguration) // Set up navigation menu navigation_view.setupWithNavController(navController) fab.setOnClickListener { view -> Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) .setAction("Action", null).show() } } override fun onSupportNavigateUp(): Boolean { return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp() } override fun onBackPressed() { if (drawer_layout.isDrawerOpen(GravityCompat.START)) { drawer_layout.closeDrawer(GravityCompat.START) } else { super.onBackPressed() } } override fun onCreateOptionsMenu(menu: Menu): Boolean { // Inflate the menu; this adds items to the action bar if it is present. menuInflater.inflate(R.menu.menu_main, menu) return true } override fun onOptionsItemSelected(item: MenuItem): Boolean { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. return when (item.itemId) { R.id.action_settings -> true else -> super.onOptionsItemSelected(item) } } }

실행해보면 Drawer가 동작하고 화면전환이 되는 것을 볼 수 있습니다.

참고

반응형

댓글