본문 바로가기
Android

[Android] inflate 에 대해 알아보기

by Glion 2023. 9. 20.
반응형
더보기

Android 앱 개발을 하다보면 Fragment 를 사용하거나, 하다못해 들어봤을텐데, 이런 형태일 것이다.

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

이 Fragment 의 onCreateView에서 return 하는 inflater.inflate... 대체 뭐길래 View 타입으로 반환되는 것일까?

 

Fragment 는 추후에 좀 더 자세히 공부하기로 하고, 이 inflate 에 대해 공부한 내용을 정리한다.

 

Inflate?

inflate는 xml 로 만들어진 layout 파일을 메모리에 올려 View 타입 객체로 만드는 것을 말한다. 아래 이미지를 보자

Activity에서 findViewById를 사용하여 TextView에 text를 넣거나, Button 을 클릭했을때의 행동을 정의한다거나 할 때,

이 findViewById는 레이아웃에 정의한 TextView나 Button의 아이디를 가져와서 해당하는 타입의 객체로 생성한다.

 

이렇게 Activity에서 xml로 만들어진 layout의 요소에 접근할 수 있고, 사용할 수 있게 하는것이 바로 inflate 이다.

 

LayoutInflater

이러한 inflate 동작은 LayoutInflater 가 하게 된다. LayoutInflater 는 xml 리소스를 View객체로 반환하는 역할을 한다.

 

사용법은 다음과 같다.

val inflater = getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater // LayoutInflater 객체 생성
inflater.inflate(resource, root, attachToRoot)

 

LayoutInflater 객체의 inflater 함수를 사용하는데 inflate 함수의 인자로 resource에 객체화할 레이아웃, root에 레이아웃을 띄울 컨테이너, attachToRoot에  Boolean 값이 들어간다.

 

resource 에는 "R.layout.레이아웃명" 이 들어간다.

root에는 레이아웃을 띄울 컨테이너 인데, 이 컨테이너는 ViewGroup 타입이다.

ViewGroup 이란 View 를 포함하여 화면에 적절히 배치하기 위한 일종의 컨테이너로서, n개의 뷰를 포함할 수 있는 컨테이너 이다. LinearLayout, RelativeLayout, ConstraintLayout 등등이 이에 포함된다.

attachToRoot는 객체화 한 뷰를 컨테이너에 지금 바로 붙일건지(true), 나중에 붙일건지(false)를 지정한다. false로 했을 경우 나중에 addView 를 통해 붙여주어야 화면에 표시된다.

 

나는 처음에 inflate에 대해 잘 알지 못하고 사용할 때, inflate 로 붙인 레이아웃을 띄울 컨테이너는 무조건 FrameLayout

이라고 생각했었다. 하지만, ViewGroup 타입의 레이아웃은 전부 컨테이너가 될 수 있다.

다음 테스트 코드에서, FrameLayout, LinearLayout, RelativeLayout, ConstraintLayout 에 inflate 를 시켜보았다.

 

전체 코드

layout_inflate

더보기
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/inflate_string"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="inflate 되었음"
        style="@style/nanumTextView"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

activity_inflate

더보기
<?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=".activity.InflateActivity">

    <!-- 1. FrameLayout에 inflate -->
    <FrameLayout
        android:id="@+id/fr_layout"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/black"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/fr_layout" />

    <!-- 2. LinearLayout에 inflate -->
    <androidx.appcompat.widget.LinearLayoutCompat
        android:id="@+id/ll_layout"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/fr_layout" />

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/black"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/fr_layout" />

    <RelativeLayout
        android:id="@+id/rl_layout"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/ll_layout" />

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/cl_layout"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/rl_layout" />


    <androidx.appcompat.widget.AppCompatButton
        android:id="@+id/btn_frameLayout"
        style="@style/nanumButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="10dp"
        android:layout_marginBottom="10dp"
        android:padding="14dp"
        android:text="프레임레이아웃 inflate"
        app:layout_constraintBottom_toTopOf="@+id/btn_relativelayout"
        app:layout_constraintEnd_toStartOf="@+id/btn_linearlayout"
        app:layout_constraintStart_toStartOf="parent" />

    <androidx.appcompat.widget.AppCompatButton
        android:id="@+id/btn_linearlayout"
        style="@style/nanumButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="10dp"
        android:padding="14dp"
        android:text="리니어레이아웃 inflate"
        app:layout_constraintBottom_toTopOf="@+id/btn_constraint"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/btn_frameLayout" />

    <androidx.appcompat.widget.AppCompatButton
        android:id="@+id/btn_relativelayout"
        style="@style/nanumButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="10dp"
        android:padding="14dp"
        android:text="렐러티브레이아웃 inflate"
        app:layout_constraintEnd_toStartOf="@+id/btn_constraint"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintBottom_toTopOf="@+id/v_endline" />

    <androidx.appcompat.widget.AppCompatButton
        android:id="@+id/btn_constraint"
        style="@style/nanumButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="10dp"
        android:padding="14dp"
        android:text="constraintlayout inflate"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/btn_frameLayout"
        app:layout_constraintBottom_toTopOf="@+id/v_endline" />

    <View
        android:id="@+id/v_endline"
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/black"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="80dp"/>

    <androidx.appcompat.widget.AppCompatButton
        android:id="@+id/btn_go_main"
        style="@style/nanumButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="10dp"
        android:layout_marginVertical="10dp"
        android:padding="14dp"
        android:text="메인으로"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/v_endline"/>

