SW 공부노트

[안드로이드/Kotlin] Navigation (with 프래그먼트) 본문

안드로이드/안드로이드 공부

[안드로이드/Kotlin] Navigation (with 프래그먼트)

요빈 2023. 4. 12. 11:01

Navigation

build.gradle(Module)

plugins{
	...
	id 'androidx.navigation.safeargs.kotlin'
}
// Navigation
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"

 

build.gradle(Project)

buildscript{
    ext.nav_version = "2.5.3"
    dependencies {
        classpath 'com.android.tools.build:gradle:7.2.0'
        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
    }
}

1. navigation 파일 생성

  • res 폴더에서 navigation 디렉터리 생성 후 nav_graph 파일 생성
  • Design 탭에서 화면 생성 후 화살표로 이어 화면 간 이동 표시
    • list -> add(arg: labe_name)
    • list -> detail(arg: id, labe_name)
    • detail -> add(arg: id, labe_name)
  • 뒤로 가기 액션 설정
    • popUpTo: BackStack에서 어디까지 이동할 것인지 결정하는 속성
    • popUpToInclusive: popUpTo로 지정한 fragment까지 pop 할 것인지 정하는 속성
  • 화면 간 인수 설정: 인수를 받는 프래그먼트의 <argument> 태그 내 작성
    • 네비게이션에서 사용하는 데이터 클래스 인수는 Serialize 또는 Parcelize 처리가 되어있어야 한다.
<fragment
    android:id="@+id/detailFragment"
    android:name="com.example.toyproject1.ui.DetailFragment"
    android:label="fragment_detail"
    tools:layout="@layout/fragment_detail">
    <argument
        android:name="item"
        app:argType="com.example.toyproject1.network.Item"/>
</fragment>

2. activity_main에 FragmentContainerView 추가

  • id는 nav_host로 설정
  • name = "androidx.navigation.fragment.NavHostFragment"
  • navigation 관련 속성 설정
    • app:defaultNavHost = "true"
    • app:navGraph = "@navigation/nav_graph"
<androidx.fragment.app.FragmentContainerView
    android:id="@+id/nav_host"
    android:name="androidx.navigation.fragment.NavHostFragment"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:defaultNavHost = "true"
    app:navGraph = "@navigation/nav_graph"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

3. MainActivity에서 navigation 관련 설정

  • navController 변수 선언 및 지연초기화
  • navHostFragment(탐색 그래프의 대상) 초기화 -> FragmentContainer id 전달
  • 내비게이션바 설정 / 위로 작업 설정
class MainActivity : AppCompatActivity() {

    private var binding: ActivityMainBinding? = null
    private lateinit var navController: NavController

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host) as NavHostFragment
        navController = navHostFragment.navController

        setupActionBarWithNavController(navController)
    }

    override fun onSupportNavigateUp(): Boolean {
        return navController.navigateUp() || super.onSupportNavigateUp()
    }
}

에러 error inflating class androidx.fragment.app.fragmentcontainerview navigation

-> nav_graph 파일에 잘못된 코드가 있어서 inflate 오류 발생

4. 화면 이동 코드 작성

  • action 변수 사용

인수를 전달해야 하는 경우 action에 담아 전달

val action = MovieListFragmentDirections.actionMovieListFragmentToAddMovieFragment()
findNavController().navigate(action)
  • action 변수 미사용
findNavController().navigate(R.id.action_movieListFragment_to_addMovieFragment)

5. 인수받기(SafeArgs)

인수를 받아야 하는 UI 클래스에서 인수가 담긴 객체를 생성한다.

val args: MainFragmentArgs by navArgs()
println(args.id) // args의 속성 통해 인수 사용

* 내비게이션 장점

   - 프래그먼트의 트랜잭션 처리

   - '위로', '뒤로' 작업을 올바르게 처리

   - 애니메이션과 전환에 표준화된 리소스 제공

   - 딥 링크 구현 및 처리

   - Safe Args를 이용한 프래그먼트간 유형 안전성이 보장되는 데이터 전달 가능

   - ViewModel을 활용해 UI 사이 데이터 공유 가능

   +) 화면 별 라벨 지정 가능

 


내비게이션이나 뷰 바인딩 실습에 프래그먼트를 사용하면서 작업 순서 등이 헷갈려서 정리해보았다.  프래그먼트 사용 과정은 다음과 같으며, 뷰 바인딩, 내비게이션 관련 설정들도 함께 작성하였다.

 

1. 프래그먼트 파일(레이아웃 파일, 코틀린 클래스) 생성

 

2. 프래그먼트 코틀린 파일 설정

   - onCreateView() 메서드 내에서 레이아웃 inflate

   - 뷰 바인딩 사용할 경우 바인딩 변수 생성(null 허용 변수와 접근 가능 변수로 총 2개)

   - onDestroyView() 메서드에서 바인딩 클래스 인스턴스에 대한 참조를 정리해야 하므로

     null 허용 바인딩 변수에 null 값 넣어주기

 

3. Activity에 Fragment 띄우기

   - activity_main 파일에 FragmentContainerView 추가해 액티비티 내에 프래그먼트 띄우기

      -> 내비게이션 관련 속성(3개: name, defaultNavHost, navGraph) 지정

     +) FrameLayout도 가능

 

4. MainActivity 설정

   - 뷰 바인딩 사용할 경우 바인딩 설정 후 레이아웃 inflate

   - supportFragmentManager.beginTransaction().add(R.id.컨테이너 아이디, 프래그먼트 변수) 통해 프래그먼트 연결

      * 네비게이션을 사용할 경우, 따로 프래그먼트 연결해 줄 필요 없음 -> navController 설정이 필요하다면 여기에 작성

 

* 프래그먼트 트랜잭션은 프래그먼트를 추가, 삭제 및 교체하는 것을 뜻하지만, 프래그먼트 백 스택 관리, 프래그먼트 전환 애니메이션 등 다양한 일을 수행할 수 있다. 즉, 프래그먼트 내 구성요소들에 접근할 수 있게 해 준다. 이를 통해 액티비티에서 특정 이벤트가 발생했을 때, 프래그먼트에서 적절한 UI 동작을 할 수 있도록 구현해 준다.