Modifier를 사용하면 컴포저블을 꾸밀 수 있다. 동작, 모양을 변경하고, 접근성 레이블과 같은 정보를 추가하고, 사용자 입력을 처리하거나, 클릭, 스크롤, 드래그 또는 확대/축소 가능 항목을 만드는 것과 같은 고급 상호 작용을 추가할 수도 있다. Modifier는 일반 Kotlin 객체다. 변수에 할당하고 재사용할 수 있다. 여러 Modifier를 차례로 연결하여 구성할 수도 있다.

이전 섹션에서 본 프로필 레이아웃을 구현해보자.

MainActivity.kt 을 열고 다음 코드를 추가하자.

@Composable
fun PhotographerCard() {
    Column {
        Text("Alfred Sisley", fontWeight = FontWeight.Bold)
        // LocalContentAlpha 는 자식들의 투명도를 정의한다.
        CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
            Text("3 minutes ago", style = MaterialTheme.typography.body2)
        }
    }
}

@Preview
@Composable
fun PhotographerCardPreview() {
    LayoutsCodelabTheme {
        PhotographerCard()
    }
}

미리보기로 보면 다음과 같다.

중요 : setContent 내에서 사용되는 앱 테마는 프로젝트 이름에 의존적이다. 이 코드랩은 LayoutsCodelab이라는 프로젝트로 가정한다. 만약 코드를 복사-붙여넣기 하는 경우, LayoutsCodelabTheme을 ui/Theme.kt 파일에 선언된 테마에 맞게 변경하는 것을 이지 말자.

Note: 코드 스니핏에서 CompositionLocalProvider 라는 것을 사용하고 있다. 이것은 컴포지션 트리에 암묵적으로 데이터를 전달한다. 이 경우 MaterialTheme에 의해 테마 계층에 선언된 중간 불투명도 수준인 ContentAlpha.medium에 접근한다.

사진이 로딩되는 동안, 플레이스홀더를 보여주기 위해 원 모양과 플레이스홀더 색상을 Surface를 사용하여 명시할 수 있다. 크기를 지정하기 위해 Modifier를 사용할 수 있다.

@Composable
fun PhotographerCard() {
    Row {
        Surface(
            modifier = Modifier.size(50.dp),
            shape = CircleShape,
            color = MaterialTheme.colors.onSurface.copy(alpha = 0.2f)
        ) {
            // Image goes here
        }
        Column {
            Text("Alfred Sisley", fontWeight = FontWeight.Bold)
            CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
                Text("3 minutes ago", style = MaterialTheme.typography.body2)
            }
        }
    }
}

여기서 두가지 정도 개선할 점이 있다.

  1. 플레이스홀더와 텍스트 사이 분리하기
  2. 텍스트를 수직-중앙 정렬 하기

#1을 위해서는 Modifier.padding을 Column에 사용하여 텍스트를 포함시키고, 약간의 공간을 컴포저블의 start에서 추가하여 이미지와 텍스트를 분리할 수 있다.

#2의 경우, 일부 레이아웃들에게 해당 레이아웃에만 적용할 수 있는 Modifier를 적용한다. 예를 들어, Row 내의 컴포저블들은 weight 또는 align 같이 의미가 있는 특정 Modifier에(Row 콘텐츠의 RowScope 리시버에서) 접근 할 수 있다. 이 범위 지정은 타입 안전성을 제공하므로 다른 레이아웃에서 의미가 없는 Modifier를 실수로 사용할 수 없다. 예를 들어 weight는 Box에서 의미가 없으므로 컴파일 타임에 오류가 방지된다.

Note: Modifier는 View 시스템의 XML 속성과 비슷한 역할을 한다. 하지만, 범위별 Modifier의 타입 안정성은 특정 레이아웃에만 적용 가능한지 발견하고 이해하는데 도움이 된다.

@Composable
fun PhotographerCard() {
    Row {
        Surface(
            modifier = Modifier.size(50.dp),
            shape = CircleShape,
            color = MaterialTheme.colors.onSurface.copy(alpha = 0.2f)
        ) {
            // Image goes here
        }
        Column(
            modifier = Modifier
                .padding(start = 8.dp)
                .align(Alignment.CenterVertically)
        ) {
            Text("Alfred Sisley", fontWeight = FontWeight.Bold)
            CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
                Text("3 minutes ago", style = MaterialTheme.typography.body2)
            }
        }
    }
}
Preview는 다음과 같다.

대부분의 컴포저블은 선택적으로 Modifier 매개변수를 사용하여 보다 유연하게 만들어 호출자가 수정할 수 있도록 한다. 자신만의 컴포저블을 생성하는 경우 Modifier를 매개변수로 사용하는 것을 고려하고 기본적으로 Modifier(즉, 아무 작업도 수행하지 않는 빈 Modifier)를 함수의 루트 컴포저블에 적용한다. 이 경우 코드는 다음과 같다.

@Composable
fun PhotographerCard(modifier: Modifier = Modifier) {
    Row(modifier) { ... }
}

Note: 규칙에 따라 Modifier는 함수의 첫번째 선택적 매개변수로 지정된다. 이렇게 하면 모든 매개변수의 이름을 지정할 필요 없이 컴포저블에 Modifier를 지정할 수 있다.

Modifier의 순서는 중요하다.

코드에서 factory-extension 함수를 사용하여 여러 Modifier를 차례로 연결하는 것을 확인할 수 있다.

순서가 중요하므로 Modifier를 체이닝 할 때 주의해야 한다. 체이닝 되는 Modifier들은 단일 인자로 연결되므로 순서가 최종 결과에 영향을 미친다.

만약 Photographer 프로필을 클릭 가능하게 만들고, 여백을 추가하려면 다음과 같이 코드를 작성하면 된다.

@Composable
fun PhotographerCard(modifier: Modifier = Modifier) {
    Row(modifier
        .padding(16.dp)
        .clickable(onClick = { /* onClick은 무시하자 */ })
    ) {
        ...
    }
}

코드를 실행하면 다음과 같다.

Note: 명시적인 순서는 다양한 Modifier가 상호 작용하는 방식을 추론하는데 도움이 된다. 박스 모델을 배워야 했던 View 시스템과 비교해보면, margin은 요소 “외부”에 적용되지만 padding은 “내부”와 배경 요소는 그에 따라 크기가 조정된다. Modifier 설계방식은 이 동작을 명시적이고 예측 가능하게 만들고, 원하는 정확한 동작을 달성하기 위해 더 많은 제어를 제공한다.

상상해보자! Modifier를 사용하면 매우 유연한 방식으로 컴포저블을 수정할 수 있다. 예를 들어 외부 간격을 추가하고, 컴포저블의 배경색을 변경하고, 행 모서리를 둥글게 만들고 싶다면 다음 코드를 사용할 수 있다.

@Composable
fun PhotographerCard(modifier: Modifier = Modifier) {
    Row(modifier
        .padding(8.dp)
        .clip(RoundedCornerShape(4.dp))
        .background(MaterialTheme.colors.surface)
        .clickable(onClick = { /* Ignoring onClick */ })
        .padding(16.dp)
    ) {
        ...
    }
}

대화형 preview 또는 에뮬레이터에서 확인해보자.

Modifier가 내부에서 작동하는 방식에 대해서는 나중에 자세히 살펴보도록 한다.

카테고리: Compose

0개의 댓글

답글 남기기

Avatar placeholder

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.