관리 메뉴

막내의 막무가내 프로그래밍 & 일상

[안드로이드] Android Jetpack Navigation 정리 및 BottomNavigationView 에 적용 + ActionBar 적용 (Kotlin) 본문

안드로이드/코틀린 & 아키텍처 & Recent

[안드로이드] Android Jetpack Navigation 정리 및 BottomNavigationView 에 적용 + ActionBar 적용 (Kotlin)

막무가내막내 2020. 4. 29. 17:56
728x90

[2021-03-30 업데이트]

 

안드로이드 코틀린 Jetpack 라이브러리들에 대해 공부중이고 Jetpack Naviagtion 중 Bottom navigation 을 프로젝트에 간단하게 적용해볼려 하고있습니다.

 

보면서 도움이 되는 사이트를 기록합니다.

 

0. 공식문서

https://developer.android.com/guide/navigation/

 

탐색  |  Android 개발자  |  Android Developers

Android Jetpack의 탐색 구성요소를 사용하여 앱에서 탐색 구현

developer.android.com

 

1. 코드랩

https://codelabs.developers.google.com/codelabs/android-navigation/index.html?index=..%2F..%2Findex#0

 

 

2. 유용한 글

https://android.jlelse.eu/beginners-guide-to-bottom-navigation-with-android-jetpack-5485d2b8bbb5

 

🚀Beginner’s Guide to Bottom Navigation with Android Jetpack — Part 1

A step-by-step guide for beginners on how to create Bottom Navigation using Android Jetpack Navigation

android.jlelse.eu

https://medium.com/harrythegreat/android-navigation-component-%EA%B0%9C%EB%85%90%EA%B3%BC-%ED%8A%9C%ED%86%A0%EB%A6%AC%EC%96%BC-1-5ac6ac081643

 

Android Navigation Component 개념과 튜토리얼 — 1

Jetpack과 함께 소개된 안드로이드 네비게이션은 기존 정말 복잡하고 난해하고 코드를 스파게티로 만들어줬던 Fragment와 Activity간 구현을 심플하고 안정적으로 이동할 수 있도록 도와주는 컴포넌트입니다. 특히 가장 큰 이점은…

medium.com

https://medium.com/@maryangmin/navigation-components-in-android-jetpack-1-introduction-e38442f70f

 

Navigation Components in Android Jetpack (1) — Introduction

Google이 Google I/O 2018에서 Jetpack을 발표하였습니다. Jetpack은 좋은 안드로이드 앱을 더 쉽게 만들 수 있도록 구글에서 지원하는 라이브러리 패키지를 뜻합니다. Jetpack에는 많은 라이브러리가 포함��

medium.com

 

 

일단은 ONE 액티비티에 THREE 프래그먼트 구조의 간단한 공부용 토이 프로젝트에 적용해봤습니다.

액티비티의 BottomNavigationView와 프래그먼트를 연결하는 작업을 해봤습니다. 간단하게 정리해봅니다.

개념과 다양한 기능 및 특징은 위 사이트들을 참고하고 공부합니다.

밑 사진은 공식문서에서 간단하게 요약정리가 잘 되어 있어 들고와봤습니다. 저 3가지 핵심요소 NavHost, NavController, 탐색그래프(NavGraph) 는 필히 아셔야 합니다.

 

 

0. 번들같이 값을 전달하는 작업이 없고 바텀네비게이션뷰를 이용한 프래그먼트 swap만 할 것이므로 다음 디펜던시만 추가해주면됩니다. 전자의 작업이나 다른 작업할 시 추가로 다른 디펜던시를 추가해야합니다.

// navigation
    implementation 'androidx.navigation:navigation-fragment-ktx:2.2.2'
    implementation 'androidx.navigation:navigation-ui-ktx:2.2.2'

    // For BottomNavigationView from Material Components
    implementation 'com.google.android.material:material:1.1.0'

 

 

1. 먼저 아래와 같이 3개의 프래그먼트와 하나의 액티비티가 있습니다.

 

 

 

 

 

2. 액티비티의 xml 입니다.

