뷰(View)가 그려지는 과정
안드로이드에서의 액티비티가 포커스를 얻으면, 자신의 레이아웃을 그리도록 요청한다.
이때 액티비티에 레이아웃의 계층구조 중 루트(root) 노드를 제공해야 한다.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(com.empo.android.empoapp.R.layout.activity_main)
}
뷰를 그리는 과정은 측정(Measure), 레이아웃(Layout) 단계가 있다.
측정(Measure) 과정 - 뷰의 크기를 구한다
public final void measure (int widthMeasureSpec, int heightMeasureSpec)
measure() 동안에 각 뷰들은 자신의 getMeasuredWidth() 와 getMeasuredHeight() 로 리턴할 값들을 세팅해줘야 합니다. (즉, 자신의 사이즈를 정해야함)
또한 뷰들은 자신의 부로로부터 부여된 constraint(제약사항)을 따라야 합니다.
이 과정을 통해 모든 부모 들은 자신의 자식들의 사이즈를 알게됩니다.
Measure 과정중 부모들은 measure() 를 한번 이상 호출할 것입니다. 예로, 부모는 첫번째 unspecified dimension 으로 measure() 를 호출해서 자신의 자식들이 얼마만큼 크기를 원하는지 알아냅니다. 그 후, 자식들의 unconstrained size 의 합이 너무 크거나 작으면 이번에는 실제 수치로 measure()를 호출해 child들이 사이즈를 정하도록 합니다.
(즉, 부모들은 첫번째 measure()로 자식들이 원하는 크기를 알아내고, 원하는 크기가 비정상적이라면 두번째 measure() 를 통해 자식들이 사이즈를 정하는데 간섭합니다.)
부모노드에서 자식노드를 경유하며 실행되며, 뷰의 크기를 알아내기 위해 호출된다. 이것은 뷰의 크기를 측정하는 것은 아니며 실제 크기 측정은 onMeasure(int, int)를 통해 이뤄진다. measure(int, int)의 내부에서는 onMeasure(int, int)를 호출함으로써 뷰의 크기를 알아낸다.
측정 과정에서는 부모 뷰와 자식 뷰간의 크기정보를 전달하기 위해 2가지의 클래스를 사용한다.
ViewGroup.LayoutParams
자식 뷰가 부모 뷰에게 자신이 어떻게 측정되고 위치를 정할지 요청하는데 사용된다. 첫번째는 ViewGroup.LayoutParams 입니다. LayoutParams는 뷰의 width, height가 얼마나 크기를 원하는지 설명합니다.
LayoutParms 는 아래 3가지로 나뉩니다.
1. 정확한 수치 (ex. 50dp, 100dp)
2. MATCH_PARENT (자신의 부모만큼 크기를 원함)
3. WRAP_CONTENT (자신의 내용물만 담을수 있을 만큼만 크기를 원함, padding 포함)
(ViewGroup.LayoutParams를 상속받은 녀석들도 있긴 함. 예로, RelativeLayout의 LayoutParams는 자식뷰들의 정렬에 대한 내용도 가지고 있음)
- 숫자 (ex. android:layout_width=”320dp”)
- MATCH_PARENT (ex.android:layout_width=”match_parent”)
- WRAP_CONTENT (ex.android:layout_width=”wrap_content”)
ViewGroup.MeasureSpec
부모 뷰가 자식 뷰에게 요구사항을 전달하는데 사용된다.
- UNSPECIFIED - 부모 뷰는 자식 뷰가 원하는 치수대로 결정한다.
- EXACTLY - 부모 뷰가 자식 뷰에게 정확한 크기를 강요한다.
- AT MOST - 부모 뷰가 자식 뷰에게 최대 크기를 강요한다.
레이아웃(Layout) 과정 - 뷰의 위치를 정함
public final void layout (int l, int t, int r, int b)
부모노드에서 자식노드를 경유하며 실행되며, 뷰와 자식뷰들의 크기와 위치를 할당할 때 사용된다. measure(int, int)에 의해 각 뷰에 저장된 크기를 사용하여 위치를 지정한다. 내부적으로 onLayout()를 호출하고 onLayout()에서 실제 뷰의 위치를 할당하는 구조로 되어있다.
measure()와 layout()함수는 내부적으로 각각 onMeasure()와 onLayout()함수를 호출한다. 이것은 final로 선언된 measure()와 layout() 대신 onMeasure()와 onLayout()을 구현(override)할 것을 장려하기 위해서이다.
뷰의 measure()함수가 반환할때, 뷰의 getMeasureWidth()와 getMeasureHeight()값이 설정된다. 만약 자식 뷰 측정값의 합이 너무 크거나 작을 경우 다시 measure()함수를 호출하여 크기를 재측정한다.
참고:
https://developer.android.com/guide/topics/ui/how-android-draws.html