sean.jin
Spark Code Blog
sean.jin
전체 방문자
오늘
어제
  • 분류 전체보기
    • 개발공부
      • Kotlin
      • LeetCode
      • Algorithm
      • React
    • 주식차트
    • 책리뷰
    • 유틸리티

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 주식입문자
  • 책
  • 주식책리뷰
  • 트리플 위칭데이
  • 책리뷰
  • 책추천
  • 자기개발
  • 쿼드러플위칭데이
  • 아빠와 딸의 주식투자 레슨
  • 네마녀의날
  • 변동성
  • 오
  • 초보
  • 부의 추월차선
  • 주식투자
  • 경제

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
sean.jin

Spark Code Blog

[Kotlin] 하단 내비게이션 개념 및 사용법 - BottomNavigationView, NavGraph, Fragment, FrameLayout - 뉴스앱 만들기 1편
개발공부/Kotlin

[Kotlin] 하단 내비게이션 개념 및 사용법 - BottomNavigationView, NavGraph, Fragment, FrameLayout - 뉴스앱 만들기 1편

2021. 6. 19. 15:39
반응형

이번 편에서는 NavigationView, NavGraph, Fragment, FrameLayout을 활용하여 하단에 내비게이션 뷰와 버튼 클릭 시  fragment가 바뀌는 방법을 다뤄보겠습니다.

 

개념

하단 내비게이션을 구현하기전 우리가 사용할 BottomNavigationView, NavGraph, Fragment, FrameLayout 역할들을 먼저 알아보겠습니다. 

 

BottomNavigationView

우리가 화면하단에 만들어줄 메뉴입니다. Activity_main에 구현후, 내비게이션에 들어갈 요소들을 menu에 넣어주겠습니다. 

NavGraph

우리가 화면전환이 이 루어지기 위해서 Intent를 많이 써왔지만 레이아웃이 복잡해질수록 intent만으로 레이아웃 간의 상호작용을 표현하는데 어려움이 있습니다. navigation graph는 프래그먼트 끼리 어떻게 연결돼있는지 확인하고 연결할 수 있습니다. 

fragment/frameLayout

내비게이션에 3개의 탭을 만들게 되는데 각 화면은 fragment로 구성하게 됩니다. 그리고 fragment들은 자신만에 layout이 있습니다. fragment를 쓰기 위해서는 frameLayout을 먼저 만들어줘야 합니다.

 

Dependencies추가 

먼저 필요한 dependencies들을 추가해주겠습니다. 

dependencies {
	implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
	implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'
}

 

Activity Main layout 만들어주기

activity_main 
<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=".ui.NewsActivity">

    <FrameLayout
        android:id="@+id/flFragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@+id/bottomNavigationView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">
        
        <fragment //하단navigation button이 눌릴떄마다 해당 fragment가 보여집니다.
            android:id="@+id/newsNavHostFragment" 
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:defaultNavHost= "true" //host를 defualt로 지정
            app:navGraph="@navigation/news_nav_graph"/> //navigation graph를 만들어줍니다. 

    </FrameLayout>

	//하단 내비게이션 바 생성
    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottomNavigationView"
        android:layout_width="match_parent"
        android:layout_height="56dp"
        app:menu="@menu/bottom_navigation_menu"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

1. FrameLayout안에 fragment를 넣어줍니다. 아래 bottom navigation View를 클릭할 때마다, fragment가 바뀝니다. 

 

2. fragment에 defaultNavHost를 true로 설정하면  activity에서의 뒤로 가기 버튼이 우리가 구현한 Navigation에 맞게 동작합니다. 

 

3. app:navGraph="@navigation/news_nav_graph"/> = NavGraph를 연결해 줍니다. Nav graph는 xml설정 완료 후 자세히 다뤄보겠습니다. 

 

4. app:menu="@menu/bottom_navigation_menu" = Bottom Navigation에 들어갈 menu를 넣어줍니다. 메뉴 만드는 법은 아래에서 다루겠습니다. 

 

