Fragment Navigation 이란?
Android Jetpack의 Navigation Component를 사용하여 페이지 이동을 쉽게 구현하게 해주는 방법이다.
* 공식 문서 *
https://developer.android.com/guide/navigation/navigation-getting-started
1. Navigation 구성요소
- Navigation Graph : 모든 Navigation 관련 정보가 하나의 중심 위치에 모여 있는 XML 리소스입니다. 단순히 말해 사용자가 앱에서 갈 수 있는 모든 플로우를 보여주고 앱 내의 Fragment를 한눈에 확인할 수 있습니다.
- NavHost : Navigation Graph에서 대상을 표시하는 빈 컨테이너입니다. 대상 구성요소에는 프래그먼트 대상을 표시하는 기본 NavHost 구현인 NavHostFragment가 포함됩니다.
- NavController : NavHost에서 App Navigation을 관리하는 객체입니다. NavController는 사용자가 앱 내에서 이동할 때 NavHost에서 대상 콘텐츠의 전환을 조종하는 역할을 합니다.
Navigation Graph에서 특정 경로를 따라 이동할지, 특정 대상으로 직접 이동할지 NavController에게 전달하고 NavController가 NavHost에 적절한 대상을 표시해주는 방식입니다.
2. 장점
- 프래그먼트의 트렌젝션 처리.
- 올바르게 Up과 Back동작을 처리.
- 화면 전환에 대한 표준화된 애니메이션 리소스.
- 딥 링크 구현 및 처리를 쉽게 할 수 있다.
- Bottom Navigation과 같은 요소들을 최소한의 추가 작업으로 구현.
- Safe Args - 대상 사이에서 데이터를 탐색하고 전달할 때 안정성을 제공하는 Graph 플러그인.
- ViewModel - Navigation Graph에 대한 ViewModel을 확인해 그래프 대상 사이에 UI 관련 데이터를 공유.
3. 사용 방법
3-1) 라이브러리 설치
( build.gradle(Module: 프로젝트명.app) )
dependencies {
def nav_version = "2.3.5"
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
}
- Sync Now를 눌러 적용
3-2) navigtion 폴더 생성
- 경로 : res폴더 우클릭 → New → AndroidResource Direcroty 클릭 → navigation 폴더 생성
3-3) navigation 파일 생성
- 경로 : navigtion폴더 우클릭 → New → Navigtion resource file 클릭 → navigation 파일 생성
- 파일을 생성하게 되면 GUI 적으로 한눈에 알아볼 수 있게 이미지로 나타낸다.
3-4) Fragment 생성
- fragment 폴더 생성 후 내부에 fragment 파일 생성
- fragment 파일 생성 : fregment폴더 우클릭 → New → Fragment → Fragment(Blank) 클릭 - fragment 이름 설정 시 Layout Name 자동 변경
- layout 자동 생성
3-5) Fragment Layout
<?xml version="1.0" encoding="utf-8"?>
<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_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph"/>
</androidx.constraintlayout.widget.ConstraintLayout>
- tools:context= ".MainActivity" : 지정해야 navigation 파일에서 등록할 수 있다( .MainActivity 액티비티 연결)
3-6) Fragment 관계 정리(화면 이동)
- 이전 3-3)에서 만들었던 navigation 파일에서 관계 설정을 한다.
navigtion → nav_graph.xml 클릭 → Design 클릭 - 집 모양을 눌러 메인 화면 설정 가능
- 화살표를 드래그하여 관계 설정을 적용한다.
3-7) Activity Layout에 Fragment Navigation 적용
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
........>
<fragment
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>
- 경로 : res → layout → 적용 액티비티 ( activity_main.xml )
- app:navGraph="@navigation/nav_graph : 이전 3-3)에서 만들어 두었던 navigtion 파일 적용
- activity layout은 단순히 fragment를 담아두는 틀 역할을 한다.
- fragment 태그 안의 속성 값은 고정 값으로 복붙!
3-8) Activity에 Navigation Controller 생성
class MainActivity : AppCompatActivity() {
//네비게이션 컨트롤러
lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// main Activity에서 선언된 fragment id를 불러와 연결한다.
navController = nav_host_fragment.findNavController()
}
}
3-9) Fragment 화면 전환 방법 (1)
( MainFragment.kt )
class MainFragment : Fragment() {
// onViewCreated에서 사용할거기 때문에 lateinit 선언
lateinit var navController: NavController
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_main, container, false)
}
// onViewCreated : 뷰를 그리고 나서 실행
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
navController = Navigation.findNavController(view)
// id클릭시 네비게이션 이동
btn_storage.setOnClickListener {
navController.navigate(R.id.action_mainFragment_to_boxFragment)
}
}
}
- navigate : 인자 입력 시 main 까지만 쓰면 위에서 관계 설정한 fragment들이 나타난다.
3-10) Fragment 화면 전환 (2) 인터페이스 활용
여러 페이지 전환 시 인터페이스 방식 사용
class SelectionFragment : Fragment(),View.OnClickListener {
//lateinit -> 나중에 정의
lateinit var navController: NavController //네비게이션 컨트롤러
...
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
//뷰를 그리고 나서 실행
super.onViewCreated(view, savedInstanceState)
navController = Navigation.findNavController(view)
btn_back.setOnClickListener(this)
option_1.setOnClickListener(this)
option_2.setOnClickListener(this)
option_3.setOnClickListener(this)
option_4.setOnClickListener(this)
// 인터페이스 없이 바로 사용도 가능한 이벤트
//btn_home.setOnClickListener{
// navController.navigate(R.id.action_resultFragment_to_mainFragment)
// }
}
override fun onClick(v: View?) {
when(v?.id){
R.id.option_1 -> {navigationWithIndex(1)}
R.id.option_2 -> {navigationWithIndex(2)}
R.id.option_3 -> {navigationWithIndex(3)}
R.id.option_4 -> {navigationWithIndex(4)}
R.id.btn_back -> {
navController.popBackStack()
}
}
}
fun navigationWithIndex(index : Int){
//fargment에 데이터를 bundle로 보낸다.
val bundle = bundleOf("index" to index) //key to value
//action_selectionFragment_to_resultFragment 로 이동
navController.navigate(R.id.action_selectionFragment_to_resultFragment, bundle)
}
}
- View.OnClickListener 인터페이스 상속받아 모든 버튼에 대한 이벤트 줄 수 있다.
- action_selectionFragment_to_resultFragment : selectionFragment에서 클릭하게 되면 resultFragment로 이동한다는 의미
- bundle : key, value 값으로 데이터를 넘긴다.
3-11) bundle 데이터 받기 예제
//데이터 받기
class ResultFragment : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
var option = -1
lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
option = arguments?.getInt("index")?:-1
return inflater.inflate(R.layout.fragment_result, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
navController = Navigation.findNavController(view)
setResult(option)
btn_home.setOnClickListener{
navController.navigate(R.id.action_resultFragment_to_mainFragment)
}
}
fun setResult(option:Int){
when(option){
1 -> {
tv_main.text = "You are a QUITTER!"
tv_sub.text ="You can let the person easily."
}
2 -> {
tv_main.text="You should focus on yourself"
tv_sub.text="You become really clingy to your ex."
}
3-> {
tv_main.text="You should take it easy"
tv_sub.text="You can do crazy things no matter what it takes."
}
4-> {
tv_main.text="You are pretty mature."
tv_sub.text="You can easily accept the break-up."
}
}
}
companion object {
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment ResultFragment.
*/
// TODO: Rename and change types and number of parameters
@JvmStatic
fun newInstance(param1: String, param2: String) =
ResultFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
}
- option = arguments?.getInt("index")?:-1
- 이전 Fragment 화면에서 넘겨준 데이터 key 값으로 가져오기 - ?:
- 엘비스 연산자로 만약 null 이면 -1을 반환
반응형
'Kotlin' 카테고리의 다른 글
[Android] 앱 배포(1) 앱 번들(App Bundle) release 파일 생성 방법 (0) | 2022.11.09 |
---|---|
[Kotlin] Null 처리 방법(Nullable, NonNull) (0) | 2022.11.04 |
[Kotlin] RecyclerView 사용 방법 (0) | 2022.10.31 |
[Kotlin] Observer Pattern(옵저버 패턴) 사용 방법 (1) | 2022.10.05 |
[Android] 앱 런처(앱 아이콘, 앱 이름, 패키지 이름 변경 ) 사용 방법 (0) | 2022.10.04 |