안드로이드 코틀린 : Fragment 추가, 변경, 삭제 사용법 및 유의점
Lucy Archive
Lucy / Facilitate4U
2021. 3. 25. 14:48

Android Kotlin : Activity에 Fragmeent 추가, 변경, 삭제 및 고려사항 정리

안드로이드 개발자 가이드에서는 (다양한 이유로) 다수의 화면을 포함하는 앱은 다수의 Activity가 아닌 Fragment 사용하길 권장합니다. 이 포스트에서는

Activity의 FrameLayout에 Fragment를 추가, 대체, 삭제 하는 방법과 기타 유의점

등을 정리합니다.

 

Fragment는?

Fragment는 Activity 내에서 UI의 일부분을 나타내는 요소입니다. 즉, 아래와 같이 한 화면에 여러개의 화면을 보여주기위해 많이 사용됩니다. 물론 여러개의 Activity를 사용해서 여러 화면을 보여 줄 수 있지만, 안드로이드 가이드에서 Activity는 앱 UI의 탐색 네비게이션(구역)과 같은 전역적인 요소를 사용하고, 탐색 네비게이션 선택에 따라 컨텐츠가 보이는 부분은 프래그먼트로 사용 할 것을 권장합니다.

안드로이드 가이드 Fragment 개요 : https://developer.android.com/guide/fragments?hl=ko

※ 화면이 하나만 필요할 때는 프래그먼트를 사용하지 않습니다.

 

Fragment 사용하기

키워드

  • Fragment
    • Activity 내에서 UI의 일부분을 나타내는 요소 입니다. Activity의 부분 집합이 될 수 있습니다.
  • Fragment Manager
    • Activity 의 FrameLayout에 Fragment를 등록, 교체, 삭제 등의 기능을 포함한 클래스입니다.
    • Fragment 추가, 교체, 삭제 등의 변경 사항은 FragmentTransaction 이라는 객체에서 등록 후 Commit() 으로 실행합니다.
    • FragmentTrasaction 객체는 supportFragmentManager.beginTransaction() 함수의 반환값 입니다.
  • FrameLayout
    • Activity 내에서 화면 전환이 필요한 구역의 컨테이너로 사용됩니다. 

 

앱 따라하기

개요

아래와 같이 실행되는 테스트 앱 제작 방법입니다.

  • SWITCH 버튼을 누르면 FrameLayout에 FragmentA 와 FragmentB 가 교차 됩니다.
  • REMOVE 버튼을 누르면 FrameLayout의 Fragment 연결이 제거 됩니다.

앱 실행 화면

프로젝트 생성

프로젝트 이름과 언어는 아래와 같이 설정합니다.

  • 프로젝트명 : Fragment
  • 언어 : Kotlin

 

ViewBinding 환경 설정

build.gradle(Module: ManagingFolder) 파일에 아래의 ViewBinding 설정 코드를 추가합니다.

android { 
	... 
    viewBinding { 
    	enabled = true 
    } 
}

코드 추가가 완료되면 아래와 같이 Sync Now 클릭해서 Gradle 변경 사항을 적용합니다.

viewBinding 설정 코드 추가 및 적용

※ ViewBinding 은 Layout 에 있는 View의 Id를 코틀린 코드에서 직접 사용 할 수 있게 해주는 도구입니다. View Binding과 관련된 설명은 아래의 링크를 참조해주세요.

안드로이드 View Binding 사용하기

 

안드로이드 View Binding 사용하기 - kotlin-android-extensions 지원 중단

안드로이드 View Binding 방법 정리 안드로이드 코드에서 레이아웃 View에 접근하기 위해 사용된 kotlin-android-extensions 의 지원이 중단예정으로, 이를 대체하여 사용 할 수 있는 ViewBinding 사용법에 대해

juahnpop.tistory.com

 

Fragment 추가하기

아래와 같이 2개의 Fragment를 추가 합니다. 추가하는 Fragment의 이름은 FragmentA, FragmentB로 추가하였습니다. Fragment가 정상적으로 추가되면 아래 우측 그림과 같이 2개의 코틀린 파일과 2개의 레이아웃 파일이 추가됩니다.

Fragment 추가

 

UI만들기

3개의 레이아웃 코드를 아래와 같이 작성합니다. 코드 순서는 activity_main.xml, fragment_a.xml, fragment_b.xml 입니다.

