Jetpack Compose의 ConstraintLayout은 UI 요소들을 배치하는 데 사용되는 도구로 XML을 사용하는 대신에 코드로 UI를 작성할 수 있다. ConstraintLayout을 사용하여 UI 요소들의 위치, 크기, 간격을 선언적으로 정의할 수 있어 유연하고 반응형인 UI를 쉽게 만들 수 있다.
@Composable
fun ConstraintLayoutEx() {
// ConstraintLayout을 생성하고 전체 공간을 채우는 Modifier를 적용한다.
ConstraintLayout(modifier = Modifier.fillMaxSize()) {
// ConstraintLayout 내에 사용할 여러 개의 UI 요소에 대한 참조를 생성한다.
val (redBox, magentaBox, greenBox, yellowBox) = createRefs()
// 부모 ConstraintLayout의 바닥과 오른쪽 끝에 배치
Box(
modifier = Modifier
.size(40.dp)
.background(Color.Red)
.constrainAs(redBox) {
bottom.linkTo(parent.bottom, margin = 8.dp)
end.linkTo(parent.end, margin = 4.dp)
}
)
// 부모 ConstraintLayout의 양쪽 끝에 배치
Box(
modifier = Modifier
.size(40.dp)
.background(Color.Magenta)
.constrainAs(magentaBox) {
start.linkTo(parent.start)
end.linkTo(parent.end)
}
)
// 부모 ConstraintLayout의 가운데에 배치
Box(
modifier = Modifier
.size(40.dp)
.background(Color.Green)
.constrainAs(greenBox) {
centerTo(parent)
}
)
// magentaBox 오른쪽 아래에 배치
Box(
modifier = Modifier
.size(40.dp)
.background(Color.Yellow)
.constrainAs(yellowBox) {
start.linkTo(magentaBox.end)
top.linkTo(magentaBox.bottom)
}
)
}
}
createRefs()는 ConstraintLayout에서 사용되는 확장 함수로, 여러 개의 UI에 대한 참조를 생성하며 각 UI 요소에 대한 참조를 담은 Ref 객체를 반환한다.
이렇게 반환 된 Ref 객체들은 각각의 UI 요소에 대한 참조를 가지고 있으며, 이를 통해 해당 UI 요소들을 ConstraintLayout에서 내에서 배치할 때 사용할 수 있다.
constrainAs() 함수는 ConstraintLayout에서 사용되며, UI 요소를 부모 ConstraintLayout 내에서의 위치 및 크기를 지정하는 데 사용된다.
- 이 함수는 UI 요소에 대한 제약 조건을 설정한다.
start
,end
,top
,bottom
을 사용하여 UI 요소를 부모의 특정 위치에 링크시킬 수 있다.- 다른 UI 요소의
start
,end
,top
,bottom
에 링크하여 UI 요소 간의 상대적인 위치를 정의할 수 있다.- UI 요소와 제약 조건 사이에 마진을 추가하여 간격을 조절할 수 있으며, 이는 UI 요소 간의 간격을 조절하거나 UI 요소와 부모 간의 여백을 추가하는 데 사용된다.
ConstraintLayout 내에서 각 UI 요소의 제약 조건을 별도로 정의하고, 그 제약 조건을 사용하여 UI를 배치하여 UI의 구조와 제약 조건을 분리하여 모듈화하고 재사용할 수 있으며 가독성이 향상 된다.
@Composable
fun ConstraintSetEx() {
/*
* ConstraintSet를 생성하고 각 UI 요소에 대한 제약 조건을 정의한다.
* 각 UI 요소에 대해 createRefFor() 함수를 사용하여 참조를 생성하고.
* constrain()를 사용하여 해당 UI 요소의 제약 조건을 설정한다.
*/
val constraintSet = ConstraintSet {
val redBox = createRefFor("redBox")
val magentaBox = createRefFor("magentaBox")
val greenBox = createRefFor("greenBox")
val yellowBox = createRefFor("yellowBox")
constrain(redBox) {
bottom.linkTo(parent.bottom, margin = 10.dp)
end.linkTo(parent.end, margin = 30.dp)
}
constrain(magentaBox) {
start.linkTo(parent.start, margin = 10.dp)
end.linkTo(parent.end, margin = 30.dp)
}
constrain(greenBox) {
centerTo(parent)
}
constrain(yellowBox) {
start.linkTo(magentaBox.end)
top.linkTo(magentaBox.bottom)
}
}
/*
* constraintSet 매개변수를 통해 UI 요소들의 위치를 설정하며,
* 각 UI 요소는 layoutId를 사용하여 constraintSet에 지정한 참조와 연결된다.
*/
ConstraintLayout(
constraintSet = constraintSet,
modifier = Modifier.fillMaxSize()) {
Box(
modifier = Modifier
.size(40.dp)
.background(Color.Red)
.layoutId("redBox")
)
Box(
modifier = Modifier
.size(40.dp)
.background(Color.Magenta)
.layoutId("magentaBox")
)
Box(
modifier = Modifier
.size(40.dp)
.background(Color.Green)
.layoutId("greenBox")
)
Box(
modifier = Modifier
.size(40.dp)
.background(Color.Yellow)
.layoutId("yellowBox")
)
}
}
createRefFor() 함수는 ConstraintSet 내에서 UI 요소에 대한 참조를 생성하는 데 사용된다.
val redBox = createRefFor("redBox")
redBox는 UI 요소에 대한 식별자이며, 이러한 식별자를 사용하여 constrain() 함수 등에서 해당 UI 요소에 대한 제약 조건을 설정할 수 있다.
constrain() 함수는 ConstraintSet에서 UI 요소의 제약 조건을 설정하는 데 사용되며, UI 요소의 위치, 크기, 여백 등을 지정할 수 있다.
- constrainAs()와 constrain()
- 두 함수 모두 UI 요소의 제약 조건을 설정하는 데 사용된다.
- constrain()는 주로 제약 조건 자체를 설정하는 데에 중점을 두고 있고, constrainAs()는 주로 UI 요소의 위치와 크기를 지정하는 데에 중점을 두고 있다.
- createVerticalChain
- 여러 개의 UI 요소를 세로 방향으로 연결하여 체인을 형성한다.
- 체인을 형성할 때, 각 요소들 간의 상대적인 위치 및 간격을 설정할 수 있다.
- createHorizontalChain
- 여러 개의 UI 요소를 가로 방향으로 연결하여 체인을 형성한다.
- 각 요소들 간의 상대적인 위치 및 간격을 설정할 수 있다.
- ChainStyle
- ChainStyle.Packed : 각 요소들 사이의 간격이 최소화된다.
- ChainStyle.Spread : 각 요소들 사이의 간격이 균등하게 분산된다.
- ChainStyle.SpreadInsid : 각 요소들 사이의 간격이 균등하게 분산되지만, 체인의 첫 번째 요소와 체인의 시작 부분 사이, 그리고 마지막 요소와 체인의 끝 부분 사이에는 간격이 생길 수 있다.
@Composable
fun ConstraintLayoutEx() {
ConstraintLayout(modifier = Modifier.fillMaxSize()) {
val (redBox, magentaBox, greenBox, text) = createRefs()
Box(
modifier = Modifier
.size(40.dp)
.background(Color.Red)
.constrainAs(redBox) {
top.linkTo(parent.top, margin = 18.dp)
}
)
Box(
modifier = Modifier
.size(40.dp)
.background(Color.Magenta)
.constrainAs(magentaBox) {
top.linkTo(parent.top, margin = 32.dp)
}
)
Box(
modifier = Modifier
.size(40.dp)
.background(Color.Green)
.constrainAs(greenBox) {
top.linkTo(parent.top, margin = 20.dp)
}
)
// createVerticalChain(redBox, magentaBox, greenBox)
// createHorizontalChain(redBox, magentaBox, greenBox)
// createHorizontalChain(redBox, magentaBox, greenBox, chainStyle = ChainStyle.Packed)
// createHorizontalChain(redBox, magentaBox, greenBox, chainStyle = ChainStyle.Spread)
createHorizontalChain(redBox, magentaBox, greenBox, chainStyle = ChainStyle.SpreadInside)
// val barrier = createTopBarrier(redBox, magentaBox, greenBox)
val barrier = createBottomBarrier(redBox, magentaBox, greenBox)
Text(
text = "세 개의 박스 중 가장 아래에 배치되어 있는 박스 밑에 텍스트 출력",
modifier = Modifier.constrainAs(text) {
top.linkTo(barrier)
}
)
}
}
createTopBarrier : 여러 UI 요소들의 상단 경계를 생성하며, 생성된 barrier는 이러한 요소들 중 가장 상단에 있는 요소의 상단 경계에 맞춰진다.
createBottomBarrier : 여러 UI 요소들의 하단 경계를 생성하며, 생성된 barrier는 이러한 요소들 중 가장 하단에 있는 요소의 하단 경계에 맞춰진다.