Jetpack Compose로 첫 번째 및 마지막 항목 패딩 문제를 해결하기 위한 나의 접근 방식

16967 단어 jetpackcomposeandroid
편집: 스크린샷이 늘어나서 죄송합니다. 각각을 클릭하시면 정확한 비율로 보실 수 있습니다.

이 포스트에서는 내가 자주 접하는 문제를 해결하기 위한 접근 방식을 공유할 것입니다. 항목 자체와 부모 경계 사이에 동일한 간격을 가진 요소 목록입니다.

다음은 우리가 만들 뷰의 예입니다.



동일한 간격이 의미하는 바를 더 잘 시각화하기 위해 다음 공간을 강조 표시했습니다.




먼저 가장 간단한 방법이 작동하지 않는 이유를 설명하고 싶습니다. 다음은 가장 간단한 접근 방식을 고려한 코드입니다.

@Composable
fun ItemList() {
    Column(modifier = Modifier.padding(vertical = 8.dp)) {
        Item("Item 1")
        Item("Item 2")
        Item("Item 3")
        Item("Item 4")
    }
}

@Composable
fun Item(text: String) {
    Text(
        text = text,
        modifier = Modifier
            .fillMaxWidth()
            .padding(horizontal = 16.dp, vertical = 8.dp)
    )
}



보시다시피 Item 의 가로 패딩은 16.dp 입니다. ItemColumn 의 수직 패딩은 8.dp 입니다. 수직 패딩이 추가되어 결과적으로 모든 곳에 16.dp 공간이 생깁니다.

그러나 이 접근 방식에는 한 가지 큰 문제가 있습니다. 클릭할 수 있을 때 보기가 좋지 않습니다. Item 함수를 수정해 보겠습니다.

@Composable
fun Item(text: String) {
    Text(
        text = text,
        modifier = Modifier
            .fillMaxWidth()
            .clickable {  } // Add this line
            .padding(horizontal = 16.dp, vertical = 8.dp)
    )
}


이제 첫 번째 항목을 클릭해 보십시오.



보시다시피 클릭한 항목 위에 공백이 있습니다. 그것은 추하다. 이를 수정하려면 부모 패딩( Column )에서 자식 패딩( Item )으로 마이그레이션해야 합니다.

이것은 첫 번째 항목과 마지막 항목이 중앙 항목과 다른 수직 패딩을 가져야 함을 의미합니다. top 첫 번째 항목의 패딩은 16.dp 이어야 하며, 마지막 항목의 bottom 패딩에도 동일하게 적용됩니다. 다른 패딩은 8.dp 값으로 변경되지 않습니다.

몇 가지 가능한 접근 방식이 있습니다. index 함수에 인수로 Item를 전달할 수 있습니다. isFirstisLast 플래그를 전달할 수 있습니다. 패딩 값을 직접 전달할 수 있습니다. 이러한 접근 방식은 모두 유효하지만 제 개인적인 취향으로는 우아하지 않다고 생각합니다.

따라서 다른 접근 방식을 제안합니다. Modifier를 인수로 전달합니다.

다음은 최종 솔루션입니다.


@Composable
fun ItemList() {
    Column {
        Item("Item 1", modifier = Modifier.padding(top = 16.dp, bottom = 8.dp))
        Item("Item 2")
        Item("Item 3")
        Item("Item 4", modifier = Modifier.padding(top = 8.dp, bottom = 16.dp))
    }
}

@Composable
fun Item(text: String, modifier: Modifier = Modifier.padding(vertical = 8.dp)) {
    Text(
        text = text,
        modifier = Modifier
            .fillMaxWidth()
            .clickable {  }
            .padding(horizontal = 16.dp)
            .then(modifier)
    )
}


결과(첫 번째 항목을 클릭한 경우)는 다음과 같습니다.




여기서 중요한 것은 .then(modifier) 옵션을 사용했다는 것입니다. then 를 사용하는 대신 수정자가 다음과 같이 주입되면 어떤 일이 일어나는지 시도해 보는 것이 좋습니다.

modifier = modifier
    .fillMaxWidth()
    .clickable {  }
    .padding(horizontal = 16.dp)


스포일러: 수직 패딩이 적용되기 전에 적용되기 때문에clickable 클릭 시 강조 표시된 영역이 패딩을 덮지 않습니다.
그래서 수식어의 순서가 중요하고 then 함수가 유용한 이유입니다.

(선택 사항) 추가 리팩토링



코드에서 추상화 수준을 혼합하지 않는 것이 매우 중요하다고 생각합니다. 다음 코드는 추상화를 혼합하는 예입니다.

// Padding size is set in the parent function:
Item("Item 1", modifier = Modifier.padding(top = 16.dp, bottom = 8.dp))
// Padding size is set in the child function:
Item("Item 2")


따라서 다음과 같은 리팩토링 단계를 제안합니다.

먼저 패딩 값을 부모로 가져옵니다.

@Composable
fun ItemList() {
    Column {
        Item("Item 1", modifier = Modifier.padding(top = 16.dp, bottom = 8.dp))
        Item("Item 2", modifier = Modifier.padding(vertical = 8.dp))
        Item("Item 3", modifier = Modifier.padding(vertical = 8.dp))
        Item("Item 4", modifier = Modifier.padding(top = 8.dp, bottom = 16.dp))
    }
}


그런 다음 가독성을 높이고 코드 중복을 제거하는 도우미 함수를 만듭니다.

@Stable
private fun Modifier.firstElementPadding(padding: Dp) =
    padding(top = padding, bottom = padding / 2)

@Stable
private fun Modifier.middleElementPadding(padding: Dp) =
    padding(vertical = padding / 2)

@Stable
private fun Modifier.lastElementPadding(padding: Dp) =
    padding(top = padding / 2, bottom = padding)



Item("Item 1", modifier = Modifier.firstElementPadding(16.dp))
Item("Item 2", modifier = Modifier.middleElementPadding(16.dp))
Item("Item 3", modifier = Modifier.middleElementPadding(16.dp))
Item("Item 4", modifier = Modifier.lastElementPadding(16.dp))

좋은 웹페이지 즐겨찾기