activity_main.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">

    <FrameLayout
        android:id="@+id/frameLayout"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_margin="12dp"
        app:layout_constraintBottom_toTopOf="@+id/btnSwitch"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btnSwitch"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="12dp"
        android:text="Switch"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/btnRemove"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent" />

    <Button
        android:id="@+id/btnRemove"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="12dp"
        android:text="Remove"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/btnSwitch" />


</androidx.constraintlayout.widget.ConstraintLayout>

fragment_a.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=".FragmentA">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This is FragmentA"
        android:background="@color/white"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

fragment_b.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=".FragmentA">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This is FragmentB"
        android:background="@color/white"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

생성된 UI 화면

 

코틀린 코드 작성1 : Fragment 사용하기

FrameLayout에 FragmentA를 넣기 위한 MainActivity.kt 최소한의 코드는 아래와 같습니다.

package com.blacklog.fragment

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.blacklog.fragment.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    lateinit var binding : ActivityMainBinding

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

        binding.btnSwitch.setOnClickListener {
            setFragment()
        }
    }

    private fun setFragment() {
        val transaction = supportFragmentManager.beginTransaction()
                .add(R.id.frameLayout, FragmentA())
        transaction.commit()
    }
}

위 코드를 작성하고 Switch 버튼을 누르면 FrameLayout에 FragmentA가 나타납니다.

코틀린 코드 작성2 : 최종 코드

Fragment 처리를 위해 생성된 FragmentTransaction 객체에는 위 코드에서 사용한 add() 메서드 이외에 replace() 메서드 및 remove() 메서드를 사용할 수 있습니다. 이 메서드들을 사용하여 작성한 MainActivity의 최종 코드는 아래와 같습니다.

package com.blacklog.fragment

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.blacklog.fragment.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    lateinit var binding : ActivityMainBinding

    /*
    * when flag is 0 : 처음
    * when flag is 1 : FragmentA
    * when flag is 2 : FragmentB
    * */
    var flag = 0

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

        binding.btnSwitch.setOnClickListener {
            switchFragment()
        }
        binding.btnRemove.setOnClickListener {
            removeFragment()
        }

    }
    private fun switchFragment() {
        val transaction = supportFragmentManager.beginTransaction()
        when(flag){
            0 -> {
                transaction.add(R.id.frameLayout, FragmentA())
                flag = 1
            }
            1 -> {
                transaction.replace(R.id.frameLayout, FragmentB())
                flag = 2
            }
            2 -> {
                transaction.replace(R.id.frameLayout, FragmentA())
                flag = 1
            }
        }
        transaction.addToBackStack(null)
        transaction.commit()
    }
    
    private fun removeFragment() {
        val transaction = supportFragmentManager.beginTransaction()
        val frameLayout = supportFragmentManager.findFragmentById(R.id.frameLayout)
        transaction.remove(frameLayout!!)
        transaction.commit()
    }
}

위 코드를 작성하면 아래와 같이 Switch버튼을 누르면 FrameLayout에 표시되는 Fragment가 A, B 서로 전환이 되고, Remove 버튼을 누르면 FrameLayout에 연결된 Fragment가 삭제 됩니다.

앱 실행 화면

유의점

Fragment 배경색 지정

Fragment의 배경색은 투명으로 설정되어 있습니다. 위의 fragment_a.xml, fagment_b.xml 코드를 보면 android:background="@color/white" 와 같이 배경색 코드가 삽입 되어 있는 것을 볼 수 있습니다. 배경색이 지정되어 있지 않으면 Activity 화면이 중첩되어 표시됩니다.

백스택 설정

Fragment는 기본적으로 백 스텍에 저장되지 않습니다. 백 스택에 저장하고 싶은 경우 FragmentTransaction 에addToBackStack(null) 코드를 추가하여 뒤로가기 버튼 클릭시 이전 화면을 볼 수 있도록 설정이 가능합니다. 아래 그림은 addToBackStack(null) 코드 유무에 따른 동작 차이 입니다.

백 스택 설정 코드 유/무에 따른 실행 결과

끝까지 읽어 주셔서 감사합니다.^^

관련포스트

🤞 안드로이드(코틀린) 앱 제작하기 관련글 목록 보기

🤞 안드로이드(코틀린) 프래그먼트 관련글 목록 보기