프레임레이아웃 안에 프래그먼트를 넣고 name을 android:name="androidx.navigation.fragment.NavHostFragment" 로 설정합니다. 호스트 역할을 할 것입니다. (메인역할)  즉 메인 액티비티는 Content와 Navigation Method는 모두 NavHost 라는 Fragment에게 위임합니다.

메인 액티비티의 xml 은 싱글 액티비티 구성일 경우 Global 한 네비게이션을 가지는 역할을 합니다.

 

app:defaultNavHost="true" 을 함으로써 뒤로가기 버튼 클릭시 NavHostFragment 로 돌아옵니다. 안할 경우 뒤로가기

버튼 클릭시 호스트화면으로 안가고 바로 앱이 종료될 것 입니다.

 

app:navGraph="@navigation/bottom_nav_graph" NavHostFragment 와 설정한 네비게이션 그래프를 연결(연관)시켜줍니다. 네비게이션 그래프는이 NavHostFragment에서 사용자가 탐색 할 수있는 모든 목적지를 지정합니다

NavHostFragment 에대해선 다음을 참고합니다.

https://developer.android.com/reference/androidx/navigation/fragment/NavHostFragment

<?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>

    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".views.MainActivity">

        <FrameLayout
            android:id="@+id/main_fl_container"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            app:layout_constraintBottom_toTopOf="@id/main_bottom_navigation"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintEnd_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent">

            <fragment
                android:id="@+id/main_nav_host"
                android:name="androidx.navigation.fragment.NavHostFragment"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:defaultNavHost="true"
                app:navGraph="@navigation/bottom_nav_graph" />
        </FrameLayout>

        <com.google.android.material.bottomnavigation.BottomNavigationView
            android:id="@+id/main_bottom_navigation"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:background="@color/colorWhiteBlue"
            app:itemIconTint="@color/colorWhite"
            app:itemTextColor="@color/colorWhite"
            app:layout_behavior="tech.thdev.app.view.BottomNavigationBehavior"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/main_fl_container"
            app:menu="@menu/bottom_menu" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

 

 

 

 

3. 네비게이션 그래프 xml 입니다.

<?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"
    app:startDestination="@id/countryFragment">

    <fragment
        android:id="@+id/countryFragment"
        android:name="com.mtjin.coronakorea.views.country.CountryFragment"
        android:label="CountryFragment"
        tools:layout="@layout/fragment_country" />
    <fragment
        android:id="@+id/cityFragment"
        android:name="com.mtjin.coronakorea.views.city.CityFragment"
        android:label="CityFragment"
        tools:layout="@layout/fragment_city" />
    <fragment
        android:id="@+id/updateFragment"
        android:name="com.mtjin.coronakorea.views.update.UpdateFragment"
        android:label="updateFragment"
        tools:layout="@layout/fragment_update" />
</navigation>

직접 xml로 추가할 수도 있지만 이미 프래그먼트가 만들어져 있는 경우  밑 사진의 동그라미 친 버튼을 통해 쉽게 추가가 가능합니다. navigation 태그안에 각 프래그먼트가 그래프로 추가됩니다. 이때 id는 추후 bottomNavigationView 의 메뉴 아이디와 동일해야 네비게이션 기능이 이어져서 동작됩니다.

추가로 navigation 태그에 startDestinaion을 설정하여 처음 띄워질(이동할) 화면을 설정이 가능합니다.

또한 전 하나의 FrameLayout 안에 fragment를 탐색하는(이동) 용도로만 써서 오른쪽의 UI가 저렇게 겹치게만 되있습니다. 

다른 값 전달 밑 특정 프래그먼트에서 다른 프래그먼트를 네비게이션하는 구조라면 밑과 같이 그려집니다. 네비게이션 장점중 하나가 이렇게 레이아웃 구조를 한눈에 보기 좋은 면도 있습니다. 

ex

 

토이프로젝트

 

 

 