내비게이션에 들어갈 Fragment Layout 만들기

먼저 이렇게 빈 코틀린 클래스와 레이아웃 파일들을 만들어줍니다.

bottom navigation메뉴는 3가지를 만들어 즐겁니(breakingNewsFragment/ savedNewsFragment/ SearchNewsFragment).

 

각 메뉴에 해당하는 3가지 프래그먼트와 각각의 layout을 만들어주어야 합니다. 

 

fragment에 들어갈 layout들을 먼저 만들어 주겠습니다. (아래 이미지는 이 강좌의 완성본입니다.)

breakingNews/savedNews/SearchNews

res/layout/fragment_breaking_news.xml 생성 
<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">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rvBreakingNews"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipToPadding="false"
        android:paddingBottom="50dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


    <ProgressBar
        android:id="@+id/paginationProgressBar"
        style="?attr/progressBarStyle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="invisible"
        android:background="@android:color/transparent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
res/layout/fragment_saved_news 생성
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rvSavedNews"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</FrameLayout>

 

res/layout/fragment_search_news 생성
<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">

    <EditText
        android:id="@+id/etSearch"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Search..."
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rvSearchNews"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:paddingBottom="50dp"
        android:clipToPadding="false"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/etSearch"
        tools:layout_editor_absoluteX="0dp" />

    <ProgressBar
        android:id="@+id/paginationProgressBar"
        style="?attr/progressBarStyle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="invisible"
        android:background="@android:color/transparent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

Fragment와 layout을 연결해주기

BreakingNewsFragment
class BreakingNewsFragment: Fragment(R.layout.fragment_breaking_news) {
}
SavedNewsFragment
class SavedNewsFragment: Fragment(R.layout.fragment_saved_news) {
}
SearchNewsFragment
class SearchNewsFragment: Fragment(R.layout.fragment_search_news) {
}

Navigation Graph/ NavGraph

각 프래그먼트에 모든 뷰를 연결해주었습니다. 이제 아까 다루기로 했던 navigation graph를 마무리해보겠습니다.

 

우리가 화면 전환이 이 루어지기 위해서 Intent를 많이 써왔지만 레이아웃이 복잡해질수록 intent만으로 레이아웃 간의 상호작용을 표현하는데 어려움이 있습니다. navigation graph는 프래그먼트 끼리 어떻게 연결돼있는지 확인하고 연결할 수 있습니다. 

 

먼저 새로운 navigation 리소스 파일을 만들어주겠습니다. 

 

1. res 폴더 아래에 새로운 리소스 파일을 만들어줍니다.

2. 리소스 타입은 navigaton입니다.

3. Navigation에서 designtab을 확인해보면 navHostFragment가 필요하다고 돼있습니다. 

4. mainActivity에 fragment를 navHost로 지정해줍니다. 추가 후 프로젝트를 껐다 다 시키면 추가됩니다. 

activity_main
<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">

    <FrameLayout
        android:id="@+id/flFragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@+id/bottomNavigationView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">
        <fragment
            android:id="@+id/newsNavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            //추가시작
            android:name="androidx.navigation.fragment.NavHostFragment"
            //추가끝
            app:defaultNavHost= "true"
            app:navGraph="@navigation/news_nav_graph"/>

    </FrameLayout>

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottomNavigationView"
        android:layout_width="match_parent"
        android:layout_height="56dp"
        app:menu="@menu/bottom_navigation_menu"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

5. navGraph를 연결하는 법을 다루기 전 뉴스들을 클릭했을 때, 프래그먼트 위에 웹뷰가 나와서 뉴스를 보이도록 하려 합니다. 그래서 webview로 이루어진 fragment를 만들어 보겠습니다 

fragment_article
<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">

    <WebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_favorite"
        app:fabSize="normal"
        android:layout_marginBottom="32dp"
        android:layout_marginEnd="32dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

ArticleFragment
class ArticleFragment: Fragment(R.layout.fragment_article) {
}

