개발 공부/안드로이드

[Compose] 컴포즈 공부하기5 - ConstraintLayout 2

yong_DD 2023. 9. 6. 17:28

기본적인 사용법에 이어 이번엔 chain과 barrier에 대해 알아보자!

 

1. Chain

chain에 대한 자세한 설명은 여기를 클릭

그림1

constraintLayout의 기능 중 하나로 chain 기능이 있다.

이것을 compose로 구현해 보자!

 

ConstraintLayout(Modifier.size(60.dp)) {
    val (box1, box2, box3) = createRefs()

    Box(
        modifier = Modifier
            .size(10.dp)
            .background(Color.Red)
            .constrainAs(box1) {
                top.linkTo(parent.top)
            }
    )

    Box(
        modifier = Modifier
            .size(10.dp)
            .background(Color.Yellow)
            .constrainAs(box2) {
                top.linkTo(parent.top)
            }
    )

    Box(
        modifier = Modifier
            .size(10.dp)
            .background(Color.Green)
            .constrainAs(box3) {
                top.linkTo(parent.top)
            }
    )
    createHorizontalChain(box1, box2, box3)
    createVerticalChain(box1, box2, box3)
 }

               createHorizontalChain                                                  createVerticalChain                                   createHorizontalChain + createVerticalChain

 

compose에서는 createHorizontalChain, createVerticalChain을 통해 만들어줘야 한다.

그리고 ChainStyle을 지정해 그림 1과 같이 만들 수 있다.

ChainStyle의 값은 아래와 같이 있다.

@Immutable
class ChainStyle internal constructor(
    internal val style: SolverChain,
    internal val bias: Float? = null
) {
    companion object {
        /**
         * A chain style that evenly distributes the contained layouts.
         */
        @Stable
        val Spread = ChainStyle(SolverChain.SPREAD)

        /**
         * A chain style where the first and last layouts are affixed to the constraints
         * on each end of the chain and the rest are evenly distributed.
         */
        @Stable
        val SpreadInside = ChainStyle(SolverChain.SPREAD_INSIDE)

        /**
         * A chain style where the contained layouts are packed together and placed to the
         * center of the available space.
         */
        @Stable
        val Packed = Packed(0.5f)

        /**
         * A chain style where the contained layouts are packed together and placed in
         * the available space according to a given [bias].
         */
        @Stable
        fun Packed(bias: Float) = ChainStyle(SolverChain.PACKED, bias)
    }
}

 

      Box(
            modifier = Modifier
                .size(10.dp)
                .background(Color.Red)
                .constrainAs(box1) {
                    top.linkTo(parent.top)
                    start.linkTo(parent.start)
                }
        )

        Box(
            modifier = Modifier
                .size(10.dp)
                .background(Color.Yellow)
                .constrainAs(box2) {
                    start.linkTo(box1.end)
                }
        )

        Box(
            modifier = Modifier
                .size(10.dp)
                .background(Color.Green)
                .constrainAs(box3) {
                    start.linkTo(box2.start)
                }
        )
        createHorizontalChain(box1, box2, box3, chainStyle = ChainStyle.SpreadInside)

코드 1을 위와 같이 수정하여 사용할 수 있다.

createHorizontalChain에 chainStyle을 넣어 사용한다.

 

 spread                                                                spreadInside                                                                        packed

 

 

2. Barrier

여러 컴포저블을 참고하여 가장 극단적인 위젯을 기반으로 가상 가이드라인을 만드는 것

createTopBarrier, createBottomBarrier, createEndBarrier, createStartBarrier를 사용

 

예를 들어 chain의 예시 사진 처럼 상자가 3개가 있고 top으로 부터 위치가 각각 다를 때 가장 아래의 box에 글을 추가하고 싶다면 어떻게 해야할까?

 

val (box1, box2, box3, text) = createRefs()

Box(
    modifier = Modifier
        .size(10.dp)
        .background(Color.Red)
        .constrainAs(box1) {
            top.linkTo(parent.top)
            start.linkTo(parent.start)
        }
)

Box(
    modifier = Modifier
        .size(10.dp)
        .background(Color.Yellow)
        .constrainAs(box2) {
            top.linkTo(parent.top, margin = 10.dp)
            start.linkTo(box1.end)
        }
)

Box(
    modifier = Modifier
        .size(10.dp)
        .background(Color.Green)
        .constrainAs(box3) {
            top.linkTo(parent.top, margin = 20.dp)
            start.linkTo(box2.start)
        }
)
createHorizontalChain(box1, box2, box3, chainStyle = ChainStyle.Spread)

val barrier = createBottomBarrier(box1, box2, box3)

Text(
    text = "여기가 최하단",
    fontSize = 10.sp,
    modifier = Modifier.constrainAs(text) {
        top.linkTo(barrier)
    }
)

코드 1을 이렇게 수정해보면 좌측의 사진처럼 나오게 된다.

 

글씨가 아래 부분에 나오기 때문에 createBottomBarrier를 통해 box1~3을 넣고 top에 각각 margin을 줘 값을 다르게 하면 가장 하단인 것을 찾아 그 아래에 barrier가 생기게 된다.

 

그 barrier를 Text의 top에 넣게 되면, box1~3의 위치가 변경됨에 따라 barrier의 위치도 바뀌므로 Text의 위치가 자동으로 바뀌게 된다!

 

이런식으로 top, start, end, bottom에 원하는 대로 barrier를 만들어 사용할 수 있다.

 

fun createBottomBarrier(
    vararg elements: ConstrainedLayoutReference,
    margin: Dp = 0.dp
): HorizontalAnchor {
    val id = createHelperId()
    tasks.add { state ->
        state.barrier(id, SolverDirection.BOTTOM).apply {
            add(*(elements.map { it.id }.toTypedArray()))
        }.margin(state.convertDimension(margin))
    }
    updateHelpersHashCode(15)
    elements.forEach { updateHelpersHashCode(it.hashCode()) }
    updateHelpersHashCode(margin.hashCode())
    return HorizontalAnchor(id, 0)
}

 

또한 Barrier에는 margin 값을 넣을 수 있기 때문에 원하는 대로 margin 값을 줄 수 있다.

 

val barrier = createBottomBarrier(box1, box2, box3, margin = 10.dp)

 

 


 

[참고 및 출처]

 

Compose의 ConstraintLayout  |  Jetpack Compose  |  Android Developers

Compose의 ConstraintLayout 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. ConstraintLayout은 화면에 다른 컴포저블을 기준으로 컴포저블을 배치할 수 있는 레이아웃

developer.android.com

 

ConstraintLayout  |  Android Developers

Stay organized with collections Save and categorize content based on your preferences. ConstraintLayout This package is part of the Android support library which is no longer maintained. The Constraint Layout support library has been superseded by the Andr

developer.android.com