Class ListView
- All Implemented Interfaces:
Scrollable
JTable/RecyclerView: only the rows in the viewport get a
widget, so a list of a million rows costs the same as one of twenty (layout
and paint are O(visible)).
Rows may have different heights: e.g. small grouping headers among normal cards. There is no global height cache and no binary search: the list keeps an anchor (which row sits where) and walks a handful of rows from it each frame, measuring each on demand. Scroll-thumb size/position are estimated from the average measured height (good enough for a scroll indicator).
You supply and cache the widgets through an ListView.Adapter: the
list asks ListView.Adapter.rowAt(int) for the (already-populated) widget of a row,
and hands it back via ListView.Adapter.recycle(limn.scene.Widget) when it scrolls out, so the
adapter can pool per row type and rebind, or just create fresh (simplest, no
pooling). The list owns only the tree/positioning; the caching policy is
yours.
Interaction: the wheel scrolls (with the shared ScrollBar); the
list is focusable and, while focused, Up/Down/Home/End/PageUp/PageDown move a
highlighted selection (auto-scrolling to reveal it) and Enter activates it;
clicking a row selects it (clicks on a row's own buttons reach those buttons).
Size steps propagate rather than being imposed. Rows are adapter-supplied
widgets in this list's subtree, so they resolve the ControlSize
themselves and list.setControlSize(SMALL) shortens them because they
re-measure. Only three metrics are the list's own: the frame-0 row-height seed used
before anything has been measured, the intrinsic width under an unbounded constraint,
and the selection ring's corner radius.
The scroll bar does not take part in the size axis (ScrollBar.thickness()
is 15 pt at every step), and it overlays the rows rather than insetting them, so at a
compact step it covers a larger fraction of a shorter row. An accepted cost of one
scrollbar geometry process-wide.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic interfaceSupplies and (optionally) caches the row widgets of aListView. -
Constructor Summary
ConstructorsConstructorDescriptionListView(ListView.Adapter adapter) A list driven byadapter, which supplies and recycles the row widgets. -
Method Summary
Modifier and TypeMethodDescriptionvoidactivate()FiresonActivatefor the selected row, as Enter does.Whether the scrollbar overlays the rows or reserves a gutter.protected booleanWhetherWidget.paintChildren(limn.graphics.Canvas)clips its children to this widget's bounds (scroll views, list viewports, tab strips).inthitTest(float localX, float localY) Deepest visible/enabled descendant containing the point (local coords), or this widget itself;nullwhen outside.onActivate(IntConsumer handler) Called with the row index on Enter or a double activation, the "open this" gesture.protected voidCalled when this widget takes keyboard focus.protected voidCalled when this widget loses keyboard focus.protected voidonKeyEvent(KeyEvent event) Key events (focused widget first, then ancestors).protected voidonLayout()Containers position children here (measure +Widget.layoutBox(float, float, float, float)per child).protected SizeonMeasure(Constraints constraints) Reports the size this widget wants withinconstraints.protected voidonMouseEvent(MouseEvent event) Mouse events (bubbling); callevent.consume()when handled.onSelect(IntConsumer handler) Called with the row index when the selection moves, by click or keyboard.protected voidpaintChildren(Canvas canvas) Children pass; override to clip (e.g.voidrefresh()Re-reads the adapter and re-lays out (call after the data changes).voidrevealRect(float x, float y, float rectWidth, float rectHeight) Scrolls the minimum so the rect (in viewport coordinates) becomes visible.introwCount()Row count as the adapter currently reports it.voidscrollBy(float dy) Scrolls by a delta in logical points (positive = toward the end).intThe selected row, or-1when nothing is selected.setBarLayout(ScrollGutters.Layout layout) Sets whether the bar floats over the rows or reserves a strip of its own (defaultScrollGutters.Layout.OVERLAY).setScrollbarPolicy(ScrollBar.Policy policy) Sets when the vertical scrollbar is shown (defaultScrollBar.Policy.AUTO).setSelectedIndex(int index) Selects a row, scrolls it into view and firesonSelect; code and a click take the same path, so a listener sees every change either way.Methods inherited from class limn.scene.Widget
acceptsTextInput, add, baselineOffset, baselineOffsetOf, caretRect, children, clipboard, controlSize, cursor, declaredControlSize, declaredLayoutDirection, declaredLocale, focusArrivedByTraversal, height, imageCursor, invalidate, invalidate, isEnabled, isFocusable, isFocused, isShowing, isVisible, layoutBox, layoutDirection, locale, localToSceneX, localToSceneY, markNeedsContainedLayout, markNeedsLayout, measure, moveChild, neutralBase, onAttached, onCharTyped, onDetached, onFileDrop, onPaint, onPaintOverlay, onPreedit, overlayPassesPointer, paintOutset, paintWidget, parent, remove, requestFocus, revealInView, scene, sceneToLocalX, sceneToLocalY, setControlSize, setCursor, setEnabled, setFocusable, setImageCursor, setInheritanceHost, setLayoutDirection, setLocale, setTooltip, setTooltip, setVisible, shapeText, textRuler, tooltip, width, x, y
-
Constructor Details
-
ListView
A list driven byadapter, which supplies and recycles the row widgets.
-
-
Method Details
-
setBarLayout
Sets whether the bar floats over the rows or reserves a strip of its own (defaultScrollGutters.Layout.OVERLAY). Reserved is what a list of records usually wants: the trailing edge of a row is where a count, a date or a status chip goes, and a thumb over it is a defect. Trailing and not right: the bar and the row's last column are both on the left of a list that reads right to left, and they move there together. -
barLayout
Whether the scrollbar overlays the rows or reserves a gutter. -
setScrollbarPolicy
Sets when the vertical scrollbar is shown (defaultScrollBar.Policy.AUTO). -
onSelect
Called with the row index when the selection moves, by click or keyboard.- Throws:
NullPointerException- ifhandleris null, as everywhere else in this set
-
onActivate
Called with the row index on Enter or a double activation, the "open this" gesture.- Throws:
NullPointerException- ifhandleris null
-
selectedIndex
public int selectedIndex()The selected row, or-1when nothing is selected. A list is one of the two widgets in this set that genuinely has no-selection as a state:clearSelection()reaches it, and a fresh list is in it. -
rowCount
public int rowCount()Row count as the adapter currently reports it. -
firstVisibleIndex
public int firstVisibleIndex()- Returns:
- the first fully-or-partly visible row index (tests/inspection)
-
refresh
public void refresh()Re-reads the adapter and re-lays out (call after the data changes). If the adapter shrank past the selected row the selection moves to the last row (or is dropped when the list is now empty) andonSelectis told, because a listener showing the selected record would otherwise still be showing a deleted one. UI thread only. -
setSelectedIndex
Selects a row, scrolls it into view and firesonSelect; code and a click take the same path, so a listener sees every change either way. Selecting the row that is already selected changes nothing, reveals nothing and fires nothing; that early return is what keeps two controls bound to each other from recursing, so do not remove it. UI thread only.- Parameters:
index- a row in[0, rowCount()).-1is not an argument even though it is whatselectedIndex()reports for an empty selection:clearSelection()is how that state is reached.- Throws:
IndexOutOfBoundsException- ifindexis outside that range, an empty list included, where every index is. An index that came from a search which found nothing, or from state saved against longer data, is a caller's bug here, exactly as it is forList.get.
-
clearSelection
Drops the selection:selectedIndex()becomes-1andonSelectis fired with it. No-op when nothing is selected. UI thread only. -
activate
public void activate()FiresonActivatefor the selected row, as Enter does. -
scrollBy
public void scrollBy(float dy) Scrolls by a delta in logical points (positive = toward the end). UI thread only. -
revealRect
public void revealRect(float x, float y, float rectWidth, float rectHeight) Scrolls the minimum so the rect (in viewport coordinates) becomes visible.- Specified by:
revealRectin interfaceScrollable
-
onMeasure
Description copied from class:WidgetReports the size this widget wants withinconstraints. Called once per layout pass, and the result is cached against the constraints and the resolved axes (size step, layout direction, locale), so it must be a pure function of them and of this widget's own state.Resolve the
ControlSizeand theLayoutDirectiononce each here and thread them down; never read either in a constructor. The locale needs no threading: it is in scope, andI18n.locale()answers it wherever text is resolved. -
onLayout
protected void onLayout()Description copied from class:WidgetContainers position children here (measure +Widget.layoutBox(float, float, float, float)per child). -
clipsChildren
protected boolean clipsChildren()Description copied from class:WidgetWhetherWidget.paintChildren(limn.graphics.Canvas)clips its children to this widget's bounds (scroll views, list viewports, tab strips). Partial rendering uses it to clamp a descendant'sWidget.invalidate()damage to the visible region; a widget scrolled out of view damages nothing. Any override that clips inpaintChildrenshould also override this.- Overrides:
clipsChildrenin classWidget
-
paintChildren
Description copied from class:WidgetChildren pass; override to clip (e.g. scroll views).- Overrides:
paintChildrenin classWidget
-
hitTest
Description copied from class:WidgetDeepest visible/enabled descendant containing the point (local coords), or this widget itself;nullwhen outside. Later children win because they paint on top. -
onMouseEvent
Description copied from class:WidgetMouse events (bubbling); callevent.consume()when handled.- Overrides:
onMouseEventin classWidget
-
onKeyEvent
Description copied from class:WidgetKey events (focused widget first, then ancestors).- Overrides:
onKeyEventin classWidget
-
onFocusGained
protected void onFocusGained()Description copied from class:WidgetCalled when this widget takes keyboard focus. Default: nothing.- Overrides:
onFocusGainedin classWidget
-
onFocusLost
protected void onFocusLost()Description copied from class:WidgetCalled when this widget loses keyboard focus. Default: nothing.- Overrides:
onFocusLostin classWidget
-