오늘은 액티비티 클래스의 뷰와 레이아웃에 대해 공부했다.
액티비티는 화면을 출력하는 컴포넌트일 뿐이지 그 자체가 화면은 아니다.
따라서 액티비티에서 적절한 화면을 구성해야한다.
화면에 내용을 표시하려면 뷰 클래스를 구성해야 한다.
문자열 출력은 TextView 클래스, 이미지는 ImageView 클래스를 이용하는 방식이다.
액티비티 실행 -> 뷰 클래스로 화면 구성 -> 기기의 화면에 출력
화면 구성 방식은 액티비티 코드에 직접 작성하는 방식과 xml 파일에 작성 후 전달하는 방식이 있다.
두 방법 모두 가능하므로 개발자가 선택하면 된다.
하지만 액티비티에 안그래도 작성할 코드가 많은데 화면 구현까지 넣으면 코드가 너무 길고 복잡해 유지보수에 힘들 수 있다.
따라서 화면 구현은 XML로, 액티비티에선 네트워킹, 데이터 핸들링, 사용자 이벤트 처리 등의 코드만 작성하는게 효율적이다.
예를 들어 TextView 2개와 ImageView 1개로 화면을 구성하고 LinearLayout 클래스로 화면을 배치한다고 할 때
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 이름 문자열 출력
val name = TextView(this).apply {
typeface = Typeface.DEFAULT_BOLD
text = "Lake Luise"
}
// 이미지 출력
val image = ImageView(this).also {
it.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.lake_1))
}
// 주소 문자열 출력
val address = TextView(this).apply {
typeface = Typeface.DEFAULT_BOLD
text = "Lake Louise, AB, 캐나다"
}
// 레이아웃
val layout = LinearLayout(this).apply {
orientation = LinearLayout.VERTICAL
gravity = Gravity.CENTER
// LinearLayout 객체에 위의 View 객체 추가
addView(name, WRAP_CONTENT, WRAP_CONTENT)
addView(image, WRAP_CONTENT, WRAP_CONTENT)
addView(address, WRAP_CONTENT, WRAP_CONTENT)
}
// layout을 화면에 출력
setContentView(layout)
}
}
TextView 2개와 ImageView 1개를 LinearLayout 객체에 추가해 이를 setContentView로 전달해서 화면에 출력하는 방식
apply 함수는 호출하려는 함수가 고차함수이고 마지막 전달 인자가 람다함수면 소괄호를 생략 가능하다. 그래서 {} 중괄호로 인자를 전달하는 모습이다.
이렇게 모든 내용을 Activity에 직접 코드로 구현시 레이아웃 XML 파일은 작성하지 않아도 된다.
res 폴더의 layout 폴더에서 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">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Lake Louise"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.22" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Lake Louise, AB, 캐나다"
tools:layout_editor_absoluteX="133dp"
tools:layout_editor_absoluteY="495dp" />
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/lake_1"
tools:layout_editor_absoluteX="0dp"
tools:layout_editor_absoluteY="100dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
setContentView(R.layout.activity_main)
액티비티 화면 구성시 사용하는 클래스는 모두 View의 하위 클래스다.
그래서 화면 구성과 관련한 클래스를 통칭해 뷰 클래스라고 한다.
View : 모든 뷰 클래스의 최상위 클래스. 액티비티는 View의 서브 클래스만 화면에 출력한다.
ViewGroup : 자체 UI가 없어 화면에 출력해도 아무것도 안나온다.
다른 뷰 여러개를 묶어 제어할 목적으로 사용한다. 컨테이너의 기능.
TextView: 문자열을 출력하는 뷰.
ImageView : 이미지를 출력하는 뷰.
레이아웃 클래스는 화면 자체가 목적이 아니라 다른 뷰 객체 여러개를 담아 한꺼번에 제어할 목적으로 사용된다.
위의 '레이아웃 XML로 화면 구성'의 코드에서 볼 수 있듯, <constraintlayout> xml 안에서 view 3개가 담겨있어 레이아웃을 구성한다.
아래의 그림처럼 레이아웃 객체를 중첩해서 계층구조를 만들어 구성할 수 있다.
이처럼 객체를 계층구조로 만들어 이용하는 패턴을
컴포지트 패턴(composite pattern)
또는 문서 객체 모델(document object model)
이라 한다.