Skip to content

Commit 9077934

Browse files
authored
Revert "Change LazyListState to be scroll-aware (#2013)" (#2022)
* Revert "Restore visibility of firstIndex and lastIndex (#2019)" This reverts commit d7e8029. * Revert "Change LazyListState to be scroll-aware (#2013)" This reverts commit e918243.
1 parent bc0c23b commit 9077934

File tree

8 files changed

+31
-272
lines changed

8 files changed

+31
-272
lines changed

CHANGELOG.md

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ Changed:
1010
- Removed generated `typealias`es for package names which changed in 0.10.0.
1111
- In `UIViewLazyList`'s `UITableView`, adding special-case handling for programmatic scroll-to-top calls.
1212
- APIs accepting a `FileSystem` and `Path` now have the `FileSystem` coming before the `Path` in the parameter list. Compatibility functions are retained for this version, but will be removed in the next version.
13-
- Change `LazyListState` to be scroll-aware, reducing the size of the preload window while actively scrolling, and optimizing the preload window once the scroll has completed.
1413

1514
Fixed:
1615
- Work around a problem with our memory-leak fix where our old LazyList code would crash when its placeholders were unexpectedly removed.

redwood-lazylayout-compose/api/redwood-lazylayout-compose.api

+4-9
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,16 @@ public abstract interface class app/cash/redwood/lazylayout/compose/LazyListScop
2424
public class app/cash/redwood/lazylayout/compose/LazyListState {
2525
public static final field $stable I
2626
public fun <init> ()V
27-
public final fun getDefaultPreloadItemCount ()I
2827
public final fun getFirstIndex ()I
2928
public final fun getLastIndex ()I
30-
public final fun getPrimaryPreloadItemCount ()I
29+
public final fun getPreloadAfterItemCount ()I
30+
public final fun getPreloadBeforeItemCount ()I
3131
public final fun getProgrammaticScrollIndex ()Lapp/cash/redwood/lazylayout/api/ScrollItemIndex;
32-
public final fun getScrollInProgressPreloadItemCount ()I
33-
public final fun getSecondaryPreloadItemCount ()I
34-
public final fun loadRange (I)Lkotlin/ranges/IntRange;
3532
public final fun onUserScroll (II)V
3633
public final fun programmaticScroll (IZZ)V
3734
public static synthetic fun programmaticScroll$default (Lapp/cash/redwood/lazylayout/compose/LazyListState;IZZILjava/lang/Object;)V
38-
public final fun setDefaultPreloadItemCount (I)V
39-
public final fun setPrimaryPreloadItemCount (I)V
40-
public final fun setScrollInProgressPreloadItemCount (I)V
41-
public final fun setSecondaryPreloadItemCount (I)V
35+
public final fun setPreloadAfterItemCount (I)V
36+
public final fun setPreloadBeforeItemCount (I)V
4237
}
4338

4439
public final class app/cash/redwood/lazylayout/compose/LazyListStateKt {

redwood-lazylayout-compose/api/redwood-lazylayout-compose.klib.api

+6-13
Original file line numberDiff line numberDiff line change
@@ -32,25 +32,18 @@ open annotation class app.cash.redwood.lazylayout.compose/ExperimentalRedwoodLaz
3232
}
3333
open class app.cash.redwood.lazylayout.compose/LazyListState { // app.cash.redwood.lazylayout.compose/LazyListState|null[0]
3434
constructor <init>() // app.cash.redwood.lazylayout.compose/LazyListState.<init>|<init>(){}[0]
35-
final fun loadRange(kotlin/Int): kotlin.ranges/IntRange // app.cash.redwood.lazylayout.compose/LazyListState.loadRange|loadRange(kotlin.Int){}[0]
3635
final fun onUserScroll(kotlin/Int, kotlin/Int) // app.cash.redwood.lazylayout.compose/LazyListState.onUserScroll|onUserScroll(kotlin.Int;kotlin.Int){}[0]
3736
final fun programmaticScroll(kotlin/Int, kotlin/Boolean, kotlin/Boolean =...) // app.cash.redwood.lazylayout.compose/LazyListState.programmaticScroll|programmaticScroll(kotlin.Int;kotlin.Boolean;kotlin.Boolean){}[0]
38-
final var defaultPreloadItemCount // app.cash.redwood.lazylayout.compose/LazyListState.defaultPreloadItemCount|{}defaultPreloadItemCount[0]
39-
final fun <get-defaultPreloadItemCount>(): kotlin/Int // app.cash.redwood.lazylayout.compose/LazyListState.defaultPreloadItemCount.<get-defaultPreloadItemCount>|<get-defaultPreloadItemCount>(){}[0]
40-
final fun <set-defaultPreloadItemCount>(kotlin/Int) // app.cash.redwood.lazylayout.compose/LazyListState.defaultPreloadItemCount.<set-defaultPreloadItemCount>|<set-defaultPreloadItemCount>(kotlin.Int){}[0]
4137
final var firstIndex // app.cash.redwood.lazylayout.compose/LazyListState.firstIndex|<get-firstIndex>(){}[0]
4238
final fun <get-firstIndex>(): kotlin/Int // app.cash.redwood.lazylayout.compose/LazyListState.firstIndex.<get-firstIndex>|<get-firstIndex>(){}[0]
4339
final var lastIndex // app.cash.redwood.lazylayout.compose/LazyListState.lastIndex|{}lastIndex[0]
4440
final fun <get-lastIndex>(): kotlin/Int // app.cash.redwood.lazylayout.compose/LazyListState.lastIndex.<get-lastIndex>|<get-lastIndex>(){}[0]
45-
final var primaryPreloadItemCount // app.cash.redwood.lazylayout.compose/LazyListState.primaryPreloadItemCount|{}primaryPreloadItemCount[0]
46-
final fun <get-primaryPreloadItemCount>(): kotlin/Int // app.cash.redwood.lazylayout.compose/LazyListState.primaryPreloadItemCount.<get-primaryPreloadItemCount>|<get-primaryPreloadItemCount>(){}[0]
47-
final fun <set-primaryPreloadItemCount>(kotlin/Int) // app.cash.redwood.lazylayout.compose/LazyListState.primaryPreloadItemCount.<set-primaryPreloadItemCount>|<set-primaryPreloadItemCount>(kotlin.Int){}[0]
41+
final var preloadAfterItemCount // app.cash.redwood.lazylayout.compose/LazyListState.preloadAfterItemCount|{}preloadAfterItemCount[0]
42+
final fun <get-preloadAfterItemCount>(): kotlin/Int // app.cash.redwood.lazylayout.compose/LazyListState.preloadAfterItemCount.<get-preloadAfterItemCount>|<get-preloadAfterItemCount>(){}[0]
43+
final fun <set-preloadAfterItemCount>(kotlin/Int) // app.cash.redwood.lazylayout.compose/LazyListState.preloadAfterItemCount.<set-preloadAfterItemCount>|<set-preloadAfterItemCount>(kotlin.Int){}[0]
44+
final var preloadBeforeItemCount // app.cash.redwood.lazylayout.compose/LazyListState.preloadBeforeItemCount|{}preloadBeforeItemCount[0]
45+
final fun <get-preloadBeforeItemCount>(): kotlin/Int // app.cash.redwood.lazylayout.compose/LazyListState.preloadBeforeItemCount.<get-preloadBeforeItemCount>|<get-preloadBeforeItemCount>(){}[0]
46+
final fun <set-preloadBeforeItemCount>(kotlin/Int) // app.cash.redwood.lazylayout.compose/LazyListState.preloadBeforeItemCount.<set-preloadBeforeItemCount>|<set-preloadBeforeItemCount>(kotlin.Int){}[0]
4847
final var programmaticScrollIndex // app.cash.redwood.lazylayout.compose/LazyListState.programmaticScrollIndex|{}programmaticScrollIndex[0]
4948
final fun <get-programmaticScrollIndex>(): app.cash.redwood.lazylayout.api/ScrollItemIndex // app.cash.redwood.lazylayout.compose/LazyListState.programmaticScrollIndex.<get-programmaticScrollIndex>|<get-programmaticScrollIndex>(){}[0]
50-
final var scrollInProgressPreloadItemCount // app.cash.redwood.lazylayout.compose/LazyListState.scrollInProgressPreloadItemCount|{}scrollInProgressPreloadItemCount[0]
51-
final fun <get-scrollInProgressPreloadItemCount>(): kotlin/Int // app.cash.redwood.lazylayout.compose/LazyListState.scrollInProgressPreloadItemCount.<get-scrollInProgressPreloadItemCount>|<get-scrollInProgressPreloadItemCount>(){}[0]
52-
final fun <set-scrollInProgressPreloadItemCount>(kotlin/Int) // app.cash.redwood.lazylayout.compose/LazyListState.scrollInProgressPreloadItemCount.<set-scrollInProgressPreloadItemCount>|<set-scrollInProgressPreloadItemCount>(kotlin.Int){}[0]
53-
final var secondaryPreloadItemCount // app.cash.redwood.lazylayout.compose/LazyListState.secondaryPreloadItemCount|{}secondaryPreloadItemCount[0]
54-
final fun <get-secondaryPreloadItemCount>(): kotlin/Int // app.cash.redwood.lazylayout.compose/LazyListState.secondaryPreloadItemCount.<get-secondaryPreloadItemCount>|<get-secondaryPreloadItemCount>(){}[0]
55-
final fun <set-secondaryPreloadItemCount>(kotlin/Int) // app.cash.redwood.lazylayout.compose/LazyListState.secondaryPreloadItemCount.<set-secondaryPreloadItemCount>|<set-secondaryPreloadItemCount>(kotlin.Int){}[0]
5649
}

redwood-lazylayout-compose/src/commonMain/kotlin/app/cash/redwood/lazylayout/compose/LazyList.kt

+10-8
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,16 @@ internal fun LazyList(
3939
) {
4040
val itemProvider = rememberLazyListItemProvider(content)
4141
val itemCount = itemProvider.itemCount
42-
val loadRange = state.loadRange(itemCount)
42+
val itemsBefore = (state.firstIndex - state.preloadBeforeItemCount).coerceAtLeast(0)
43+
val itemsAfter = (itemCount - (state.lastIndex + state.preloadAfterItemCount).coerceAtMost(itemCount)).coerceAtLeast(0)
4344
val placeholderPoolSize = 20
4445
LazyList(
4546
isVertical = isVertical,
4647
onViewportChanged = { localFirstVisibleItemIndex, localLastVisibleItemIndex ->
4748
state.onUserScroll(localFirstVisibleItemIndex, localLastVisibleItemIndex)
4849
},
49-
itemsBefore = loadRange.first,
50-
itemsAfter = itemCount - loadRange.count() - loadRange.first,
50+
itemsBefore = itemsBefore,
51+
itemsAfter = itemsAfter,
5152
width = width,
5253
height = height,
5354
margin = margin,
@@ -56,7 +57,7 @@ internal fun LazyList(
5657
scrollItemIndex = state.programmaticScrollIndex,
5758
placeholder = { repeat(placeholderPoolSize) { placeholder() } },
5859
items = {
59-
for (index in loadRange) {
60+
for (index in itemsBefore until itemCount - itemsAfter) {
6061
key(index) {
6162
itemProvider.Item(index)
6263
}
@@ -82,12 +83,13 @@ internal fun RefreshableLazyList(
8283
) {
8384
val itemProvider = rememberLazyListItemProvider(content)
8485
val itemCount = itemProvider.itemCount
85-
val loadRange = state.loadRange(itemCount)
86+
val itemsBefore = (state.firstIndex - state.preloadBeforeItemCount).coerceAtLeast(0)
87+
val itemsAfter = (itemCount - (state.lastIndex + state.preloadAfterItemCount).coerceAtMost(itemCount)).coerceAtLeast(0)
8688
val placeholderPoolSize = 20
8789
RefreshableLazyList(
8890
isVertical,
89-
itemsBefore = loadRange.first,
90-
itemsAfter = itemCount - loadRange.count() - loadRange.first,
91+
itemsBefore = itemsBefore,
92+
itemsAfter = itemsAfter,
9193
onViewportChanged = { localFirstVisibleItemIndex, localLastVisibleItemIndex ->
9294
state.onUserScroll(localFirstVisibleItemIndex, localLastVisibleItemIndex)
9395
},
@@ -102,7 +104,7 @@ internal fun RefreshableLazyList(
102104
placeholder = { repeat(placeholderPoolSize) { placeholder() } },
103105
pullRefreshContentColor = pullRefreshContentColor,
104106
items = {
105-
for (index in loadRange) {
107+
for (index in itemsBefore until itemCount - itemsAfter) {
106108
key(index) {
107109
itemProvider.Item(index)
108110
}

redwood-lazylayout-compose/src/commonMain/kotlin/app/cash/redwood/lazylayout/compose/LazyListState.kt

+4-66
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,6 @@ import androidx.compose.runtime.setValue
2525
import app.cash.redwood.lazylayout.api.ScrollItemIndex
2626

2727
private const val DEFAULT_PRELOAD_ITEM_COUNT = 15
28-
private const val SCROLL_IN_PROGRESS_PRELOAD_ITEM_COUNT = 5
29-
private const val PRIMARY_PRELOAD_ITEM_COUNT = 20
30-
private const val SECONDARY_PRELOAD_ITEM_COUNT = 10
31-
32-
private const val DEFAULT_SCROLL_INDEX = -1
3328

3429
/**
3530
* Creates a [LazyListState] that is remembered across compositions.
@@ -75,15 +70,11 @@ public open class LazyListState {
7570
public var lastIndex: Int by mutableIntStateOf(0)
7671
private set
7772

78-
internal var preloadItems: Boolean = true
79-
80-
public var defaultPreloadItemCount: Int = DEFAULT_PRELOAD_ITEM_COUNT
81-
public var scrollInProgressPreloadItemCount: Int = SCROLL_IN_PROGRESS_PRELOAD_ITEM_COUNT
82-
public var primaryPreloadItemCount: Int = PRIMARY_PRELOAD_ITEM_COUNT
83-
public var secondaryPreloadItemCount: Int = SECONDARY_PRELOAD_ITEM_COUNT
73+
/** How many items to load in anticipation of scrolling up. */
74+
public var preloadBeforeItemCount: Int by mutableIntStateOf(DEFAULT_PRELOAD_ITEM_COUNT)
8475

85-
private var firstIndexFromPrevious1: Int by mutableIntStateOf(DEFAULT_SCROLL_INDEX)
86-
private var firstIndexFromPrevious2: Int by mutableIntStateOf(DEFAULT_SCROLL_INDEX)
76+
/** How many items to load in anticipation of scrolling down. */
77+
public var preloadAfterItemCount: Int by mutableIntStateOf(DEFAULT_PRELOAD_ITEM_COUNT)
8778

8879
/** Perform a programmatic scroll. */
8980
public fun programmaticScroll(
@@ -115,57 +106,4 @@ public open class LazyListState {
115106
this.firstIndex = firstIndex
116107
this.lastIndex = lastIndex
117108
}
118-
119-
public fun loadRange(itemCount: Int): IntRange {
120-
val preloadBeforeItemCount: Int
121-
val preloadAfterItemCount: Int
122-
123-
when {
124-
// Ignore preloads.
125-
!preloadItems -> {
126-
preloadBeforeItemCount = 0
127-
preloadAfterItemCount = 0
128-
}
129-
130-
// Scrolling down.
131-
firstIndexFromPrevious1 != DEFAULT_SCROLL_INDEX && firstIndexFromPrevious1 < firstIndex -> {
132-
preloadBeforeItemCount = 0
133-
preloadAfterItemCount = scrollInProgressPreloadItemCount
134-
}
135-
136-
// Scrolling up.
137-
firstIndexFromPrevious1 != DEFAULT_SCROLL_INDEX && firstIndexFromPrevious1 > firstIndex -> {
138-
preloadBeforeItemCount = scrollInProgressPreloadItemCount
139-
preloadAfterItemCount = 0
140-
}
141-
142-
// Stopped scrolling down.
143-
firstIndexFromPrevious2 != DEFAULT_SCROLL_INDEX && firstIndexFromPrevious2 < firstIndex -> {
144-
preloadBeforeItemCount = secondaryPreloadItemCount
145-
preloadAfterItemCount = primaryPreloadItemCount
146-
}
147-
148-
// Stopped scrolling up.
149-
firstIndexFromPrevious2 != DEFAULT_SCROLL_INDEX && firstIndexFromPrevious2 > firstIndex -> {
150-
preloadBeforeItemCount = primaryPreloadItemCount
151-
preloadAfterItemCount = secondaryPreloadItemCount
152-
}
153-
154-
// New.
155-
else -> {
156-
preloadBeforeItemCount = defaultPreloadItemCount
157-
preloadAfterItemCount = defaultPreloadItemCount
158-
}
159-
}
160-
161-
// TODO(dylan+jwilson): If we're contiguous with our previous loaded range,
162-
// don't rush to remove things from the previous range.
163-
val begin = (firstIndex - preloadBeforeItemCount).coerceAtLeast(0)
164-
val end = (lastIndex + preloadAfterItemCount).coerceAtMost(itemCount).coerceAtLeast(0)
165-
166-
this.firstIndexFromPrevious2 = firstIndexFromPrevious1
167-
this.firstIndexFromPrevious1 = firstIndex
168-
169-
return begin until end
170-
}
171109
}

redwood-lazylayout-compose/src/commonTest/kotlin/app/cash/redwood/lazylayout/compose/LazyListTest.kt

+5-4
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,12 @@ class LazyListTest {
101101

102102
with(awaitSnapshot()) {
103103
val lazyList = single() as LazyListValue
104-
assertThat(lazyList.itemsBefore).isEqualTo(50)
105-
assertThat(lazyList.itemsAfter).isEqualTo(35)
104+
assertThat(lazyList.itemsBefore).isEqualTo(35)
105+
assertThat(lazyList.itemsAfter).isEqualTo(25)
106106
assertThat(lazyList.placeholder)
107107
.isEqualTo(List(20) { TextValue(Modifier, "Placeholder") })
108108
assertThat(lazyList.items)
109-
.isEqualTo(List(15) { TextValue(Modifier, (it + 50).toString()) })
109+
.isEqualTo(List(40) { TextValue(Modifier, (it + 35).toString()) })
110110
}
111111
}
112112
}
@@ -117,7 +117,8 @@ class LazyListTest {
117117
var index5ComposeCount = 0
118118
setContent {
119119
val lazyListState = rememberLazyListState().apply {
120-
preloadItems = false
120+
preloadBeforeItemCount = 0
121+
preloadAfterItemCount = 0
121122
}
122123
LazyColumn(
123124
state = lazyListState,

0 commit comments

Comments
 (0)