[Android] 안드로이드의 레이아웃 인플레이션(Layout Inflation)
일반적으로 안드로이드 앱의 레이아웃을 정의하기 위해 XML 레이아웃을 사용한다.
XML 레이아웃은 단순히 XML로 정의된 파일이다. 이 파일엔 뷰의 배치 방식과 속성이 정의되어 있다.
따라서 XML 코드를 작성했다고 바로 화면을 띄우고 앱을 실행할 수는 없다.
화면의 구성을 XML로, 기능을 소스 코드로 각각 분리해서 정의했다고 가정해보자.
복수의 파일 중 적절한 XML을 소스 코드에서 어떻게 선택해서 인식할 수 있을까?
소스 코드에 어떤 XML이 지정되어야 하는지 매치하는 과정은 반드시 필요하다.
이 때 등장하는 개념이 레이아웃 인플레이션(Layout Inflation)
이다.
XML 레이아웃과 Java 코드를 연결하기
안드로이드 스튜디오에서 새로운 프로젝트를 만들면 MainActivity.java가 자동으로 생성된다.
MainActivity의 OnCreate() 메서드 안에는 setContentView(R.layout.activity_main);
이 들어가 있다.
즉, setContentView()
는 파라미터로 넘어온 레이아웃과 XML 레이아웃 파일을 연결하기 위해 사용한다.
파라미터로 레이아웃을 지정할 때는 확장자 없이 R.layout.파일명
의 형식을 사용한다.
이렇게 XML 레이아웃의 내용이 메모리에 객체화되는 과정을 인플레이션(Inflation)
이라고 한다.
setContentView()를 호출하면 내부적으로 인플레이션 과정이 진행되기 때문에 자바 코드에서 XML에 정의한 뷰들을 사용할 수 있다.
setContentView()의 역할
- 화면에 나타날 뷰를 지정
- 레이아웃 내용을 메모리에 객체화
인플레이션은 앱이 실행되는 시점에 진행된다. 따라서 setContentView()를 호출하기 전에 XML에 정의된 뷰를 참조하게 되면 NPE가 발생하며 앱이 강제로 종료된다.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button mEmailSignInButton = (Button) findViewById(R.id.sign_in_button);
mEmailSignInButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
attemptLogin();
}
});
setContentView(R.layout.activity_login);
}
setContentView()는 전달받은 레이아웃 안에 들어있는 뷰들을 메모리에 올린다.
메모리에 올라간 뷰를 소스 코드에서는 id를 통해 참조할 수 있다. 객체를 찾을 때는 findViewById()
메서드를 이용할 수 있다.
XML에 뷰를 추가할 때 넣어둔 id 속성의 값을 파라미터로 사용한다.
Button button = (Button) findViewById(R.id.sign_in_button);
별도의 XML 레이아웃 파일을 불러오기
XML로 화면의 일부분을 차지하는 부분 화면을 따로 정의할 수 있다. setContentView()는 화면 전체를 설정하는 역할만을 수행하기 때문에 부분 화면을 불러올 때는 사용할 수 없다.
화면 전체에 뿌려줄 XML 레이아웃이 아닌 별도의 XML 파일을 Java 코드에서 사용하려면 어떻게 해야할까?
안드로이드는 인플레이션 처리를 할 XML을 직접 지정할 수 있도록 LayoutInflater
라는 클래스를 제공한다.
LayoutInflater는 시스템 서비스로 제공하는 클래스이므로 getSystemService()
라는 메서드를 이용해 LayoutInflater 객체를 참조한 후 사용해야 한다.
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
아니면 LayoutInflater 클래스의 from()
메서드를 호출하여 참조할 수도 있다.
LayoutInflater inflater = LayoutInflater.from(getApplicationContext());
inflate()
의 첫번째 파라미터로 레이아웃 리소스 아이디를, 두번째 파라미터로 부분 화면을 로드할 부모 컨테이너를 지정한다.
container = findViewById(R.id.{부분 화면을 로딩할 뷰의 이름});
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.{불러올 XML 파일명}, container, true);
아래는 TextView가 든 부분 화면을 로드하는 간단한 예제이다. 버튼을 클릭하면 container로 id가 지정된 LinearLayout에 부분 화면이 로드될 것이다.
-
activity_main.xml : 전체 화면이 정의된 레이아웃 파일이다.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <Button android:id="@+id/btn_main" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="부분 화면 추가하기" /> <LinearLayout android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" />
-
sub.xml : container 자리에 로드될 부분 화면을 정의한 레이아웃 파일이다.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/tv_sub" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
-
MainActivity.java : 부분 화면을 inflate 한다.
public class MainActivity extends AppCompatActivity { private Button button; private LinearLayout container; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button = findViewById(R.id.btn_main); container = findViewById(R.id.container); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); inflater.inflate(R.layout.sub, container, true); TextView subTextView = container.findViewById(R.id.tv_sub); subTextView.setText("부분 화면입니다!"); } }); } }
이제 버튼을 클릭한 순간 sub.xml의 내용이 뷰그룹 객체로 메모리에 올라간다.
부분 레이아웃은 container 객체에 설정되었으므로 container 객체에 findViewById()를 사용해야 부분 화면의 뷰를 참조할 수 있다.
좌 : 버튼 클릭 전
우 : 버튼 클릭 후
'if (study) > Android' 카테고리의 다른 글
[Android] 안드로이드의 4대 컴포넌트 (구성 요소) (0) | 2019.08.29 |
---|---|
[Android] 안드로이드의 이벤트 처리 (0) | 2019.08.28 |
[Android] TableLayout(테이블 레이아웃) 사용하기 (0) | 2019.08.22 |