TsvrcList
Tsvrc.UI.TsvrcList is a pooled, paginated list view: it instantiates one
ListItem per visible row rather than one per data entry, so a list backed
by thousands of rows only ever pays for however many are on screen at once. Its generated
shadow is TsList. Local-only and unsynced: each client's own list state is independent.
See Build a paginated list UI for a task-oriented
walkthrough.
Setup
Wire up in the inspector: _itemContainer (typically a ScrollRect's Content transform)
and _itemPrefab (a prefab carrying a ListItem component). Set _pageSize to a positive
number to paginate, or -1 to load every item on one page with no pagination at all.
Usage
list.SetData(dataList); // a VRC.SDK3.Data.DataList of DataDictionary entries
The list is always in one of three states, read via ListState: STATE_LOADING,
STATE_EMPTY, or STATE_POPULATED. SetData resets to the first page and picks between the
latter two based on what it's given: STATE_EMPTY if called with null or a zero-length
list (shows the empty indicator), STATE_POPULATED otherwise (rebuilds the item pool for the
current page). SetData never enters STATE_LOADING; only SetLoadingState() does that,
destroying all live items and showing the loading indicator if one is wired up.
SelectedIndex, CurrentPage, and
PageCount are all readable, along with HasNextPage/HasPreviousPage for wiring up
pagination controls (NextPage()/PreviousPage() call SetPage for you, and are no-ops at
either end of the range).
Each list entry is expected to be a DataDictionary token; a non-dictionary entry at a given
index is silently treated as an empty dictionary rather than causing an error, so a
ListItem's _OnBind override should be written defensively against missing keys either
way.
Selection
A ListItem calls back into OnItemSelected(dataIndex) when pressed.
TsvrcList records the index and emits OnItemSelectedEvent via TsEmit, so anything
elsewhere in your world can subscribe via TsSubscribe rather than needing a direct
reference to the specific pressed item. ClearSelection() resets SelectedIndex to -1
without touching anything else.
Pool rebuild behavior
SetPage, SetData, and SetLoadingState all destroy every currently-live ListItem
(calling Unbind() on each first) before creating whatever the new state needs. There's no
attempt to diff and reuse items across a page change or state transition. This keeps the
pooling logic simple at the cost of a full rebuild on every page turn; if a prefab's
_OnBind/_OnUnbind are expensive, that cost is paid on every page change, not just once.
A prefab instance that comes back from Instantiate without a ListItem component attached
is destroyed immediately and skipped, rather than left in the pool in a broken state.