</androidx.constraintlayout.widget.ConstraintLayout>

InflateActivity

더보기
class InflateActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_inflate)

        val frContainer = findViewById<FrameLayout>(R.id.fr_layout)
        val llContainter = findViewById<LinearLayoutCompat>(R.id.ll_layout)
        val rlContainter = findViewById<RelativeLayout>(R.id.rl_layout)
        val clContainter = findViewById<ConstraintLayout>(R.id.cl_layout)
        val inflater = getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater

        findViewById<AppCompatButton>(R.id.btn_go_main).apply{
            setOnClickListener { finish() }
        }

        findViewById<AppCompatButton>(R.id.btn_frameLayout).apply {
            setOnClickListener {
                // attachToRooT 를 false로 주어 바로 붙이지 않았을때
                val inflateView = inflater.inflate(R.layout.layout_inflate, frContainer, false)
                frContainer.addView(inflateView) // 컨테이너에 붙이는 작업
                inflateView.findViewById<AppCompatTextView>(R.id.inflate_string).text = "프레임레이아웃 inflate"
            }
        }

        findViewById<AppCompatButton>(R.id.btn_linearlayout).apply{
            setOnClickListener {
                inflater.inflate(R.layout.layout_inflate, llContainter, true).findViewById<AppCompatTextView>(R.id.inflate_string).text = "리니어레이아웃 inflate"
            }
        }
        
        findViewById<AppCompatButton>(R.id.btn_relativelayout).apply{
            setOnClickListener {
                inflater.inflate(R.layout.layout_inflate, rlContainter, true).findViewById<AppCompatTextView>(R.id.inflate_string).text = "렐러티브레이아웃 inflate"
            }
        }

        findViewById<AppCompatButton>(R.id.btn_constraint).apply{
            setOnClickListener {
                inflater.inflate(R.layout.layout_inflate, clContainter, true).findViewById<AppCompatTextView>(R.id.inflate_string).text = "ConstraintLayout inflate"
            }
        }
    }
}

 

 

결과

 

setContentView(R.layout.activity_main)

새로운 액티비티를 생성했을 때, 어디에서도 inflate 관련된 코드를 찾을 수 없는데, 그럼 어떻게 바로 findViewById를 사용할 수 있었던 것일까?

 

액티비티를 생성하면, setContentView(R.layout.액티비티레이아웃) 부분을 볼 수 있을 것이다.

이 setContentView 가 xml을 객체화 하는 inflate 동작을 내부적으로 수행한다. 다음은 Activity의 기본적인 코드이다.

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

Activity가 시작하면 onCreate() 가 불리고, 그 안에서 setContentView(R.layout.activity_main) 이 실행되며 activity_main.xml 이 Activity에 inflate된다.

 

 

마무리

한 화면 안에 다른 화면을 보여주어야 할때나, 동적으로 화면을 전환시켜야 할때 inflate를 이용할 수 있다.

 

inflate 는 xml 레이아웃을 객체화 해주는 것으로서,

LayoutInflater.inflate(resource: Int, container: ViewGroup, attachToRoot: Boolean) 의 형태이다.

 

 


출처

https://www.crocus.co.kr/1584

 

Android LayoutInflater 개념 및 사용 방법

LayoutInflater이란? LayoutInflater은 XML에 미리 정의해둔 틀을 실제 메모리에 올려주는 역할을 한다. Inflater 단어의 뜻이 부풀리다라는 의미로써 LayoutInflater라는 단어에서도 유추가 가능하다. 즉, LayoutI

www.crocus.co.kr

 

반응형