Jetpack은 Android 개발을 빠르게 도와주는 컴포넌트 라이브러리입니다.
2018 Google I/O 행사에서 Jetpack Navigation이 소개되었다고 하네요.
Android Studio 3.3버전부터 Navigation Editor 기능이 생기면서 Xcode처럼 UI를 통한 Navigation 편집이 가능해졌습니다.
그렇다면 Jetpack Navigation 사용방법에 대해서 알아보겠습니다.
Step 1. gradle에 Navigation관련 추가
//Jetpakc-Navigation : Kotlin
def nav_version = "2.3.5"
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
Step 2. Navigation 탐색 그래프 만들기
res폴더 우클릭 -> Android Resouce File -> File name, Resource type: Navigation으로 설정 후 생성 -> res 폴더안에 navigation 폴더가 생성된것을 확인
Step 3. fragment 생성
navigation생성한 파일을 Design보기로 변경하여 다음과 같이 버튼을 눌러 fragment를 생성합니다.
Step 4. MainActivity에 navigation을 보여줄 framgnet로 셋팅
<?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">
<androidx.fragment.app.FragmentContainerView
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>
<androidx.fragment.app.FragmentContainerView를 설정하여
app:navGraph설정 등을 해줍니다.
여기까지 왔으면 navigation과 fragment설정을 끝났으며 각 코드를 작성하여 프로그램을 만들어 줍니다.
전체코드
----------------------------------------------------------------------------------------------------------------------
//MainActivity.kt
package com.example.jetpack_navigation_kotlin
//MainActivity.kt
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- acitivity_main.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"
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>
//nav_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"
android:id="@+id/nav_graph"
app:startDestination="@id/fragment1">
<fragment
android:id="@+id/fragment1"
android:name="com.example.jetpack_navigation_kotlin.fragment1"
android:label="fragment1_fragment"
tools:layout="@layout/fragment1_fragment" >
<action
android:id="@+id/action_fragment1_to_fragment2"
app:destination="@id/fragment2" />
</fragment>
<fragment
android:id="@+id/fragment2"
android:name="com.example.jetpack_navigation_kotlin.fragment2"
android:label="fragment_fragment2"
tools:layout="@layout/fragment_fragment2" >
<action
android:id="@+id/action_fragment2_to_fragment1"
app:destination="@id/fragment1" />
</fragment>
</navigation>
//fragment1.kt
package com.example.jetpack_navigation_kotlin
import androidx.lifecycle.ViewModelProvider
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.navigation.fragment.findNavController
import com.example.jetpack_navigation_kotlin.databinding.Fragment1FragmentBinding
class fragment1 : Fragment() {
private var _binding: Fragment1FragmentBinding? = null
private val binding get() = _binding!!
// companion object {
// fun newInstance() = fragment1()
// }
private lateinit var viewModel: Fragment1ViewModel
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
_binding = Fragment1FragmentBinding.inflate(inflater, container, false)
findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<String>("return")?.observe(viewLifecycleOwner){
binding.tv1.text = "fragment1에서 받은 데이터 ${it}"
}
binding.tvMovefragment1.setOnClickListener {
//fragment2로 보낼 데이터 set
val bundle = Bundle()
bundle.putString("data", binding.et1.text.toString())
//fragment2로 이동
this.findNavController().navigate(R.id.fragment2, bundle)
}
return binding.root
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
//(테스트) Fragment - ViewModel 생성
viewModel = ViewModelProvider(this).get(Fragment1ViewModel::class.java)
}
}
//fragment1ViewModel.kt
package com.example.jetpack_navigation_kotlin
import androidx.lifecycle.ViewModel
class Fragment1ViewModel : ViewModel() {
// TODO: Implement the ViewModel
}
//fragment1_fragment.xml
<?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=".fragment1">
<EditText
android:id="@+id/et_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#00F0F0"
android:gravity="center"
android:hint="fragment2로 전달할 데이터를 입력하세요"
app:layout_constraintBottom_toTopOf="@+id/tv_movefragment1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<TextView
android:id="@+id/tv_movefragment1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#F0F0F0"
android:text="go to fragment2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#F0F0F0"
android:text="fargment2에서 받은 데이터"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_movefragment1"/>
</androidx.constraintlayout.widget.ConstraintLayout>
//fragment2.kt
package com.example.jetpack_navigation_kotlin
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.addCallback
import androidx.navigation.fragment.findNavController
import com.example.jetpack_navigation_kotlin.databinding.FragmentFragment2Binding
class fragment2 : Fragment() {
private var _binding: FragmentFragment2Binding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
_binding = FragmentFragment2Binding.inflate(inflater, container, false)
//fragment1에서 받은 데이터 출력
binding.tv2.text = arguments?.getString("data")
//뒤로가기 TextView 클릭 시
binding.tvMovefragment2.setOnClickListener {
goBack()
}
//뒤로가기 버튼 눌렀을때
requireActivity().onBackPressedDispatcher.addCallback{
goBack()
}
return binding.root
}
private fun goBack(){
//fragment1으로 보낼 데이터 set
val returnMsg = binding.et2.text.toString()
findNavController().apply {
previousBackStackEntry?.savedStateHandle?.set("return", returnMsg)
popBackStack()
}
// findNavController().previousBackStackEntry?.savedStateHandle?.set("return", returnMsg)
// findNavController().popBackStack()
}
}
//fragment_fragment2.xml
<?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=".fragment2">
<EditText
android:id="@+id/et_2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#00F0F0"
android:gravity="center"
android:hint="fragment1으로 전달할 데이터를 입력하세요"
app:layout_constraintBottom_toTopOf="@+id/tv_movefragment2"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<TextView
android:id="@+id/tv_movefragment2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#F0F0F0"
android:text="go to fragment1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#F0F0F0"
android:text="fargment2에서 받은 데이터"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_movefragment2"/>
</androidx.constraintlayout.widget.ConstraintLayout>
//build.gradle (:app)
plugins {
id 'com.android.application'
id 'kotlin-android'
}
android {
compileSdk 30
defaultConfig {
applicationId "com.example.jetpack_navigation_kotlin"
minSdk 21
targetSdk 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
//View, Data Binidng
buildFeatures {
viewBinding true
dataBinding true
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.6.0'
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
//Jetpakc-Navigation : Kotlin
def nav_version = "2.3.5"
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
}
'🖥 Programming > 📱 Android (Kotlin)' 카테고리의 다른 글
[Android][kotlin] switch 버튼 색상 색상 바꾸기(custom) / 토글버튼(Toggle Button) (0) | 2021.11.29 |
---|---|
[Android][kotlin] DecimalFormat / 숫자 천 단위 콤마, 소숫점 넣기 (0) | 2021.11.15 |
[Android][kotlin] android:adjustViewBounds="true" 안먹는 현상 (0) | 2021.11.11 |
[Android][kotlin] requireContext()와 getContext() (0) | 2021.11.10 |
[Android] This version of the Android Support plugin for IntelliJ IDEA (or Android Studio) cannot open this project, please retry with version 4.2 or newer. (0) | 2021.10.30 |
[Android][kotlin] MVVM 패턴공부 (0) | 2021.10.30 |
[Android][kotlin] DataBinding & LiveData 같이 사용하기 (0) | 2021.10.28 |
[Andorid][kotlin] Android JetPack 구성도 (0) | 2021.10.27 |