본문 바로가기
안드로이드/Android

[Android] View

by jinwo_o 2024. 10. 5.

View

 

  • 그리기 및 이벤트 처리를 담당하는 UI 구성요소의 기본 클래스
  • *위젯을 작성하는 데 사용되는 기본 클래스 (새로운 위젯을 만들기 위해선 View 를 상속하여 구현해야 한다)
    • 위젯(컴포넌트) : View 를 상속받아 구현하는 TextView, Button 등 어떤 특수한 목적을 가지고 있는 View
  • 위젯들을 담는 부모 뷰 Layout 도 View 를 상속받는 *ViewGroup 을 상속받아 구현한다.
    • ViewGroup : View 의 또 다른 서브 클래스이자 보이지 않는 컨테이너로, 다른 View 들을 포함할 수 있다.

 

View 가 그려지는 과정

  • 뷰는 포커스를 받게 되면 Android 에게 View Hierarchy 의 루트 노드를 제공하여 레이아웃을 그리게 된다.
    • 액티비티의 onCreate() 내에서 setContentView() 를 통해 루트 노드 전달
  • 레이아웃은 루트 노드부터 리프 노드까지 트리를 따라 순서대로 그려지게 된다.
    • 부모가 먼저 그려지고 그 다음 자식들 순서대로 그려지는 형태 (Top-down 방식)
  • 부모 뷰(ViewGroup, Layout)는 자식 뷰들의 draw() 를 호출하여 화면에 지정된 형태로 자식 뷰들을 그려줄 것을 요청한다.
    • 모든 뷰는 스스로 그려질 책임이 있다.
  • 레이아웃을 그리는 과정은 크게 *Measure 단계와 *Layout 단계를 거친다.

 

View Lifecycle

  • 부모 뷰가 addView() 를 호출하면, 자식 뷰가 부모 뷰에 추가되고, 이후 뷰의 생명주기 과정이 진행된다.

 

1. Constructor(생성자)

public View(Context context) { .. }

public View(Context context, @Nullable AttributeSet attrs) {
  this(context, attrs, 0);
}

public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
  this(context, attrs, defStyleAttr, 0);
}

public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { .. }
  • 모든 뷰는 생성자를 통해 초기화되며 생명 주기가 시작된다.
  • 이때 *AttributeSet 을 전달받아 뷰의 속성을 설정할 수 있다.
    • AttributeSet : XML 레이아웃 파일에서 정의된 뷰의 속성(Attribute)을 가져오는 데 사용되는 인터페이스
  • addView() 메소드를 갖게 된다.

1-1. View(Context context)

  • 코드에서 View 를 동적으로 만들 때 사용할 수 있는 간단한 생성자
  • context : View 가 실행될 때 사용되는 context 로, 현재 테마, 리소스 등을 구성하는 데 사용된다.

1-2. View(Context context, @Nullable AttributeSet attrs)

  • XML 에서 View 를 *전개 할 때 호출되는 생성자
    • 전개(Inflate) : xml 에 표기된 레이아웃을 메모리에 로딩된 후 객체화 시키는 과정
  • XML 파일에서 지정된 속성을 제공하여 XML 파일에서 View 를 구성할 때 호출된다.
  • 이 생성자는 기본 스타일인 0을 사용하기 때문에 context 의 테마와 지정된 AttributeSet 의 속성 값만 적용된다.

1-3. View(Context context, @Nullable AttributeSet attrs, int defStyleAttr)

  • XML 을 통해 전개를 하고 테마 속성에서 클래스별 기본 스타일을 적용한다.
  • 이 생성자는 서브 클래스가 전개할 때 자체 기본 스타일을 사용할 수 있도록 한다.
    • 예시: Button 클래스의 생성자는 슈퍼 클래스의 생성자를 호출하면서 defStyleAttr R.attr.buttonStyle 을 제공한다. 이를 통해 Button 스타일이 적용되어, 기본적인 View 속성과 Button 클래스의 속성을 모두 수정할 수 있다.
      • 버튼에 대한 일관된 스타일링을 유지하면서도, 추가적인 속성을 쉽게 조정할 수 있다.
  • defStyleAttr : View의 기본값을 제공하는 Style 리소스 대한 참조를 포함하는 현재 테마의 속성이다. 기본값을 찾지 않으려면 0으로 지정할 수 있다.

1-4. View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes)

  • XML 을 전개하고 테마 속성 또는 Style 리소스에서 클래스 별 기본 스타일을 적용한다.
  • 이 생성자는 서브 클래스가 전개할 때 자체 기본 스타일을 사용할 수 있도록 한다. 위와 유사하다.
  • defStyleRes : View 의 defStyleAttr 가 0이거나 테마에서 찾을 수 없는 경우에만 기본값을 제공하는 Style 리소스 ID 다. 기본값을 찾지 않으려면 0으로 지정한다.

 

2. onAttachedToWindow()

  • 뷰가 윈도우에 연결될 때 호출된다.
  • 뷰가 활성화될 수 있고, 뷰를 그리기 위한 surface 가 있다는 것을 아는 단계이다.
  • 고유 ID 를 통해 뷰에 접근 가능하다.
  • 리소스 할당을 시작하거나 리스너를 설정할 수 있다.

 

