Skip to content

Commit

Permalink
Update UITableView to track changes precisely (#1538)
Browse files Browse the repository at this point in the history
* Update UITableView to track changes precisely

Previously we called reloadData() whenever anything changed
in the underlying model.

With this change we fire precise events to the UI when inserts
and removes happen in the source LazyList. This attempts to
coalesce changes to itemsBefore() and itemsAfter() with
adjacent changes and the beginning and end of the items list.
To implement this the changes are buffered into an intermediate
model before they are applied.

When a cell changes from being a placeholder to a loaded
item, or the opposite, this does a cell content change
without firing an event through the UITableView. To
implement this we must track which cells are currently
displaying placeholders. This PR includes a new datastructure,
SparseList, to implement this tracking.

This PR also changes the number of placeholders that
guest code offers to host code. I found experimentally
that 20 placeholders was not enough for UITableView.

This PR changes LazyList from UICollectionView to
UITableView. This change was potentially unnecessary,
though UITableView has fewer features that we don't
need.

* Restore accidentally-deleted file

* Restore some removed imports

* Address some PR feedback

* Address PR feedback
  • Loading branch information
squarejesse authored Oct 4, 2023
1 parent 585821a commit 6d9d398
Show file tree
Hide file tree
Showing 9 changed files with 1,527 additions and 108 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ internal fun LazyList(
val itemsBefore = remember(state.firstVisibleItemIndex) { (state.firstVisibleItemIndex - OffscreenItemsBufferCount / 2).coerceAtLeast(0) }
val itemsAfter = remember(lastVisibleItemIndex, itemProvider.itemCount) { (itemProvider.itemCount - (lastVisibleItemIndex + OffscreenItemsBufferCount / 2).coerceAtMost(itemProvider.itemCount)).coerceAtLeast(0) }
val scrollItemIndex = remember(state.scrollToItemTriggeredId) { ScrollItemIndex(state.scrollToItemTriggeredId, state.firstVisibleItemIndex) }
var placeholderPoolSize by remember { mutableStateOf(20) }
// TODO(jwilson): drop this down to 20 once this is fixed:
// https://github.com/cashapp/redwood/issues/1551
var placeholderPoolSize by remember { mutableStateOf(30) }
LazyList(
isVertical,
itemsBefore = itemsBefore,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class LazyListTest {
assertThat(snapshot)
.containsExactly(
DefaultLazyListValue.copy(
placeholder = List(20) { TextValue(Modifier, "Placeholder") },
placeholder = List(30) { TextValue(Modifier, "Placeholder") },
),
)
}
Expand Down Expand Up @@ -91,7 +91,7 @@ class LazyListTest {
.containsExactly(
DefaultLazyListValue.copy(
itemsAfter = expectedItemsAfter,
placeholder = List(20) { TextValue(Modifier, "Placeholder") },
placeholder = List(30) { TextValue(Modifier, "Placeholder") },
items = List(expectedItemCount) { TextValue(Modifier, it.toString()) },
),
)
Expand Down Expand Up @@ -124,7 +124,7 @@ class LazyListTest {
DefaultLazyListValue.copy(
itemsBefore = 35,
itemsAfter = 25,
placeholder = List(20) { TextValue(Modifier, "Placeholder") },
placeholder = List(30) { TextValue(Modifier, "Placeholder") },
items = List(40) { TextValue(Modifier, (it + 35).toString()) },
),
)
Expand Down
Loading

0 comments on commit 6d9d398

Please sign in to comment.