[Android / Kotlin] Bottom Navigation View 구현하기 (Jetpack Navigation)

선주·2022년 2월 25일
0

Android

목록 보기
8/11
post-thumbnail

🎈 Navigation 구성요소

1) Navigation Graph

모든 Navigation 관련 정보가 하나의 중심 위치에 모여 있는 XML 리소스. 단순히 말해 사용자가 앱에서 갈 수 있는 모든 플로우를 보여주고 앱내의 Fragment를 한눈에 확인 할 수 있다.

2) NavHost

Navigation Graph에서 대상을 표시하는 빈 컨테이너. 대상 구성요소에는 프래그먼트 대상을 표시하는 기본 NavHost 구현인 NavHostFragment가 포함된다.

3) NavController

NavHost에서 App Navigation을 관리하는 객체. NavController는 사용자가 앱 내에서 이동할 때 NavHost에서 대상 콘텐츠의 전환을 조종하는 역할을 한다.

동작방식

Navigation Graph에서 특정 경로를 따라 이동할지, 특정 대상으로 직접 이동할지 NavController에게 전달하고 NavController가 NavHost에 적절한 대상을 표시해주는 방식!


🔨 build.gradle 의존성 추가

Module단위 build.gradle 파일을 열어 plugins, android, dependencies에 아래 라인을 추가해주자!

plugins {
    id 'kotlin-kapt'
}

android {
    buildFeatures {
        dataBinding true
    }
}

dependencies {
    implementation("androidx.navigation:navigation-fragment-ktx:2.4.0")
    implementation("androidx.navigation:navigation-ui-ktx:2.4.0")
} 

navigation의 버전은 공식문서에서 확인한 후 안정된 버전으로 작성하는 것이 좋다. 현재 내가 글을 쓰는 시점에서는 2.4.0 버전이 권장된다.


📂 Fragment 생성

이대로 생성하면 Fragment와 그와 연결된 레이아웃이 함께 만들어진다. Fragment 이름을 HomeFragment라고 명명하면 fragment_home.xml이 같이 생성되는 것!


🚀 Navigation Graph 생성

res 폴더 아래에 navigation 디렉터리를 만들고, nav_graph.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"
    android:id="@+id/nav_graph"
    app:startDestination="@+id/homeFragment">

    <fragment
        android:id="@+id/homeFragment" 
        android:name="com.example.heyhong.fragment.HomeFragment"
        android:label="HomeFragment"
        tools:layout="@layout/fragment_home" />

    <fragment
        android:id="@+id/buildingFragment"
        android:name="com.example.heyhong.fragment.BuildingFragment"
        android:label="BuildingFragment"
        tools:layout="@layout/fragment_building" />

    <fragment
        android:id="@+id/facilityFragment"
        android:name="com.example.heyhong.fragment.FacilityFragment"
        android:label="FacilityFragment"
        tools:layout="@layout/fragment_facility" />

    <fragment
        android:id="@+id/noticeFragment"
        android:name="com.example.heyhong.fragment.NoticeFragment"
        android:label="NoticeFragment"
        tools:layout="@layout/fragment_notice" />

</navigation>

(1) navigation

  • app:startDestination="@+id/homeFragment" 속성을 추가한다.
    앱 실행 시 가장 처음 뜨는 프래그먼트를 지정하는 속성이다.

(2) fragment

  • Navigation을 이용해 왔다리갔다리 할 프래그먼트들을 모두 정의해둔다.
  • name: 프래그먼트 파일의 경로를 넣어준다.
  • layout: 프래그먼트의 xml파일을 연결해준다.

🚀 Menu 생성

res 폴더 아래에 menu 디렉터리를 만들고, nav_menu.xml 파일을 생성한다.

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

    <item
        android:id="@+id/homeFragment"
        android:icon="@drawable/ic_menu_home"
        android:title=""/>

    <item
        android:id="@+id/buildingFragment"
        android:icon="@drawable/ic_menu_building"
        android:title="건물"/>

    <item
        android:id="@+id/facilityFragment"
        android:icon="@drawable/ic_menu_facility"
        android:title="시설"/>

    <item
        android:id="@+id/noticeFragment"
        android:icon="@drawable/ic_menu_notice"
        android:title="공지"/>

