안드로이드에서 Navigation 사용하는 방법!
프로젝트 시작할때 항상 하는 일인데 매번 해도 헷갈리고 그래서 문서로 남겨놓아야겠다.
안드로이드 스튜디오에서 프로젝트를 만들고 구조를 살펴보면, 빌드 관련 사항들이 Gradle Scripts 에 모여있다.
여기서 주로 사용하는 것들은 build.gradle 인데, 헷갈리게 이름 똑같은 애가 2개 있다.
첫번째 build.gradle 은 Project 수준의 gradle 이고
두번째 build.gradle 은 Module(앱) 수준의 gradle 이다.
<Project 의 build.gradle>
buildscript {
ext.kotlin_version = "1.5.31"
ext.nav_version = "2.3.5"
repositories {
google()
mavenCentral()
}
dependencies {
classpath "com.android.tools.build:gradle:7.0.3"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.31"
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
맨 위의 두줄은 dependency 설정할 때 필요한 버전을 변수로 만들어버렸다.
새로 업데이트되어도 변수만 바꿔주면 되니까 아주 편함!
project 의 builde.gradle 에 선언해도, module 의 build.gradle 에서도 사용할 수 있다.
navigation 에서 인자 전달할 때 쓰는 safe-arg 도 우선 추가해놓았다.
<Module 의 build.gradle>
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'androidx.navigation.safeargs.kotlin'
}
safe-arg 관련된 플러그인을 추가하고
buildFeatures {
dataBinding true
viewBinding true
}
android{
}
이렇게 돼있는 부분에 buildFeatures 부분을 추가하면 dataBinding 을 사용할 수 있다.(navigation 과 상관없지만 나는 이것도 같이 사용할거라 추가함!)
dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
// navigation
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
}
dependency 에 navigation-fragment , navigation-ui 들을 추가했다. (밑에 두줄)
요기서 $변수명 으로 버전을 쓰면 아까 선언했던 변수를 가져올 수 있다!
res/layout 폴더에 xml 파일을 생성한다.
intro_fragment.xml 과 main_fragment.xml 을 생성해주었다.
intro_fragment.xml
main_fragment.xml
intro_fragment 에서 터치 -> main_fragment 전환 하도록 만들어보려고 한다.
xml 만 띡 만든다고 화면에 띄워지는게 아니다!
activity 화면 만들고 코틀린 파일 작성했듯이, fragment 화면 만들고 파일에 연결해줘야한다.
class IntroFragment : Fragment() {
private lateinit var binding: IntroFragmentBinding
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
binding = IntroFragmentBinding.inflate(inflater, container, false)
return binding.root
}
}
Fragment 에서 뷰를 결합해준다.
⭐️ 데이터 바인딩을 사용하려면, xml 작성할 때 가장 바깥을 <layout>
태그로 감싸줘야한다!! ⭐️
그래야 결합할때 IntroFragmentBinding 같이 xml 파일이름 + Binding
형식의 클래스가 만들어진다.
res 폴더에 디렉토리를 생성하고 이름을 navigation 으로 설정한다!
navigation 디렉토리 안에 navigation 파일(navigation graph) 을 만들어준다.
이 파일의 이름은 상관 없는데, 디렉토리 이름은 꼭 navigation 이어야함!
Navigation Graph 는 말 그대로 fragment가 어떤 fragment 로 전환되고 이동해야하는지 길을 알려주는 지도인 셈이다.
<fragment
android:id="@+id/introFragment"
android:name="com.example.navigationStudy.scene.IntroFragment"
android:label="IntroFragment"
tools:layout="@layout/intro_fragment" />
<fragment>
태그로 fragment 를 추가할 수 있다. id, label 은 원하는 대로 지으면 되고 name 은 아까 생성한 코틀린 파일과 연결짓는 속성이다.
tools:layout 속성으로 xml 파일을 적어주면
아까 생성한 xml 파일이 나타난다!
화면이 몇 개 없을 때는 굳이 없어도 되지만, 화면이 많아질수록 헷갈리기 때문에 난 항상 추가해놓는 편이다.
화살표로 표시하기 때문에 아주 직관적이다.
어떤 화면에서 출발해서 어디로 가는지 눈에 잘 들어옴
이거 설정 안하면 앱이 죽는다 (아마도....)
맨-처음에 프로젝트 생성 시에 자동으로 추가되는 activity_main.xml 로 돌아온다!
navigation graph 를 여기에 넣어줘야한당.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.fragment.app.FragmentContainerView 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/navHost"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/main_navigation"
tools:context=".MainActivity"></androidx.fragment.app.FragmentContainerView>
FragmentContainerView 는 Fragment 를 위해 customized 된 레이아웃인데, Fragment 전환을 안정적으로 처리할 수 있다는 장점이 있다.
속성을 살펴보면,
app:navGraph
가 아까 만들어놓은 navigation graph 를 설정하는 부분이다.
intro_fragment.xml 에서 main_fragment.xml 로 이동하게 할 예정!
intro_fragment.xml
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val action: NavDirections = IntroFragmentDirections.actionIntroFragmentToMainFragment()
binding.root.setOnClickListener {
view.findNavController().navigate(action)
}
}
이 함수는 처음에 만든 함수랑 다르다! onViewCreate() 임.. 헷갈리지 말자!
아무튼, navigation graph 에서 intro -> main 으로 방향을 설정했는데,
val action: NavDirections = IntroFragmentDirections.actionIntroFragmentToMainFragment()
여기가 방향을 가져오는 부분이다.
intro 화면에서 아무데나 누르면 이동하도록, 클릭리스너 안에서
view.findNavController().navigate(action)
해당 화살표 방향으로 이동하도록 해줌!
‼️결과는 다음과 같다.
귀여운 춘식이가 짠-!
기염둥이 춘식이는 프렌즈샵에서 주어옴 큐티 ㅠ.ㅠ
여기! 에서 확인 가능합니당.
velog 에서는 아직 이미지 크기 조절이 안되나보다. 미리보기에선 적용되는데 작성하고 나면 겁나 큼 😭