안드로이드 Navigation 사용하기 (Kotlin)

Ddudduu·2021년 11월 4일

안드로이드에서 Navigation 사용하는 방법!
프로젝트 시작할때 항상 하는 일인데 매번 해도 헷갈리고 그래서 문서로 남겨놓아야겠다.

1. gradle 설정하기


안드로이드 스튜디오에서 프로젝트를 만들고 구조를 살펴보면, 빌드 관련 사항들이 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 들을 추가했다. (밑에 두줄)
요기서 $변수명 으로 버전을 쓰면 아까 선언했던 변수를 가져올 수 있다!

gradle 설정을 바꾼 다음엔 꼭 sync 를 해주자

2. 전환할 fragment 생성하기

res/layout 폴더에 xml 파일을 생성한다.
intro_fragment.xml 과 main_fragment.xml 을 생성해주었다.

intro_fragment.xml

main_fragment.xml

intro_fragment 에서 터치 -> main_fragment 전환 하도록 만들어보려고 한다.

3. 뷰 결합

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 형식의 클래스가 만들어진다.

4. Navigation Graph 생성하기

4-1. res/navigation 디렉토리 생성

res 폴더에 디렉토리를 생성하고 이름을 navigation 으로 설정한다!

navigation 디렉토리 안에 navigation 파일(navigation graph) 을 만들어준다.
이 파일의 이름은 상관 없는데, 디렉토리 이름은 꼭 navigation 이어야함!

4-2. Navigation Graph 생성

Navigation Graph 는 말 그대로 fragment가 어떤 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 파일이 나타난다!
화면이 몇 개 없을 때는 굳이 없어도 되지만, 화면이 많아질수록 헷갈리기 때문에 난 항상 추가해놓는 편이다.

  • Fragment 연결
    Fragment 를 추가했다면, 이제 Fragment 끼리 연결시켜줘야하는데 넘나 쉬움

    Fragment 를 클릭하면 저렇게 파란색 버튼이 뿅 생기는데
    저걸 잡고 원하는 Fragment 로 드래그한다.
그러면 화살표가 생김! Fragment 연결 완료!

화살표로 표시하기 때문에 아주 직관적이다.
어떤 화면에서 출발해서 어디로 가는지 눈에 잘 들어옴

  • startDestination 지정
    해당 Navigation Graph 의 시작점을 설정해주는 작업이다.
    지도 앱에서 출발점을 정하는 것과 똑같다!
원하는 Fragment 선택하고, 위의 메뉴 중에 집 모양 🏠을 누르면 설정 완료! (Fragment 이름 왼편에 집 표시가 생김)

이거 설정 안하면 앱이 죽는다 (아마도....)

5. Activity 에 navigation Graph 심어주기

맨-처음에 프로젝트 생성 시에 자동으로 추가되는 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 를 설정하는 부분이다.

6. 터치 -> Fragment 전환

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 에서는 아직 이미지 크기 조절이 안되나보다. 미리보기에선 적용되는데 작성하고 나면 겁나 큼 😭

profile
Android

0개의 댓글