Skip to content

Commit 96deaaa

Browse files
authored
Merge pull request #8 from DongChyeon/refactor/#7-graphicslayer-optimization
[Refactor/#7] Optimize recomposition using graphicsLayer
2 parents fd4b62f + 39791bd commit 96deaaa

File tree

1 file changed

+40
-18
lines changed
  • timepicker/src/main/java/com/dongchyeon/timepicker/ui

1 file changed

+40
-18
lines changed

timepicker/src/main/java/com/dongchyeon/timepicker/ui/PickerItem.kt

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@ import androidx.compose.foundation.layout.fillMaxWidth
77
import androidx.compose.foundation.layout.height
88
import androidx.compose.foundation.layout.padding
99
import androidx.compose.foundation.lazy.LazyColumn
10+
import androidx.compose.foundation.lazy.LazyListItemInfo
1011
import androidx.compose.material3.Text
1112
import androidx.compose.runtime.Composable
1213
import androidx.compose.runtime.LaunchedEffect
13-
import androidx.compose.runtime.derivedStateOf
1414
import androidx.compose.runtime.getValue
1515
import androidx.compose.runtime.mutableIntStateOf
1616
import androidx.compose.runtime.remember
17+
import androidx.compose.runtime.rememberUpdatedState
1718
import androidx.compose.runtime.setValue
1819
import androidx.compose.runtime.snapshotFlow
1920
import androidx.compose.ui.Alignment
@@ -104,6 +105,14 @@ internal fun <T> PickerItem(
104105
val totalItemHeight = itemHeightDp + style.itemSpacing
105106
val totalItemHeightPx = totalItemHeight.toPx()
106107

108+
val layoutInfo by rememberUpdatedState(listState.layoutInfo)
109+
110+
val itemInfoMap = remember(layoutInfo) {
111+
layoutInfo.visibleItemsInfo.associateBy { it.index }
112+
}
113+
114+
val viewportCenterOffset = layoutInfo.viewportStartOffset + (layoutInfo.viewportEndOffset - layoutInfo.viewportStartOffset) / 2
115+
107116
Box(modifier = modifier) {
108117
LazyColumn(
109118
state = listState,
@@ -115,20 +124,6 @@ internal fun <T> PickerItem(
115124
.pointerInput(Unit) { detectVerticalDragGestures { change, _ -> change.consume() } }
116125
) {
117126
items(listScrollCount, key = { index -> index }) { index ->
118-
val layoutInfo by remember { derivedStateOf { listState.layoutInfo } }
119-
120-
val viewportCenterOffset = layoutInfo.viewportStartOffset +
121-
(layoutInfo.viewportEndOffset - layoutInfo.viewportStartOffset) / 2
122-
123-
val itemInfo = layoutInfo.visibleItemsInfo.find { it.index == index }
124-
val itemCenterOffset = itemInfo?.offset?.let { it + (itemInfo.size / 2) } ?: 0
125-
126-
val distanceFromCenter = abs(viewportCenterOffset - itemCenterOffset).toFloat()
127-
val maxDistance = totalItemHeightPx * visibleItemsMiddle
128-
129-
val alpha = curveEffect.calculateAlpha(distanceFromCenter, maxDistance)
130-
val scaleY = curveEffect.calculateScaleY(distanceFromCenter, maxDistance)
131-
132127
val item = getItemForIndex(
133128
index = index,
134129
items = items,
@@ -140,11 +135,17 @@ internal fun <T> PickerItem(
140135
text = item?.let { itemFormatter(it) } ?: "",
141136
maxLines = 1,
142137
style = style.textStyle,
143-
color = style.textColor.copy(alpha = alpha),
138+
color = style.textColor,
144139
modifier = Modifier
145140
.padding(vertical = style.itemSpacing / 2)
146-
.graphicsLayer(scaleY = scaleY)
147-
.onSizeChanged { size -> itemHeightPixels = size.height }
141+
.curvedPickerEffect(
142+
index = index,
143+
viewportCenterOffset = viewportCenterOffset,
144+
itemInfoMap = itemInfoMap,
145+
totalItemHeightPx = totalItemHeightPx,
146+
visibleItemsMiddle = visibleItemsMiddle,
147+
curveEffect = curveEffect
148+
).onSizeChanged { size -> itemHeightPixels = size.height }
148149
.then(textModifier)
149150
)
150151
}
@@ -180,6 +181,27 @@ private fun getStartIndexForInfiniteScroll(
180181
return listScrollMiddle - listScrollMiddle % itemSize - visibleItemsMiddle + startIndex
181182
}
182183

184+
fun Modifier.curvedPickerEffect(
185+
index: Int,
186+
viewportCenterOffset: Int,
187+
itemInfoMap: Map<Int, LazyListItemInfo>,
188+
totalItemHeightPx: Float,
189+
visibleItemsMiddle: Int,
190+
curveEffect: CurveEffect
191+
): Modifier = graphicsLayer {
192+
val itemInfo = itemInfoMap[index]
193+
val itemCenterOffset = itemInfo?.let { it.offset + (it.size / 2) } ?: 0
194+
195+
val distanceFromCenter = abs(viewportCenterOffset - itemCenterOffset).toFloat()
196+
val maxDistance = totalItemHeightPx * visibleItemsMiddle
197+
198+
val alpha = curveEffect.calculateAlpha(distanceFromCenter, maxDistance)
199+
val scaleY = curveEffect.calculateScaleY(distanceFromCenter, maxDistance)
200+
201+
this.alpha = alpha
202+
this.scaleY = scaleY
203+
}
204+
183205
@Composable
184206
@Preview
185207
private fun PickerItemPreview() {

0 commit comments

Comments
 (0)