3. measure()

  • 뷰가 얼마나 커야 하는지 크기를 요청한다.
  • 뷰는 반드시 ViewGroup 에 속해 있다. 그러므로 뷰는 자신의 크기를 결정하기 위해 자신을 담고 있는 부모 뷰의 크기를 알아야 하고 그 안에서 자신이 사용할 영역을 알아야 한다.
  • View 객체의 측정된 너비와 높이 값은 부모 뷰가 부여한 제약 조건을 준수해야 한다.
  • Measure 단계가 모두 종료되고 모든 상위 뷰들과 자식 뷰들의 측정값을 모두 수락하는 단계를 거친다.
    • 부모 뷰는 자식 뷰의 크기 합이 너무 크거나 작을 경우, 자식 뷰에 대해 두 번 이상의 measure() 호출을 할 수 있다.
  • measure() 의 파라미터에는 *MeasureSpec 을 전달한다.
    • View.MeasureSpecs : 부모 뷰가 자식 뷰의 크기를 제한할 때 사용한다.
      • UNSPECIFIED : 자식 뷰의 크기에 대한 제한이 없다.
      • EXACTLY : 자식 뷰의 정확한 사이즈를 설정한다.
      • AT_MOST : 자식 뷰의 최대 사이즈를 설정한다.

 

4. onMeasure()

  • 뷰의 크기를 측정하기 위해 measure() 에서 호출하는 콜백 메서드로, 정확한 측정값을 제공하기 위해 재정의해야 한다.
    • 측정값을 정하기 전에는 너비와 높이가 0이다.
  • 부모 뷰는 모든 자식 뷰의 measure() 가 완료된 후, 자식 뷰의 getMeasuredWidth()getMeasuredHeight() 값을 사용하여 자신의 크기를 설정한다.
  • setMeasuredDimension() 호출하여 명시적으로 너비와 높이 설정한다.
    • 호출하지 않으면 IllegalStateException 을 던진다.
  • ViewGroup.LayoutParams : 자식 뷰가 부모 뷰에게 너비와 높이에 대해 얼마나 크게 되기를 원하는지를 설명한다.
    • MATCH_PARENT : 자식 뷰가 부모 뷰의 크기에 꽉 맞추겠다.
    • WRAP_CONTENT : 자식 뷰가 자신의 내용물 크기에 맞춰 크기를 조정하겠다.
    • 정확한 숫자값 : DP 값

 

5. layout()

  • 뷰와 모든 자식 뷰들의 위치를 요청한다.

 

6. onLayout()

  • 뷰의 크기와 위치를 지정하기 위해 layout() 에서 호출하는 콜백 메서드
  • 부모 뷰는 Measure 단계에서 측정된 크기를 사용하여 모든 자식 뷰들의 위치를 배정한다.

 

7. dispatchDraw()

  • ViewGroup 에 속한 메서드
  • 뷰가 다시 그려져야 할 경우, 자식 뷰들도 함께 다시 그려지도록 한다.

 

8. draw(), onDraw()

  • 실제로 뷰를 그리는 단계
  • 파라미터로 *Canvas 객체가 넘어오고, Canvas 객체에 *Paint 를 이용해서 텍스트, 선, 비트맵 등을 그리기 위한 메서드를 정의한다. 
    • Canvas : 어떤 도형을 그릴 것인지에 대한 메서드를 제공하는 객체
    • Paint : 색상, 스타일, 글꼴 등을 정의하는 객체
  • 크기와 위치는 이전에 계산되었기 때문에, 이를 기준으로 뷰가 그려지게 된다.
  • 해당 콜백 메소드는 언제든 다시 호출될 수 있기 때문에, 이 안에서 객체를 생성하면 안된다.
    • 스크롤, 스와이프 등 인터렉션이 발생하면 언제든 호출될 수 있다.

 

9-1. invalidate()

  • 글자나 색상 등 크기 변화 없이 단순히 뷰의 속성 등이 변경된 경우, 뷰를 다시 그리기 위해 호출하는 메소드

9-2. requestLayout()

  • 뷰의 크기 변화하면 레이아웃의 배치도 달라질 수 있기 때문에, 뷰를 다시 측정하기 위해 호출하는 메서드

 

10. 기타

10-1. onDetachedFromWindow()

  • 뷰가 윈도우에서 분리될 때 호출된다.
  • 이 시점에서 더 이상 드로잉을 할 표면이 없다.
  • 예약된 자원을 정리하거나 정리하는 모든 종류의 작업을 중지해야 하는 곳이다.
  • 부모 뷰에서 해당 뷰 제거를 호출하거나 액티비티가 onDestroy() 될 때 호출된다.

10-2. onFinishInflate()

  • 뷰의 inflate 가 끝날 때 호출된다.
    • 레이아웃의 경우 모든 Child View 가 추가 된 후에 호출된다.

 


 

[Android] CustomView 알아보기

CustomView를 만드는 이유 Android에는 UI를 구성하는 데 사용할 수 있는 미리 빌드된 기본 클래스인 View 및 ViewGroup과 다양한 서브클래스(위젯 및 레이아웃)가 있습니다. 어플리케이션의 UI 요구사항에

seosh817.tistory.com

 

[Android] View 의 한 평생 살펴보기

너무 아름다운 다운 다운 다운 View (죄송합니다)

velog.io

 

Android에서보기의 수명주기

안드로이드 앱을 실행할 때 우리가 가장 먼저 스크린에서 볼 수 있는 것이 View라고 말할 수 있다.

charlezz.medium.com

 

'안드로이드 > Android' 카테고리의 다른 글

[Android] Strong, Soft, Weak, Phantom Reference  (0) 2024.10.21
[Android] ConstraintLayout  (0) 2024.10.02
[Android] px(pixel), dp(dip), sp  (0) 2024.10.01