ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [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 완성된 모습

     

     

     

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

    반응형

    댓글

Written by 나도개발자.