안드로이드 개발

[Android/Kotlin] Jetpack Bottom Navigation Bar

나도개발자 2020. 8. 17. 16:20

미리보기

 

Jetpack Navigation은 UI 전환을 쉽게 구현할 수 있도록 도와준다. Navigation을 자동으로 연결해주어 불필요한 코드 작성을 줄이고, 유지보수에도 용이하다. 또한 Back Stack 관리 등 여러 장점으로 인하여 사용하게 되었다.

 

Jetpack의 장점

  • 프래그먼트 트랜잭션 처리.
  • 기본적으로 '위로'와 '뒤로' 작업을 올바르게 처리.
  • 애니메이션과 전환에 표준화된 리소스 제공.
  • 딥 링크 구현 및 처리.
  • 최소한의 추가 작업으로 탐색 UI 패턴(예: 탐색 창, 하단 탐색) 포함.
  • Safe Args - 대상 사이에서 데이터를 탐색하고 전달할 때 유형 안정성을 제공하는 그래프 플러그인입니다.
  • ViewModel 지원 - 탐색 그래프에 대한 ViewModel을 확인해 그래프 대상 사이에 UI 관련 데이터를 공유합니다.

※ Android studio 3.3 이상부터 사용이 가능하다.

 

관련 자료

↓ Google material에서 제공하는 Bottom Navigation Bar 관련 자료

https://material.io/develop/android/components/bottom-navigation

 

Material Design

Build beautiful, usable products faster. Material Design is an adaptable system—backed by open-source code—that helps teams build high quality digital experiences.

material.io

↓ Android에서 제공하는 Jetpack 관련 자료

https://developer.android.com/jetpack?hl=ko

 

Android 개발자  |  Android Developers

Jetpack은 개발자가 관심 있는 코드에 집중할 수 있도록 권장사항 준수, 상용구 코드 제거, Android 버전과 기기에서 일관되게 작동하는 코드 작성을 돕는 라이브러리 모음입니다.

developer.android.com

 

↓ Android에서 제공하는 Jetpack Navigation 관련 자료

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

 

탐색  |  Android 개발자  |  Android Developers

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

developer.android.com

 

01. build.gradle 의존성 추가

 

 

android {} 내부에 android.dataBinding을 추가해준다.

 

[Gradle Scripts] - [build.gradle(Module: app)]

android.dataBinding {
        enabled = true
    }

 

fragment간에 값을 전달하지 않고, 전환만 할 경우 아래 Dependency만 추가해주면 된다. 전달해야 할 값이 있다면 다른 Dependency도 추가해줘야 한다.

 

[Gradle Scripts] - [build.gradle(Module: app)]

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

 

02. Fragment 생성

원하는 navigaion 갯수만큼 Fragment를 생성해준다. Google에서는 3개 이상을 사용할 것을 권장한다.

 

java 우클릭 - new - Fragment - Fragment(Blank) 클릭
Fragment Name과 Fragment Layout Name 작성 - Finish

 

03. Main XML (Bottom Navigaion Bar가 들어갈 Activity의 XML)

databinding을 위해 layout 태그로 감싸준다.

 

- fragment : android:name="androidx.navigation.fragment.NavHostFragment"

NavHost(탐색 그래프에서 대상을 표시하는 빈 컨테이너) 역할을 한다.

 

- fragment : app:defaultNavHost="true"

뒤로 가기 버튼을 누르면 NavHostFragment(@navigation/navi_graph에서 app:startDestination으로 설정)로 돌아온다. false가 기본값으로 뒤로가기 버튼을 누르면 바로 앱이 종료된다.

 

- fragment : app:navGraph="@navigation/navi_graph"

NavHostFragment와 내비게이션 그래프를 연결시킨다. (05에서 생성)

 

- BottomNavigationView : app:menu="@menu/navi_menu"

BottomNavigationView와 menu를 연결시킨다.


- BottomNavigationView : app:labelVisibilityMode="unlabeled"

아이콘 밑의 lable을 비활성화 시킨다. (menu의 title에서 지정해준다.)


- BottomNavigationView : app:itemIconTint="@drawable/navi_selector"

아이콘 색상을 지정해주는 옵션이다. '@color/mainBlue'나 '#000000' 등 색상으로 지정해주면 전체 색상이 바뀌고, 눌렸을 때와 눌리지 않았을 때 색상을 지정해주고 싶을 경우 drawable 폴더에 selector를 만들어준다. (04에서 생성)


- BottomNavigationView : app:layout_behavior="tech.thdev.app.view.BottomNavigationBehavior"

스크롤시 하단으로 숨기게 하는 라이브러리이다. 

 

[res] - [layout] - act_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">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

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

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

        </FrameLayout>

        <com.google.android.material.bottomnavigation.BottomNavigationView
            android:id="@+id/navi"
            android:layout_width="match_parent"
            android:layout_height="@dimen/naviH"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/fl_container"
            android:background="@color/white"
            app:menu="@menu/navi_menu"
            app:labelVisibilityMode="unlabeled"
            app:itemIconTint="@drawable/navi_selector"
            app:layout_behavior="tech.thdev.app.view.BottomNavigationBehavior" />
    </androidx.constraintlayout.widget.ConstraintLayout>

</layout>

 

04. seletor 사용하여 아이콘 색상 변경 (itemIconTint)

