Quick List View Pro


A uGUI scrolling list that instantiates row objects only for the rows on screen. Variable heights with no pre-measure pass, and a report window that counts the work instead of promising it.


by Krykftn | Advanced Editor Tools & Systems


Price History +

A list of ten thousand items does not need ten thousand GameObjects. It needs as many as fit on screen. This is a uGUI list that builds exactly that many, and shows you the numbers while it does it.

WHAT IT DOES

Rows are instantiated only while they are visible. When one scrolls off, it goes back to a pool and comes out again as a different row. In the first sample scene - 50,000 rows, a 600-unit viewport - eleven GameObjects are ever created, and scrolling the whole list a second time creates none.

ROWS DO NOT HAVE TO BE THE SAME HEIGHT

And you do not have to know the heights in advance. Each row starts at an estimate you set. The first time it is built it is measured, and the running average of the measured rows becomes the estimate for the rows that have not been built yet, so the content size settles as the user scrolls.

If you already know your sizes, implement IListSizeSource and nothing is measured or corrected.

IT DOES NOT JUMP

When a row above the viewport turns out to be a different size than assumed, everything below it moves. The list adds that difference to the scroll position in the same frame, before anything draws, so the rows the user is reading stay exactly where they were.

THE REPORT WINDOW

Window > Analysis > Quick List View Report, or the Open report button on the component. Leave it open while you scroll.

It counts the work rather than describing it: objects ever created, times a row was reused, rows measured, updates that did nothing because the visible window had not moved, the largest number of rows any single update had to build, and managed bytes allocated inside the list's update. The allocation figure is read from the runtime; on a platform that does not report it, the window says so instead of showing a number.

IT ALSO READS YOUR SETUP

Most complaints about list performance are not about the list. A layout component quietly forcing a rebuild every frame costs more than the rows do, and it is findable by looking. So the window looks, and names what it finds:

• a layout group or ContentSizeFitter on the Content, which will fight the list every frame

• a ScrollRect that cannot scroll on the axis the list is set to

• a row prefab with a ContentSizeFitter but nothing that reports a preferred size, so every row collapses

• the list sharing a Canvas with the rest of the screen, so one row change re-batches everything

• a Viewport with nothing clipping it

• Movement Type set to Unrestricted

• an Estimated Row Size far from the measured average

• more than four raycast targets on one row

A correct setup produces no findings at all.

FOUR SAMPLE SCENES

• Rows: 50,000 rows of unknown heights. Watch the object counter stop at a couple of dozen and stay there.

• Chat: messages sized by their text, with Send buttons that append new ones at runtime. Adding 200 messages creates zero objects.

• Strip: the same component horizontal, 20,000 cards, widths supplied up front so nothing is measured.

• Jump: 200,000 rows and a box to jump to any of them; a jump is one index lookup, not a walk.

Each scene has an on-screen readout counting objects, reuses, measurements, skipped updates and allocated bytes as you drag.

GETTING STARTED

Implement one interface: a Count property and a Bind method that fills a row from an index. Call SetSource and that is the whole integration. Implement IListRecycleAware as well if a row owns something that should be released when it leaves the screen.

MEASURED

Unity 2022.3.62f2. 50,000 rows, 600-unit viewport, one row in seven three times taller than the rest, dragged from the top of the list to the bottom and back.

• 11 GameObjects instantiated; a second full pass creates none

• 0 managed bytes allocated while scrolling

• 35,733 of 81,072 updates did no work at all

• Size index, 200,000 rows: 1 ms to build, 2 ms to measure every row, 16 ms for 200,000 offset lookups

These come from the automated checks that ship with the package. Your own project is the only benchmark that matters, which is what the report window is for.

REQUIREMENTS

• Unity 2022.3 LTS or newer

• Unity's UI package (com.unity.ugui)

• No other dependencies, no accounts, no plugins

• Any render pipeline

LIMITS

One column; grids are not supported in 1.0. Rows are measured after they are built, so a row that changes height while it is on screen needs Rebuild, or sizes supplied through IListSizeSource. A row that computes its height in Start rather than in Bind will be measured before it is ready. The samples use legacy Text so they have no package dependencies; TextMeshPro works the same way.