반응형
Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Archives
Today
Total
관리 메뉴

코딩하기 좋은날

Navigation 과 Fragment (Kotlin) 본문

Android

Navigation 과 Fragment (Kotlin)

huiung 2020. 5. 23. 14:37
반응형

모든 코드는 Kotlin으로 작성 되었습니다.

 

 

Navigation 과 Frament 를 이용하면 기존에 화면 전환을 위해 여러 Activity를 만들고 상황에 따라 Activity를 전환 하는것이 아니라 MainActivity를 두고 Navagation이라는 기능을 통해 만들어놓은 Fragment로 이동하는 것이 가능합니다. 이것이 Andriod Jetpack 에 추가된 Navigation 이라는 기능입니다.

 

Navigation을 이용해 fragment간 화면 전환과 bundle을 통한 데이터를 전달하는 앱을 하나 만들어 보겠습니다.

 

우선 Navigation을 사용하기 위해서 build.gradle에 아래와 같은 dependency를 추가 해줍니다.

 

dependencies {
  def nav_version = "2.3.0-beta01"

  // Java language implementation
  implementation "androidx.navigation:navigation-fragment:$nav_version"
  implementation "androidx.navigation:navigation-ui:$nav_version"

  // Kotlin
  implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
  implementation "androidx.navigation:navigation-ui-ktx:$nav_version"

  // Dynamic Feature Module Support
  implementation "androidx.navigation:navigation-dynamic-features-fragment:$nav_version"

  // Testing Navigation
  androidTestImplementation "androidx.navigation:navigation-testing:$nav_version"
}

 

1. MainActivity 에 Navigation host를 추가 해주어야 합니다. Navigation host는 frament간 전환을 가능하게 해 줍니다. 이를 위해 먼저 res 폴더 하위에 Resource directory를 하나 만들어 줍니다. Type은 Navigation으로 해야 합니다. 그리고 이 디렉터리 하위에 Navigation resource file 인 nav_graph.xml 을 하나 만들어 줍니다. 생성하면 아래와 같이 보입니다.

 

그 다음엔 activity_main.xml 파일로 가서 다음과 같은 코드를 추가 해 줍니다.

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

2. MainActivity가 있는 디렉터리에서 package를 하나 만듭니다. 그리고 여기서 사용할 fragment를 2개 만들어 줍니다.

 

그리고 나서 각각 생긴 frament의 xml 파일에 textview를 2개 추가 해줍니다. 하나는 그냥 글이 써져있고 다른 하나는 bundle을 통해 전달 받은 값을 표시해 보겠습니다.

 

fragment_first.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"
    android:background="@color/mycolor"
    tools:context=".fragment.first">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:id="@+id/textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="first fragment"
        android:textSize="32sp"
        android:gravity="center"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textview2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        android:layout_marginTop="30dp"
        app:layout_constraintTop_toBottomOf="@+id/textview"></TextView>

</androidx.constraintlayout.widget.ConstraintLayout>

 

fragment_second.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"
    android:background="@color/colorPrimary"
    tools:context=".fragment.second">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:id="@+id/textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="second fragment"
        android:textSize="32sp"
        android:gravity="center"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textview2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        android:layout_marginTop="30dp"
        app:layout_constraintTop_toBottomOf="@+id/textview"></TextView>

</androidx.constraintlayout.widget.ConstraintLayout>

 

이렇게 작성한 뒤 아까 만들었던 nav_graph.xml 파일로 이동합니다. 이동 후 design 모드로 보면 

 

 

아래와 같은 화면이 있는데 상단 왼쪽에 + 를 통해서 fragment를 추가 해 주면 됩니다. 집 그림이 있는 fragment는 앱을 최초 실행 했을 때 나오는 fragment입니다. 그리고 fragment를 클릭하면 저렇게 동그라미가 나오는데 저것을 fragment 끼리 연결 해 주면 navController를 통해서 이동이 가능 해 집니다. 저렇게 연결된 화살표를 xml 코드에서는 action 이라고 칭하고 있습니다. 이 action을 클릭하면 action의 속성을 볼 수 있는데 다음과 같습니다.

 

enter / exit / popEnter / popExit 의 애니메이션을 지정 할 수 있는 것이 보입니다. navigation 은 fragment를 스택으로 관리 하기 때문에 뒤로 가기 버튼을 누르면 스택의 pop을 하고 top fragment를 보여 줍니다. 따라서 popEnter/ popExit Anim 이 따로 존재 하는 것 같습니다. 저는 그냥 default 애니메이션 이용 하겠습니다.

 

3. MainActivity.kt 로 가서 navController를 지정해 줍니다.

 

MainActivity.kt

 

class MainActivity : AppCompatActivity() {

    lateinit var navController: NavController

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        navController = nav_host_fragment.findNavController()

    }
}

4. 다른 fragment들의 코드를 작성해 줍니다.

 

first.kt

 

class first : Fragment() {

    lateinit var navController: NavController

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_first, container, false)
    }

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

        navController = Navigation.findNavController(view)
        val bundle = bundleOf("message" to "i'm from first fragment!")

        val message = arguments?.getString("message")

        textview2.text = message

        textview.setOnClickListener {
            navController.navigate(R.id.action_first2_to_second2, bundle)
        }
    }
}

onViewCreated 함수를 override 한뒤 arguments 에서 받아온 메시지가 있으면 textview2 에 메시지를 넣고 textview 를 클릭 했을 때 fragment를 전환 할 것이므로 setOnClickListener 를 위와 같이 해줍니다. 코틀린에서는 override 할 함수가 하나만 있고 매개변수에 람다식을 넣어야 할 때 저렇게 간단하게 작성이 가능하여 자바처럼 보일러 플레이트 코드가 많이 줄어듭니다!

 

second.kt

 

class second : Fragment() {

    lateinit var navController: NavController

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_second, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        navController = Navigation.findNavController(view)


        val bundle = bundleOf("message" to "i'm from second fragment")

        val message = arguments?.getString("message")

        textview2.text = message

        textview.setOnClickListener {
            navController.navigate(R.id.action_second2_to_first2, bundle)
        }
    }

}

여기까지 작성한 후 실행을 하게 되면 아래와 같이 최초 화면 입니다.

 

text를 클릭하면 아래와 같이 나오고 bundle을 통해 넘어온 데이터가 나오는 것을 볼 수 있습니다. 여기서 text를 클릭하게 되면

 

 

bundle로 부터 데이터를 받았기 때문에 아래와 같이 나옴을 알 수 있습니다. 

이런식으로 아주 편리하게 사용을 할 수 있습니다.

반응형