fun Modifier.topFadingEdge(
lazyListState : LazyListState,
length : Dp,
edgeColor : Color? = null
) = composed(
debugInspectorInfo {
name = "length"
value = length
}
){
val color = edgeColor ?: MaterialTheme.colorScheme.surface
drawWithContent {
val topFadingEdgeStrength by derivedStateOf {
lazyListState.layoutInfo.run {
val firstItem = visibleItemsInfo.first()
when {
visibleItemsInfo.size in 0..1 -> 0f
firstItem.index > 0 -> 1f
firstItem.offset == viewportStartOffset -> 0f
firstItem.offset < viewportStartOffset -> firstItem.run {
abs(offset) / size.toFloat()
}
else -> 1f
}
}.coerceAtMost(1f) * length.value
}
drawContent()
drawRect(
brush = Brush.verticalGradient(
colors = listOf(
color,
Color.Transparent,
),
startY = 0f,
endY = topFadingEdgeStrength,
),
size = Size(
this.size.width,
topFadingEdgeStrength
),
)
}
}
- drawWithContent: 기존의 컨텐츠와 함께 Fading Edge를 그리는 블록을 정의합니다.
- derivedStateOf: lazyListState를 기반으로 계산된 Top Fading Edge의 강도를 추출합니다.
- lazyListState.layoutInfo: LazyListState에 포함된 layoutInfo 속성으로부터 RecyclerView의 레이아웃 정보를 가져옵니다.
- visibleItemsInfo.first() : 현재 화면에 보이는 첫 번째 아이템의 정보를 가져옵니다.
- visibleItemsInfo.size in 0..1 : 현재 화면에 보이는 아이템이 0개 또는 1개일 경우, 즉 스크롤이 최상단에 위치할 경우 topFadingEdgeStrength는 0이 됩니다. (최상단에 아이템이 없거나 하나인 경우에는 페이딩 효과가 필요하지 않기 때문입니다.)
- firstItem.index > 0 : 첫 번째 아이템이 최상단이 아닌 경우, 즉 스크롤이 최상단에서 멀어졌을 경우 topFadingEdgeStrength는 1이 됩니다. (최상단에서 멀어질수록 페이딩 효과가 강해집니다.)
- firstItem.offset == viewportStartOffset : 첫 번째 아이템이 정확히 최상단에 위치한 경우, topFadingEdgeStrength는 0이 됩니다. (첫 번째 아이템이 정확히 최상단에 위치할 때도 페이딩 효과가 필요하지 않기 때문입니다.)
- firstItem.offset < viewportStartOffset : 첫 번째 아이템이 최상단보다 위에 위치한 경우, 즉 스크롤이 최상단에서 멀어진 경우 topFadingEdgeStrength는 abs(offset) / size.toFloat()를 통해 계산됩니다. 이 값은 스크롤이 최상단에서 멀어질수록 커집니다. (offset은 첫 번째 아이템이 최상단에서 멀어진 거리를 의미하며, size는 첫번 째 아이템의 전체 사이즈를 의미합니다.)
- 이렇게 계산된 topFadingEdgeStrength 값은 0부터 1까지의 범위를 갖기 때문에, length라는 Fading Edge의 길이와 곱해줌으로써 실제 Fading Edge의 높이를 결정합니다.
- drawContent: 기존의 컨텐츠를 그립니다.
- drawRect: Fading Edge를 그립니다. Brush.verticalGradient를 사용하여 그라데이션 효과를 적용하며, startY와 endY를 이용하여 Fading Edge의 강도를 지정합니다.