아이콘이 선택됐을 때와 선택되지 않았을 때 원하는 색상을 지정해주기 위해 selector를 만들어서 BottomNavigationView에 적용시킨다.

 

- item : android:color="@color/mainBlue"

state_checked=true인 항목이 Navigation에서 선택된 상태이다. @color/에서 원하는 색상을 불러오거나 '#000000'과 같이 hex 색상을 직접 입력해줄 수 있다. 

 

 

[res]- [drawable] - navi_selector.xml

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

 

05. 내비게이션 그래프 생성

내비게이션 그래프는 모든 탐색 관련 정보가 하나의 중심 위치에 모여 있는 XML 리소스이다. 여기에는 대상이라고 부르는 앱 내의 모든 개별적 콘텐츠 영역과 사용자가 앱에서 갈 수 있는 모든 이용 가능한 경로가 포함된다.

 

res폴더 내에 navigation 폴더를 만들고, navi_graph.xml 파일 생성

 

- navigation app:startDestination="@id/fragHome"

기본 화면(처음 뜨는 화면, 돌아오는 화면)을 지정해줍니다. 원하는 fragment 아이디를 써주면 된다.

- fragment : android:id="@+id/fragHome"

이 아이디는 이후에 만들 menu의 item 아이디와 동일해야 한다.
- fragment : android:name="com.app0.simforpay.HomeFrag"

java 폴더 내의 kotlin 파일의 이름을 넣어준다. com.app0.simforpay는 자신의 프로젝트명이고, HomeFrag는 kotlin 파일명이다.
- fragment : tools:layout="@layout/frag_home"

각 fragment에 XML 파일을 연결시켜 layout을 지정해준다.

 

[res] - [navigation] - navi_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"
    app:startDestination="@id/fragHome">

    <fragment
        android:id="@+id/fragHome"
        android:name="com.app0.simforpay.HomeFrag"
        tools:layout="@layout/frag_home" />

    <fragment
        android:id="@+id/fragCalendar"
        android:name="com.app0.simforpay.CalendarFrag"
        tools:layout="@layout/frag_calendar" />

    <fragment
        android:id="@+id/fragContract"
        android:name="com.app0.simforpay.ContractFrag"
        tools:layout="@layout/frag_contract" />

    <fragment
        android:id="@+id/fragFriends"
        android:name="com.app0.simforpay.FriendsFrag"
        tools:layout="@layout/frag_friends" />

    <fragment
        android:id="@+id/fragSetting"
        android:name="com.app0.simforpay.SettingFrag"
        tools:layout="@layout/frag_setting" />
</navigation>

 

Design으로 변경하면 Navigation 이동 관계를 UI로 설정할 수 있으며 레이아웃 구조를 한 눈에 파악하기도 쉽다.

 

06. menu 생성

 

res폴더 내에 menu 폴더를 만들고, menu.xml 파일 생성

 

- item : android:id="@+id/fragHome"

전에 만든 내비게이션 그래프의 fragment 아이디와 동일해야 한다.

- item : android:icon="@drawable/ic_tab_home"

원하는 아이콘 파일을 불러온다.

- item : android:title="홈"

아이콘 밑에 표시될 레이블을 지정해준다.

 

[res] - [menu] - menu.xml

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

    <item
        android:id="@+id/fragHome"
        android:icon="@drawable/ic_tab_home"
        android:title="홈" />

    <item
        android:id="@+id/fragCalendar"
        android:icon="@drawable/ic_tab_calendar"
        android:title="달력" />

    <item
        android:id="@+id/fragContract"
        android:icon="@drawable/ic_add"
        android:title="작성" />

    <item
        android:id="@+id/fragFriends"
        android:icon="@drawable/ic_tab_friends"
        android:title="친구" />

    <item
        android:id="@+id/fragSetting"
        android:icon="@drawable/ic_tab_setting"
        android:title="설정" />

</menu>

 

menu.xml Design 화면

 

07. MainAct 작성

act_main과 연결된 MainAct.kt 파일에 코틀린 코드를 작성한다. 

※private lateinit var binding: ActMainBinding 빠트리지 않도록 주의해야 한다.

 

- initNavigation() : NavigationUI.setupWithNavController(①, findNavController(R.id.②))

① act_main.xml의 BottomNavigationView 아이디

act_main.xml의 fragment 아이디

 

- initBinding() : binding = DataBindingUtil.setContentView(this, R.layout.③)

③ MainAct와 연결 할 XML 파일 : act_main.xml

 

[java] - MainAct.kt

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.databinding.DataBindingUtil
import androidx.navigation.findNavController
import androidx.navigation.ui.NavigationUI
import com.app0.simforpay.databinding.ActMainBinding
import kotlinx.android.synthetic.main.act_main.*

class MainAct : AppCompatActivity() {
    private lateinit var binding: ActMainBinding

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

        initBinding()
        initNavigation()
    }

    private fun initNavigation() {
        NavigationUI.setupWithNavController(navi, findNavController(R.id.navi_host))
    }

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

완성

BottomNavigationView 완성된 모습

 

 

 

본 작성자는 안드로이드 개발을 공부하고 있는 학생으로 피드백 및 질문을 환영합니다. 그러나 무단복제 및 배포는 정중하게 사양하고 있으며, 참고 사이트로 링크를 남기실 때는 동의를 구해주시기 바랍니다.

반응형