반응형
메뉴를 이동해도 이전에 보던 프래그먼트의 상태가 유지되도록 하단 네비바를 만드는 방법이다.
3개의 메뉴를 가진 네비게이션 바를 만들어보자
네비게이션 기능에 필요한 파일 총 4개 (네비 조작에 의해 바뀌는 화면fragment 제외)
navi_menu.xml : 네비게이션의 메뉴 구성
NaviActivity.kt : 네비게이션 항목 선택에 따라 띄울 화면(fragment)을 컨트롤
activity_navi.xml : NaviActivity.kt와 연결된 뷰
menu_selector_color.xml : 네비바의 선택된 항목과 선택되지 않은 항목의 색 구분하여 설정 가능
완성화면
코드부터 보자. 설명은 맨 아래에 있으니 참고
navi_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<!-- id값은 어떤 항목을 선택했는지 구분하기 위해 NaviActivity.kt에서 사용-->
<item
android:id="@+id/categoryFragment"
android:title="카테고리"
android:icon="@drawable/ic_category"/>
<item
android:id="@+id/homeFragment"
android:title="홈"
android:icon="@drawable/ic_home"/>
<item
android:id="@+id/myPageFragment"
android:title="마이페이지"
android:icon="@drawable/ic_mypage"/>
</menu>
activity_navi.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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=".NaviActivity"
android:orientation="vertical">
<FrameLayout
android:id="@+id/mainNaviFragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="9"/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/mainNavi"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="@menu/navi_menu"
app:itemBackground="@color/burgundy"
app:itemIconTint="@drawable/menu_selector_color"
app:itemTextColor="@drawable/menu_selector_color"
android:layout_weight="1"/>
</LinearLayout>
NaviActivity.kt
package com.example.navigationApp
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction
import com.example.navigationApp.category.CategoryFragment
import com.example.navigationApp.databinding.ActivityNaviBinding
private const val TAG_CATEGORY = "category_fragment"
private const val TAG_HOME = "home_fragment"
private const val TAG_MY_PAGE = "my_page_fragment"
class NaviActivity : AppCompatActivity() {
//뷰바인딩 사용
private lateinit var binding: ActivityNaviBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityNaviBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
//맨 처음 보여줄 프래그먼트 설정
setFragment(TAG_HOME, HomeFragment())
//네비 항목 클릭 시 프래그먼트 변경하는 함수 호출
// TODO : setOnNavigationItemSelectedListener가 deprecated되어서 대체했는데 setOnItemReselectedListener 는 뭐가 다른 거지?
binding.mainNavi.setOnItemSelectedListener { item->
when(item.itemId){
R.id.categoryFragment -> setFragment(TAG_CATEGORY, CategoryFragment())
R.id.homeFragment -> setFragment(TAG_HOME, HomeFragment())
R.id.myPageFragment -> setFragment(TAG_MY_PAGE, MyPageFragment())
}
true
}
/* //프래그먼트 설정
val resultFragmentId = intent.getIntExtra("selectFragmentId", 0)
binding.mainNavi.selectedItemId = resultFragmentId*/
}
//프래그먼트 컨트롤 함수
fun setFragment(tag: String, fragment: Fragment){
val manager: FragmentManager = supportFragmentManager
val ft: FragmentTransaction = manager.beginTransaction()
//트랜잭션에 tag로 전달된 fragment가 없을 경우 add
if(manager.findFragmentByTag(tag) == null){
ft.add(R.id.mainNaviFragmentContainer, fragment, tag)
}
//작업이 수월하도록 manager에 add되어있는 fragment들을 변수로 할당해둠
val category = manager.findFragmentByTag(TAG_CATEGORY)
val home = manager.findFragmentByTag(TAG_HOME)
val myPage = manager.findFragmentByTag(TAG_MY_PAGE)
//모든 프래그먼트 hide
if(category!=null){
ft.hide(category)
}
if(home!=null){
ft.hide(home)
}
if(myPage!=null){
ft.hide(myPage)
}
//선택한 항목에 따라 그에 맞는 프래그먼트만 show
if(tag == TAG_CATEGORY){
if(category!=null){
ft.show(category)
}
}
else if(tag == TAG_HOME){
if(home!=null){
ft.show(home)
}
}
else if(tag == TAG_MY_PAGE){
if(myPage!=null){
ft.show(myPage)
}
}
//마무리
ft.commitAllowingStateLoss()
//ft.commit()
}//seFragment함수 끝
}
menu_selector_color.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/dark_burgundy" android:state_checked="true"/>
<item android:color="@color/white" android:state_checked="false"/>
</selector>
과정 설명
중간중간 점 세개는 읽기좋게 여백 주고 싶어서 넣었다 큼직하게 세 덩어리로 보면 된다.
- res 폴더 안에 New > Directory > menu 디렉토리 생성.
- menu디렉토리 안에 New > Menu Resource File > navi_menu.xml 파일 생성 (menu폴더 안에 만들지 않고 그냥 res폴더 안에 만들고 싶으면 res안에 New > Android Resource File > Resource type : Menu 로 설정해 만듦)
- navi_menu.xml 파일 내용 작성 : 메뉴 목록, id(어떤 항목을 선택했는지 구분하기 위해 NaviActivity.kt에서 사용됨), 아이콘 등
- 네비게이션을 만들 액티비티 생성. NaviActivity.kt와 그에 연결된 뷰 activity_navi.xml
- activity_navi.xml 내용 작성 : 전체를 감싸는 레이아웃을 LinearLayout으로 함(꼭 그래야 하는 건 아님). 프래그먼트가 들어갈 FrameLayout과 BottomNavigation 뷰를 차례로 만들고 layout_weight값을 각각 9와 1로 줌(다른 비율을 원하면 조정). 각각 id값을 줌
- NaviActivity.kt 파일 내용 작성 : 각 프래그먼트를 의미할 TAG값을 만들어 사용. 네비메뉴 클릭 시 띄울 프래그먼트를 바꿔주는 함수 setFragment 생성. setFragment에서 네비 메뉴 선택 시 모든 컨트롤을 담당함 - FragmentManager와 FragmentTransaction을 생성하고 클릭된 메뉴 태그에 해당하는 fragment가 FragmentTransaction에 추가되어 있지 않을 경우 add함. 트랜잭션의 프래그먼트 객체를 모두 변수에 담음. 이 변수들을 이용해 프래그먼트들을 모두 hide한 후 선택된 프래그먼트만 show함
- menu_selector_color.xml 생성과 작성 : drawable폴더 안에 New > Drawable Resource File > Root element : selector로 네비바의 선택된 항목과 선택되지 않은 항목의 색 구분하여 설정 가능. 파일 만든 후 BottomNavigation 뷰에 itemIconTint와 itemTextColor속성값으로 넣어줌
끝
네비 만드는 법 까먹지 말자
참고
처음 프래그먼트 상태유지 서칭할 때 도움이 된 글
반응형
'Android > Kotlin' 카테고리의 다른 글
[Android/Kotlin] EditText 내용 비어있는지 빈 칸 확인하기 null check (0) | 2021.08.14 |
---|---|
[Android/Kotlin] 많이 쓰이는 홍보 배너 형태의 뷰 만들기 : ViewPager2 (1) | 2021.08.11 |
메모) RecyclerView GridLayout 아이템 간 간격, 크기 조정 (0) | 2021.08.08 |
[Android/Kotlin] RecyclerView등의 Adapter어댑터에서 액티비티 종료하기, setResult하기 (0) | 2021.07.29 |
[Android/Kotlin] 다른 액티비티 실행 후 결과 받아오기 startActivityForResult, setRestult, 구 onActivityResult (0) | 2021.07.19 |