4. 바텀네비게이션뷰의 menu xml 입니다. 해당 바텀네비게이션의 뷰를 누를 때 이동해할 프래그먼트와 id를 매칭시켜주어야합니다. (3번에서의 네비게이션 그래프의 fragment id와 매칭해줘야합니다.) 

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/countryFragment"
        android:icon="@drawable/ic_statistics_white_24dp"
        android:title="@string/menu_total_stat_title_text" />

    <item
        android:id="@+id/cityFragment"
        android:icon="@drawable/ic_city_white_24dp"
        android:title="@string/menu_local_stat_title_text" />

    <item
        android:id="@+id/updateFragment"
        android:icon="@drawable/ic_update_white_24dp"
        android:title="@string/menu_ready_title_text" />

</menu>

 

 

 

 

 

5. 마지막으로 액티비티에서 NavController로 세팅해주면 끝이 납니다. (initNavigation())

NavController란 NavController는 위에서 만든 내비게이션 그래프에 맞게 main_nav_host (호스트 네비게이션) 안이 구현되도록 도와주는 오브젝트입니다.

더 자세한 설명과 예제는 위 참고사이트나 아래 사이트를 참고합니다.

https://codelabs.developers.google.com/codelabs/android-navigation/index.html?index=..%2F..%2Findex#4

package com.mtjin.coronakorea.views

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.navigation.findNavController
import androidx.navigation.ui.setupWithNavController
import com.mtjin.coronakorea.R
import com.mtjin.coronakorea.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        initBinding()
        initNavigation()
    }

    private fun initNavigation() {
        val navController = findNavController(R.id.main_nav_host)
        binding.mainBottomNavigation.setupWithNavController(navController)
        // 위와 같은 2번째 방법
//        NavigationUI.setupWithNavController(
//            main_bottom_navigation,
//            findNavController(R.id.main_nav_host)
//        )
    }

    private fun initBinding() {
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        binding.lifecycleOwner = this
    }

    companion object {
        const val TAG = "MainActivityTag"
    }
}

 

 

 

6. 결과

보통 바텀바를 사용할 때 리스너를 사용해서 분기문으로 supportFragmentManager 를 사용해 replace 했었는데 그런 코드 없이 네비게이션을 통해 자동으로 연결됨을 볼 수 있습니다. 그리고 app:defaultNavHost="true" 로 인해 예시로 두번째 프래그먼트에서 뒤로가기 누를시 호스트화면(첫번째 프래그먼트)로 이동함을 볼 수 있습니다.  백스택 관리도 해주므로 매우 좋은 것 같습니다.

적용한 토이프로젝트 포스팅 내용은 간단한 네비게이션의 기능중 하나의 예이고 문서를 읽어보니 다양하고 좋은 기능이 많더라고요. 더 자세히 공부해보고 추후 프로젝트에 적용하면 좋을 것 같습니다. (바텀바뿐만 아니라 메뉴,툴바 등 적용, 값 전달, navigation을 통해 한눈에 앱 레이아웃 및 탐색 구조를 보기 좋고 관리하기 유용, Argument 값 전달, 애니메이션적용 등...)

 

 

 

 

 

위 프로젝트는 다음 저장소에서 보실 수 있습니다. :)

github.com/mtjin/CoronaKoreaReleaseVersion

 

mtjin/CoronaKoreaReleaseVersion

출시버전. Contribute to mtjin/CoronaKoreaReleaseVersion development by creating an account on GitHub.

github.com

 

 

 


[2021-01-23 업데이트]

액션바도 jetpack navigation이 적용이 가능한데 샘플 코드를 기록합니다. 주석을 보시면 기능이 이해가 가실거라고 생각합니다.  쉽게 액션바 및 뒤로가기 버튼이 자동 구현되니 유용할 수 있다 생각합니다. :)  

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.findNavController
import androidx.navigation.ui.setupActionBarWithNavController

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

            setupActionBarWithNavController(findNavController(R.id.navHostFragment)) //액션바 뒤로가기 버튼 생김
    }

    override fun onSupportNavigateUp(): Boolean { //액션바 뒤로가기 클릭 시 동작
        val navController = findNavController(R.id.navHostFragment)
        return navController.navigateUp() || super.onSupportNavigateUp() //
    }
}

이 코드의 링크는 github.com/mtjin/to-do-android-app 입니다.

 

 

 

댓글과 공감은 큰 힘이 됩니다. 감사합니다. !!

 

 

728x90
Comments