본문 바로가기
프로그래밍

프래그먼트 안의 프래그먼트 네비게이션, 데이터 바인딩으로 더욱 깔끔하게!

by Kongkongpapa 2025. 3. 20.
728x90
반응형
SMALL

안드로이드 앱 개발에서 프래그먼트 네비게이션은 복잡한 UI를 관리하는 데 필수적인 도구입니다. 특히, 프래그먼트 안에 또 다른 프래그먼트 네비게이션을 구현해야 하는 경우, 코드가 복잡해지기 쉽습니다. 이럴 때 데이터 바인딩을 활용하면 코드를 훨씬 깔끔하고 효율적으로 관리할 수 있습니다. 이번 포스팅에서는 프래그먼트 안의 프래그먼트 네비게이션을 데이터 바인딩으로 구현하는 방법을 자세히 알아보겠습니다.

프래그먼트 안의 프래그먼트 네비게이션이란?

프래그먼트 안의 프래그먼트 네비게이션은 하나의 프래그먼트 내에서 여러 개의 하위 프래그먼트를 관리하고 전환하는 것을 의미합니다. 예를 들어, 탭 레이아웃이나 뷰페이저를 사용하여 여러 개의 하위 화면을 표시하는 경우에 유용합니다.

데이터 바인딩이란?

데이터 바인딩은 XML 레이아웃과 Kotlin 코드를 연결하여 뷰와 데이터를 자동으로 동기화하는 기술입니다. findViewById()를 사용하지 않고도 뷰에 직접 접근하고, 데이터 변경 시 자동으로 UI를 업데이트할 수 있어 코드의 가독성과 유지보수성을 높여줍니다.

데이터 바인딩 적용 방법

  1. build.gradle 설정: build.gradle (Module:app) 파일에 데이터 바인딩을 활성화합니다.
  2. Gradle
     
    android {
        // ...
        buildFeatures {
            dataBinding true
        }
    }
    
  3. 레이아웃 파일 수정: 레이아웃 파일을 <layout> 태그로 감싸고, <data> 태그를 추가하여 변수를 정의합니다.
  4. 프래그먼트 코드 수정: FragmentXXXBinding.inflate()를 사용하여 뷰 바인딩 객체를 생성하고, binding.root를 반환하도록 변경합니다. 뷰에 접근할 때 binding.뷰ID 형태로 접근합니다.

예시 코드

다음은 부모 프래그먼트(ParentFragment) 안에 두 개의 자식 프래그먼트(ChildFragment1, ChildFragment2)를 네비게이션으로 전환하는 예시 코드입니다.

1. 네비게이션 그래프 (nav_graph.xml)

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/childFragment1">

    <fragment
        android:id="@+id/childFragment1"
        android:name="com.example.fragmentnavigation.ChildFragment1"
        android:label="ChildFragment1"
        tools:layout="@layout/fragment_child1">
        <action
            android:id="@+id/action_childFragment1_to_childFragment2"
            app:destination="@id/childFragment2" />
    </fragment>

    <fragment
        android:id="@+id/childFragment2"
        android:name="com.example.fragmentnavigation.ChildFragment2"
        android:label="ChildFragment2"
        tools:layout="@layout/fragment_child2">
        <action
            android:id="@+id/action_childFragment2_to_childFragment1"
            app:destination="@id/childFragment1" />
    </fragment>
</navigation>

2. 부모 프래그먼트 (ParentFragment.kt)

Kotlin
 
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.NavHostFragment
import com.example.fragmentnavigation.databinding.FragmentParentBinding

class ParentFragment : Fragment() {

    private lateinit var binding: FragmentParentBinding

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentParentBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        val navHostFragment = childFragmentManager.findFragmentById(R.id.child_nav_host_fragment) as NavHostFragment
        val navController = navHostFragment.navController

        // 필요한 경우 navController를 사용하여 추가적인 네비게이션 설정 가능
    }
}

3. 자식 프래그먼트 1 (ChildFragment1.kt)

Kotlin
 
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import com.example.fragmentnavigation.databinding.FragmentChild1Binding

class ChildFragment1 : Fragment() {

    private lateinit var binding: FragmentChild1Binding

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentChild1Binding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        binding.buttonToChild2.setOnClickListener {
            findNavController().navigate(R.id.action_childFragment1_to_childFragment2)
        }
    }
}

4. 자식 프래그먼트 2 (ChildFragment2.kt)

Kotlin
 
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import com.example.fragmentnavigation.databinding.FragmentChild2Binding

class ChildFragment2 : Fragment() {

    private lateinit var binding: FragmentChild2Binding

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentChild2Binding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        binding.buttonToChild1.setOnClickListener {
            findNavController().navigate(R.id.action_childFragment2_to_childFragment1)
        }
    }
}

5. 부모 프래그먼트 레이아웃 (fragment_parent.xml)

XML
 
<?xml version="1.0" encoding="utf-8"?>
<layout 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">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".ParentFragment">

        <androidx.fragment.app.FragmentContainerView
            android:id="@+id/child_nav_host_fragment"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:defaultNavHost="true"
            app:navGraph="@navigation/nav_graph" />
    </FrameLayout>
</layout>

6. 자식 프래그먼트 레이아웃 (fragment_child1.xml, fragment_child2.xml)

XML
 
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:orientation="vertical">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Child Fragment 1" />

        <Button
            android:id="@+id/button_to_child2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Go to Child 2" />
    </LinearLayout>
</layout>

<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <LinearLayout
        android:layout_width
        android:layout_height="match_parent"
        android:gravity="center"
        android:orientation="vertical">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Child Fragment 2" />

        <Button
            android:id="@+id/button_to_child1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Go to Child 1" />
    </LinearLayout>
</layout>

 

코드 설명

  • 네비게이션 그래프: nav_graph.xml에서 childFragment1과 childFragment2를 정의하고, 액션을 통해 서로 연결합니다.
  • 부모 프래그먼트: ParentFragment는 FragmentContainerView를 사용하여 자식 프래그먼트들을 표시합니다. 데이터 바인딩을 통해 레이아웃과 연결하고, childFragmentManager를 사용하여 네비게이션 컨트롤러를 초기화합니다.
  • 자식 프래그먼트: ChildFragment1과 ChildFragment2는 데이터 바인딩을 통해 레이아웃과 연결하고, 버튼 클릭 시 findNavController().navigate()를 호출하여 다른 프래그먼트로 이동합니다.
  • 레이아웃 파일: 각 레이아웃 파일은 <layout> 태그로 감싸고, 필요한 뷰들을 정의합니다. 데이터 바인딩을 통해 뷰에 직접 접근할 수 있습니다.

결론

프래그먼트 안의 프래그먼트 네비게이션을 데이터 바인딩과 함께 사용하면 코드를 더욱 깔끔하고 효율적으로 관리할 수 있습니다. 데이터 바인딩을 통해 뷰와 데이터를 직접 연결하고, findViewById() 호출을 줄여 코드의 가독성과 유지보수성을 높일 수 있습니다. 안드로이드 앱 개발 시 프래그먼트 네비게이션과 데이터 바인딩을 적극적으로 활용하여 효율적인 개발을 경험해 보세요!

728x90
반응형
LIST