6. 이제 다시 res/navigation/news_nav_graph 디자인 탭으로 돌아갑니다. 그리고 우리가 사용하는 fragment들을 추가해줍니다. 

fragment를 navigation graph에 불러오는법 

7. 이제 fragment끼리 상호작용을 위해 서로 연결해주어야 합니다. 먼저 각 프래그먼트에서 뉴스를 클릭했을 때 webview가 들어간 article fragment가 나와 야하기 때문에 , breaking news, search news, saved news, 프래그 먼트들을, article fragment에 연결하겠습니다. 

갹 fragment를 연결해주는법

  • 드래그하여 article fragment로 연결해줍니다. 

자동 배열 기능

  • 위에 버튼을 누르면 자동으로 배열 가능합니다. 

  • start destination을 breaking News로 설정해줍니다. 위에 breakingNews fragment선택 후 집 모양을 눌러주세요.  앱이 처음 시작했을 때 보이는 fragment를 breakingNews로 설정됩니다. 

 

하단 내비게이션 메뉴 구성하기

activity_main에서 메뉴를 적어주었지만 만들어주지 않았는데요, 이제 만들어보겠습니다. 

res폴더 아래에 menu resource파일을 만들어줍니다. 

이름은 menu로 선택을 해줍니다.

아래와 같이 메뉴 구성을 하였습니다. 

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/breakingNewsFragment"
        android:title="BreakingNews"
        android:icon="@drawable/ic_launcher_background"/> //아이콘은 원하시는 아이콘으로 설정해주시면됩니다.
    <item android:id="@+id/savedNewsFragment"
        android:title="Saved News"
        android:icon="@drawable/ic_launcher_background"/>
    <item android:id="@+id/searchNewsFragment"
        android:title="Breaking News"
        android:icon="@drawable/ic_launcher_background"/>
</menu>

**메뉴 이름은 fragment의 파일 이름과 꼭 같아야합니다. **

MainActivity에 내비게이션 인스턴스화 하기

마지막으로 navigation을 mainactivity에 불러와주면 됩니다. 

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

        bottomNavigationView.setupWithNavController(newsNavHostFragment.findNavController())
    }
}

그리고 실행해보시면 아래와 같이 잘 작동되는 걸 보실 수 있습니다. 

 

반응형

'개발공부 > Kotlin' 카테고리의 다른 글

[Kotlin]Room Database 개념 및 사용법 - entity, DAO, database, Typeconverter 생성 - MVVM 뉴스앱 만들기 3편  (0) 2021.06.26
[Kotlin] 레트로핏 사용법 - Interface, retrofitInstance, constant만들기, GET의미, JSON To Kotlin 플러그인 - 뉴스앱 만들기 2편  (0) 2021.06.22
[Kotlin] LeetCode: Move Zeroes 이해하기 쉬운 코드, 간단한 답  (0) 2021.06.15
[Kotlin] 코루틴 Coroutine - async와 await, LifecycleScope과 ViewModelScope 사용법 및 사용예제- 4편  (0) 2021.06.14
[Kotlin] 코루틴 Coroutine 제어하기 -Join, repeat,cancel,withTimeout - 3편  (0) 2021.06.12
    '개발공부/Kotlin' 카테고리의 다른 글
    • [Kotlin]Room Database 개념 및 사용법 - entity, DAO, database, Typeconverter 생성 - MVVM 뉴스앱 만들기 3편
    • [Kotlin] 레트로핏 사용법 - Interface, retrofitInstance, constant만들기, GET의미, JSON To Kotlin 플러그인 - 뉴스앱 만들기 2편
    • [Kotlin] LeetCode: Move Zeroes 이해하기 쉬운 코드, 간단한 답
    • [Kotlin] 코루틴 Coroutine - async와 await, LifecycleScope과 ViewModelScope 사용법 및 사용예제- 4편
    sean.jin
    sean.jin
    앱개발, 알고리즘, JS, Kotlin, 미국 취업준비

    티스토리툴바