</menu>
  • id: 내비게이션 그래프의 프래그먼트 id와 동일하게 작성해야 맵핑을 통해 바텀내비게이션바로 만들어줄 수 있다.
  • icon: 바텀내비게이션에 표시될 아이콘 이미지를 연결한다.
  • title: 바텀내비게이션에 표시될 레이블 텍스트를 작성한다.

🎨 selector 생성

menu_selector.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="@color/blue_1" android:state_checked="true"/>
    <item android:color="@color/black" android:state_checked="false"/>
</selector>

아이템을 클릭한 상태와 클릭하지 않은 상태에 색을 다르게 주기 위한 파일이다.
android:state_checked="true"가 클릭한 상태, false가 클릭하지 않은 상태다.


🏠 activity_main.xml 수정

<?xml version="1.0" encoding="utf-8"?>
<layout>

    <androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <fragment
            android:id="@+id/nav_host"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            app:navGraph="@navigation/nav_graph"
            app:defaultNavHost="true"
            app:layout_constraintBottom_toTopOf="@id/nav_bar"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <com.google.android.material.bottomnavigation.BottomNavigationView
            android:id="@+id/nav_bar"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:background="@color/white"
            app:menu="@menu/nav_menu"
            app:itemBackground="@color/white"
            app:itemIconTint="@drawable/menu_selector"
            app:itemTextColor="@drawable/menu_selector"
            app:labelVisibilityMode="labeled"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/nav_host" />

    </androidx.constraintlayout.widget.ConstraintLayout>

</layout>

(1) fragment

  • android:name="androidx.navigation.fragment.NavHostFragment"
    탐색 그래프에서 대상을 표시하는 빈 컨테이너인 NavHost 역할을 하도록 설정한다.

  • app:navGraph="@navigation/nav_graph"
    NavHostFragment와 내비게이션 그래프를 연결시킨다.

  • app:defaultNavHost="true"
    뒤로가기 버튼을 누르면 NavHostFragment(@navigation/navi_graph에서 app:startDestination으로 설정)로 돌아오게 설정한 것이다.
    기본값은 false이고, 뒤로가기 버튼을 누르면 앱이 종료된다.

(2) BottomNavigationView

  • app:menu="@menu/nav_menu"
    BottomNavigationView와 메뉴를 연결시킨다.

  • app:labelVisibilityMode="labeled"
    아이콘 밑의 레이블을 보이게 설정한다. 숨기고 싶으면 unlabeled로 설정한다.

  • app:itemIconTint="@drawable/menu_selector" (아이콘)
    app:itemTextColor="@drawable/menu_selector" (레이블)
    아이콘과 레이블의 색상을 지정해주는 속성인데, 아이템을 클릭한 상태와 클릭하지 않은 상태에 색을 다르게 주기 위해 위에서 만들었던 selector를 연결해준다.

  • app:itemBackground="@color/white"
    아이템을 클릭할 때 검은 원이 퍼져나가는 ripple효과를 제거하기 위한 속성이다.


🏠 MainActivity 수정

class MainActivity : AppCompatActivity() {
    private lateinit var binding : ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        initBinding()
        initNavigation()
    }

    private fun initBinding() {
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
    }

    private fun initNavigation() {
        NavigationUI.setupWithNavController(binding.navBar, findNavController(R.id.nav_host))
    }
}

NavController

  • NavHost에서 App Navigation을 관리하는 객체. NavController는 사용자가 앱 내에서 이동할 때 NavHost에서 대상 콘텐츠의 전환을 조종하는 역할을 한다.

NavigationUI.setupWithNavController

  • 바텀내비게이션 view와 navController를 인자로 받고, 이 바텀내비게이션에서 이동이 일어나면 그에 따라 navController가 NavHost에 프래그먼트를 그려준다. 이 과정에서 바텀내비게이션의 menu id와 fragment id가 자동으로 맵핑된다.




참고 문서
https://hayeon1549.tistory.com/2
https://jae-young.tistory.com/46
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

profile
기록하는 개발자 👀

0개의 댓글