이건 또 왜 번역 '탐색'일까
차라리 '네비' 그 자동차 '네비' 개념이 더 와닿겠어...ㅠㅠ
제발 destination을 '대상'이라고 표시하지마요
님아 Actions
을 '작업'이라고 표시하지마요
읽는 내내 너무 헷갈려...ㅠㅠ
|
Navigation이란?
- "여러 Fragment 들을 포함한 하나의 Activity가 있는 앱"을 위해 설계됨
ㄴ> Fragment (<< Navigation의 'destination')을 교체하여 화면이동한다.
- Activity은 Navigation 'graph'와 연결됨
- Activity는 Fragment을 교체해야 하는 NavHostFragment를 포함함.
- CASE) 여러 Activity들이 있는 앱이라면 -> 각 Activity별로 자체 NavigationGraph가 있다.
Safe Args 란?
- 화면 navigate를 위해 Safe Args Gradle 플러그인을 사용하는 것이 좋다. (매우 좋더라)
- 화면이동 destiation 간 유형 안전한 이동 및 인수 전달을 사용 설정하는 간단한 객체 및 빌더 클래스를 생성해준다.
- 각 action마다 action이 탐색을 시작하는 destination인 각 발신 [ Directions 클래스]를 생성함
생성된 입니다.
- [ Directions 클래스 ]
: Safe Args 추가 시 요소의 id 속성을 기반으로 생성되는 클래스
- 클래스 이름은 발신 '{destination 클래스 이름}Directions'
ㄴ > ex1) android:id=@+id/main_nav 값이 있는 <navigation> 요소가 있다면, Directions클래스 이름은 MainNavDirections
ㄴ > ex2) destination의 이름이 SpecifyAmountFragment라면 생성된 클래스의 이름은 SpecifyAmountFragmentDirections
- 생성된 클래스에는 발신 destination에서 정의한 각 action의 정적 메서드가 포함됨.
이 메서드는
ㄴ> @param : 정의된 action 매개변수
ㄴ> @return : navigate()에 전달할 수 있는 NavDirections 객체를 반환하여 화면 이동 시 사용할 수 있다.
- [ 프로젝트에 Safe Args를 추가하기 ]
1) 최상위 build.gradle 파일에 다음의 classpath를 포함
buildscript {
repositories {
google()
}
dependencies {
val nav_version = "2.5.3"
classpath("androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version")
}
}
2) 앱 또는 모듈의 build.gradle 파일에 다음 행을 추가
ㄴ> 2-1) 자바 모듈 또는 자바와 Kotlin 혼합 모듈에 적합한 자바 언어 코드를 생성하려면
plugins {
id("androidx.navigation.safeargs")
}
ㄴ> 2-2) Kotlin 전용 모듈에 적합한 Kotlin 코드를 생성하려면 다음을 추가하세요.
plugins {
id("androidx.navigation.safeargs.kotlin")
}
3) gradle.properties 파일에 android.useAndroidX=true가 있어야 함
[Navigation 구성]
1. Navigation Graph
: Navigation 관련 정보를 볼 수 있는 XML리소스 파일
- 앱의 모든 탐색 (화면 이동) 경로를 보여준다.
- "Navigation Graph는 사용자가 이동할 수 있는 이 NavHostFragment의 모든 destination을 지정한다."
- 주로 res/navigation 폴더에 xml파일로 존재 (루트가 <navigation>태그로 시작)
<?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"
android:id="@+id/nav_graph">
</navigation>
- 이 xml에서 스토리보드처럼 모든 플로우를 보여주고 앱내의 Fragment를 한눈에 확인가능 (아래 이미지처럼)
[ NavigationGraph 화면 구성 ]
ㄴ> destination(=대상 ≈화면) : 앱의 다양한 콘텐츠 영역(화면)
ㄴ> Action (=작업, 화살표로 표시됨): 한 대상에서 다른 대상으로 이동할 수 있는 방법을 "화살표로 표시" (=> 사용자가 택할 수 있는 경로를 나타내는 대상 간의 논리적 연결)
[ NavigationGraph 추가하기 ]
- res에서 마우스 오른쪽 버튼으로 클 > New > Android Resource File을 선택 > New Resource File 대화상자
- File name 필드에 'nav_graph'와 같은 파일 이름을 입력
- Resource type 드롭다운 목록에서 Navigation을 선택한 후 OK를 클릭하면 끝
1 - A) destination
[ destination의 구성 ]
대상을 클릭하여 선택하고 Attributes 패널에서 다음 속성을 확인합니다.
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
app:startDestination="@id/blankFragment">
<fragment
android:id="@+id/blankFragment"
android:name="com.example.cashdog.cashdog.BlankFragment"
android:label="@string/label_blank"
tools:layout="@layout/fragment_blank" />
</navigation>
- 태그(ex : <fragment>) : 대destination이 소스 코드에서 프래그먼트, 활동 또는 기타 맞춤 클래스로 구현되는지 여부를 나타냄
- android:label 필드 : 사용자가 읽을 수 있는 destination 이름
- NavGraph를 setupWithNavController()를 사용하여 Toolbar에 연결한 경우와 같이 UI에 이 필드 값이 표시
- 값에 리소스 문자열을 사용하는 것이 좋다 - android:id 필드 : destination을 참조하는 데 사용되는 destinationID
- android:name 필드 : destination과 연결된 클래스의 이름이 표시
[ Start destination이란? ]
: (NavigationGraph 가 지정된) Activity를 열 때 처음으로 표시되는 화면이며 사용자가 앱을 종료할 때 마지막으로 보게 되는 화면
- destination에 app:startDestination 필드에서 지정함
app:startDestination="@id/destinationID"
2 - B) action
: destination 간의 논리적 연결
- 일반적으로 한 destination을 다른 destination에 연결함. (=사용자가 앱에서 선택할 수 있는 다양한 경로를 표시)
- NavigationGraph 에서 화살표로 표시함
Global Action
: "어디서든 특정 destination으로 이동할 수 있는 action"
- [ Global Action 사용하기 ]
: 화면 이동 시 navigate() 메서드의 파라미터로
ㄴ> (1) 'Global Action ID값' 전달
viewTransactionButton.setOnClickListener { view ->
view.findNavController().navigate(R.id.action_global_mainFragment)
}
ㄴ> (2) Safe Args 사용 시에는 -> 'NavDirections 객체'를 전달
: Directions 클래스의 'Global Action'메소드를 호출하면 -> 'NavDirections'객체를 전달받을 수 있다.
ㄴ> ex)
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_nav"
app:startDestination="@id/mainFragment">
<fragment
android:id="@+id/mainFragment"
... >
<argument
android:name="safeArgs1명"
app:argType="safeArgs1데이터타입" />
</fragment>
<action
android:id="@+id/action_global_mainFragment"
app:destination="@id/mainFragment"/>
...
</navigation>
위와 같은 경우에는 아래와 같이 navigate 사용
viewTransactionButton.setOnClickListener { view ->
view.findNavController().navigate(
MainNavDirections.actionGlobalMainFragment(safeArgs1값)
)
}
- [ Global Action 만들기 ]
- Graph Editor에서 대상을 클릭하여 강조표시합니다.
- 대상을 마우스 오른쪽 버튼으로 클릭하여 컨텍스트 메뉴를 표시합니다.
- Add Action > Global을 선택합니다. 화살표(->)가 대상의 왼쪽에 나타납니다.
- Text 탭을 클릭하여 XML 텍스트 뷰로 이동합니다. 전역 작업의 XML은 다음과 유사합니다.
2. NavHost
: Navigation Graph에서 destination을 표시하는 빈 컨테이너
( = NavController를 통한 Navigation을 위한 single Context 또는 컨테이너)
- "사용자가 앱을 탐색(navigate)하는 동안 NavHost서 destination이 교체된다"
- NavHost로 사용하려면 'interface NavHost'에서 파생되어야 한다.
ㄴ> NavHost 구현한 "NavHostFragment" 써서 destination의 교체를 처리
ㄴ>
public interface NavHost ㄴ> Known direct subclasses : NavHostFragment
ㄴ> Known indirect subclasses: DynamicNavHostFragment
|
- 하나의 NavHost만 기본값으로 지정가능
ㄴ> 동일한 레이아웃에 여러 호스트가 있는 ( ex 창이 2개인 레이아웃라고 하는데 뭔지 모르겠다 등) 경우도호스트만 기본 NavHost로 지정해야 합니다.
[ Activity에 NavHost 추가하기 ]
Ex) Activity의 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=".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" />
<com.google.android.material.bottomnavigation.BottomNavigationView
.../>
</androidx.constraintlayout.widget.ConstraintLayout>
ㄴ>
- android:name 속성 : NavHost구현의 클래스 이름
(android:name = "androidx.navigation.fragment.NavHostFragment") - app:navGraph 속성 : NavHostFragment를 NavigationGraph와 연결
- app:defaultNavHost="true" 속성을 사용하면 NavHostFragment가 시스템 뒤로 버튼을 가로챈다.
[ NavHost의 역할 ]
- NavController상태를 저장 및 복원
- 루트 뷰에서 Navigation.setViewNavController를 호출
- NavController.popBackStack을 수동으로 호출하거나 NavController를 구성할 때 -> NavHostController.setOnBackPressedDispatcher를 호출하여 시스템 뒤로 버튼 이벤트를 NavController로 라우팅함.
[ NavHost의 선택적 고려사항 ]
- <특정 Lifecycle 주기와 연결하기>
: NavHostController.setLifecycleOwner를 호출
- <NavController.getViewModelStoreOwner 및 NavigationGraph 범위에서 ViewModel을 사용하기 >
: NavHostController.setViewModelStore를 호출
3. NavController
: NavHost에서 App의 Navigation을 관리하는 객체
- 사용자가 앱 내에서 이동할 때 "NavHost에서 destination 콘텐츠의 전환을 조종하는 역할"
- NavController직접 노출되지 않고 외부에서 로만 액세스할 수 있어야 함
[ destination으로 이동 (=코드에서 화면 이동시키기)]
: [NavController객체를 가져와] 메소드 호출하여 이동함
+) NavController객체는 NavHost 내에서 앱 탐색을 관리 & 각 NavHost에는 해당하는 자체 NavController가 존재
ㄴ> [ (컴포넌트별) NavController 객체를 가져오는 방법 ]
1) Fragment에서 findNavController() 메소스 호출
2) View에서 findNavController() 메소스 호출
3-1) Activity에서 findNavController(viewId: Int) 메소스 호출
3-2) Activity에서 (1)FragmentContainerView를 사용하여 NavHostFragment를 만들 때나
(2) FragmentTransaction을 통해 NavHostFragment를 Activity에 수동으로 추가하는 경우, NavHostFragment에서 직접 NavController를 검색해야 한다. ex↓
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
※ 주의 : 3-2)에서 Navigation.findNavController(Activity, @IdRes int)를 통해 Activity의 onCreate()에서 NavController를 검색하려고 하면 실패함
[출처]
- [공식] https://developer.android.com/guide/navigation/navigation-getting-started?hl=ko
- https://jae-young.tistory.com/46