코틀린 & Java/컴포즈 Compose

컴포즈(Compose) 선언적 패러다임 이해

코딩하는후운 2023. 8. 16. 17:58
반응형

전통적인 뷰 기반 접근 방식은 컴포넌트와 클래스에 중점을 뒀던 것에 비해
새로운 프레임워크는 선언적 접근 방식을 따른다.

안드로이드 뷰 시스템 살펴보기

  • 기존 접근 방식
    • 컴포넌트 트리를 정의하고 런타임에서 변경하는 것
    • 레이아웃 파일은 계층구조(트리)를 정의
  • 레이아웃 파일 인플레이팅
    • 두가지 문제
      • 변수를 초기화 하기 전에 접근하면 런타임에서 크래시
      • 컴포넌트 개수가 많아지면 코드가 비대해짐
        • 두 번째 문제를 해결하고자, 컴포넌트 참조를 계속 유지해야 하는 작업을 덜어주고자 구글은 뷰 바인딩 기능을 제공
  • 일반적인 UI 프레임워크를 명력적이라고 하는 이유
    • UI는 XML파일로 정의
    • UI는 런타임 단계에서 컴포넌트 트리로 인플레이트된다.
    • UI를 변경하려면 연관된 모든 컴포넌트의 속성을 수정해야만 한다.
    • UI 요소가 화면에서 보이지 않더라도 컴포넌트 트리의 요소로는 남아있다.

컴포넌트에서 컴포저블 함수로 이동

  • 컴포넌트 계층 구조
    • 전문적인 속성일 수록 다른 컴포넌트에 재사용할 가능성이 낮아진다.
  • 모든 안드로이드 뷰는 클래스다
  • 레이아웃 파일의 태그는 클래스를, 속성은 클래스의 멤버를 나타낸다
  • inflate()는 객체 트리를 생성한다
  • 객체 트리를 수정해 UI를 변경한다.

android.view.View는 모든 안드로이드 UI 요소의 최상위 요소가 된다.

  • 컴포넌트 계층 구조의 한계
    • 예) 버튼이 텍스트를 보여준다. 이미지를 보여주고 싶으면 이미지 버튼
      • 둘다 보여주고 싶으면? 가까운 공통 부모는 View이다.
      • 버튼의 모든 기능은 이미지 버튼에서 바로 사용할 수 없다.
    • 이는 자바가 단일 상속 기반이기 때문
    • 뷰는 패딩에 대해 알고 있지만 마진은 모른다. 마진은 뷰그룹이 알고 있다.
      • 사용하고 싶으면 뷰그룹을 확장해야 한다. → 필요 유무와 관계없이 다른 모든기능을 상속하게 된다.
      • 개별 기능을 분리할 수 없기 때문
  • 잿팩 컴포즈는 구성 요소끼리 조합하는 방식을 사용(플러터와 같음)
    • 클래스 대신 컴포저블 함수를 사용
  • 컴포저블 UI의 진입점은 컴포저블 함수다
  • 거기서부터 다른 컴포저블 함수가 호출된다.
  • 컴포저블 함수는 주로 content 매개변수를 전달 받는데, 이는 다른 컴포저블 함수다
  • 호출 순서는 다른 UI요소와 비교해 UI요소가 위치할 곳을 제어한다.

레이아웃 파일은 초기 상태로 컴포넌트 트리를 정의하는 반면
컴포저블 UI는 항상 실제 데이터를 사용해 정의

  • UI가 화면에 나타나기 전에 이를 설정하거나 준비할 필요가 없다는 것

동작 원리

  • 컴포저블 함수는 항상 실제 값으로 호출
  • 컴포즈 UI를 업데이트 하는 일련의 과정을 재구성이라 부름.

재구성

  • UI의 일부인 컴포저블 함수가 업데이트돼야 할 때마다 자동으로 발생
  • UI의 모습이나 행위에 영향을 주는 값 중 일부가 변경되는것이 해당
  • 잿팩 컴포즈가 UI 변경이 필요하다고 판단되는 값을 전달한다면 컴포즈 런타임은 변경이 일어나면 재구성 방식을 사용해 UI 업데이트를 수행할 것이다.
  • 시간이 지나면서 변경되는 값을 상태(State)라고 한다.
    • mutableStateOf()를 사용하면 상태를 생성할 수 있다.
    • 컴포저블 함수에서 상태를 참조하려면 함수에서 remember(기억) 해야 한다.

 

아키텍처 관점에서 설명

일반 적인 기능은 다음 사항을 포함

  • 화면의 위치와 크기
  • 배경과 같은 기본적인 시각적 측면
  • 간단한 사용자 상호작용(클릭에 반응)

안드로이드 뷰 시스템은 클래스 기반이기 때문에 부모 메서드를 재정의해 기능을 변경하게 된다.

반면

컴포저블 함수는 공유되는 프로퍼티가 존재하지 않는다.
@Composable 어노테이션을 함수에 추가하는 것으로 함수를 인지하게 할 수 있다.

  • 반환 타입을 명시하지 않는다는 점 외에 컴포저블 함수는 공통적인 부분이 거의 없는것 처럼 보인다.
    • 그러나 아키텍처의 관점의 판단일지도 모른다.

 

클릭 동작에 반응

잿팩 컴포즈는 두가지 방식으로 클릭 이벤트 처리를 제공
1. 클릭 이벤트 처리를 필요로 하는 컴포저블 함수는 전용 onClick매개변수를 갖는다

@Composable
@Preview
fun ButtonDemo() {
	Box {
		Button(onClick = {
			println("clicked")
		}) {
			Text("Click me!")
		}
	}
}

onClick이 필수

2. 변경자(modifier)로 수정할 수 있다.

modifier = Modifier.clickable { ...

 

UI 요소 크기 조절과 배치

  • Box() 는 FrameLayout과 유사
    • 박스 내부에서 위치는 contentAlignment로 제어
@Composable
@Preview
fun BoxDemo() {
	Box(contentAlignment = Alignment.Center) {
		Box(
			modifier = Modifier
				.size(width = 100.dp, height = 100.dp)
				.background(Color.Green)
		)
		Text(
			text = "Hello",
			color = Color.Black,
			modifier = Modifier.align(Alignment.Topstart)
		)
	}
}
  • Modifier.fillMaxSize() : 컴포저블 함수를 가능한 한 크게 만들어줌.

변경자는 체이닝이 가능하다.

  • 체이닝의 최상위는 Modifier 동반객체(companion object)

 

참조 : 젯팩 컴포즈로 개발하는 안드로이드 UI

반응형