Skip to main content

CollectionView Overview

CollectionView

CollectionView is Hosanna's large-list surface. It virtualizes rows and cells, recycles view instances, and keeps focus state stable while data changes. Use it for rails, grids, tabbed rows, EPG-style rows, and any list that can grow or load dynamically.

Choosing Between Repeater, ScrollView, and CollectionView

ContentUse
A few similar buttons, icons, or badgesRepeater
One heterogeneous detail page, settings page, or form that extends beyond the viewportScrollView
A data-driven list, rail, grid, EPG, season list, episode list, or collection that can growCollectionView

CollectionView is also a strong choice for detail screens and form-like experiences when their sections can be represented as rows or items. It provides better scaling and can use AppConfig fragments for reusable presentation and separately managed layout and style updates.

Do not embed Repeater, ScrollView, or ScrollContainer inside CollectionView cells, custom cells, or supplementary/header views. Use CollectionView rows, cells, headers, and fragments so the collection remains the single owner of focus, scrolling, recycling, and updates.

CollectionView row and cell layout modelCollectionView row and cell layout model

A CollectionView renders visible rows, each row positions its cells, and focus is tracked by row and item index.

Quick Start

Collections Collectionview Basic

@view('CollectionsCollectionviewBasic')
export class CollectionsCollectionviewBasicView extends BaseExampleScreenView<CollectionsCollectionviewBasicState> {
  @state private dataSource = new CollectionViewDataSource([]);

  constructor() {
    super();
    // Seed a couple of rows using the built-in 'rows.regular' style
    const rows: ICollectionViewDataSourceRow[] = [
      this.createRow('Row A', 6),
      this.createRow('Row B', 8),
    ];
    this.dataSource.appendRows(rows, undefined, true);
  }

  protected getViews(): ViewStruct<ViewState>[] {
    // --- edit below ---

    return [
      VGroup([
        Label({ text: 'CollectionView: Basic' }),
        Button({ text: 'Add Row', width: 300 })
          .isInitialFocus(true)
          .onClick(() => this.dataSource.appendRows([this.createRow('New Row', 5)], undefined, true)),
        CollectionView({ id: 'cv' })
          .translation([0, 80])
          .dataSource(this.dataSource),
      ]).itemSpacing(12)
    ];

    // --- edit above ---
  }

  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  private createRow(label: string, count = 6): ICollectionViewDataSourceRow<any, any> {
    const items = Array(count).fill(0).map((_, i) => ({
      id: `${label}-item-${i + 1}`,
      imageSet: { $RES$: 'https://via.assets.so/movie.png?w=384&h=216&q=85' },
    }));
    return {
      id: `row-${label}-${Math.random().toString(36).slice(2, 7)}`,
      settingsKey: 'rows.regular',
      data: { label },
      items,
    };
  }
}

Core Model

  • View: CollectionView({ id }).dataSource(dataSource) renders the current CollectionViewDataSource.
  • Rows: each data source row has an id, settingsKey, optional settingsOverrides, optional row data, and an items array.
  • Settings: row and cell styles live in assets/meta/app.config.json under top-level rows and cells.
  • Cells: most rows use DynamicCell, which renders fragment JSON and applies normal, focused, selected, and disabled state styles.
  • Focus: focusedIndices stores [rowIndex, itemIndex]; events expose row and item indices, and helper methods return focused row/item data.

AppConfig Row and Cell Styles

Rows are configured by style keys such as rows.regular. settingsOverrides can adjust an individual row without creating a new global style.

{
"rows": {
"regular": {
"rowType": "HorizontalRow",
"height": 317,
"contentOffset": [255, 0],
"cellSize": [384, 216],
"spacing": 15,
"screenPosition": [0, 150],
"cellSettingsKey": "cells.regular",
"headerSettings": {
"height": 51,
"labelOffset": [255, 0],
"fontKey": "~theme.fonts.heading-24"
},
"focusSettings": {
"indicatorImageUri": "images/input-focusrect.9.png",
"indicatorAppearance": "onTop"
}
}
}
}

Cells use fragment-style config. $supportsDataMap enables ${data.*} bindings; $RES$ inside a data path is replaced with the active resolution suffix.

{
"cells": {
"regular": {
"$supportsDataMap": true,
"views": {
"base": [
{
"id": "poster",
"subType": "Poster",
"width": 384,
"height": 216,
"uri": "${data.imageSet.$RES$}"
}
],
"normal": {
"poster": { "loadingBitmapUri": "~theme.images.placeholder" }
},
"focused": {
"poster": { "scale": [1.05, 1.05] }
}
}
}
}
}

API Surface

  • CollectionView: dataSource, rowSpacing, focusIndicatorAppearance, onItemSelected, onItemLongPressSelected, onOptionsKeyPressed, onItemFocus, onRowFocus.
  • Navigation helpers: jumpToRow(rowIndex, itemIndex?, force?), scrollToRow(rowIndex, itemIndex?, force?), renderForIndices(rowIndex, itemIndex).
  • Focused data helpers: getFocusedDataSourceRow(), getFocusedDataSourceItem(), getDataSourceItemForIndex(rowIndex, itemIndex), getCellForIndex(rowIndex, itemIndex).
  • DataSource: appendRows, replaceAllRows, appendItemsToRow, removeItemsFromRow, updateItem, removeRow, moveRowToIndex, changeRowEnabled, ChangeRowHidden, applyUpdates.
  • Pointer support: mouse hover/click, wheel scrolling, touch drag, horizontal row axis locking, momentum, and pointer focus indicator modes are handled by the web input adapters.

Edge-to-Edge Collections

CollectionViewSafeAreaBehavior.FullViewportSafeFocus keeps the collection's drawable viewport edge-to-edge while using native interaction insets for focus positions and the first/last scroll extents. It merges those native values with explicit scrollInsets; existing collections default to None and retain their current geometry.

CollectionView({
id: 'fullViewportFeed',
width: screenWidth,
height: screenHeight,
viewportHeight: screenHeight,
floatingFocusAreaHeight: screenHeight,
safeAreaBehavior: CollectionViewSafeAreaBehavior.FullViewportSafeFocus,
dataSource,
});

See Safe Areas and Edge-to-Edge Screens for the full screen-policy model and native verification guidance.

Learn More

  • CollectionView API: API
  • Styles and AppConfig: guide
  • Web Expression, DPI, and Touch Input: guide
  • Safe Areas and Edge-to-Edge Screens: guide
Talk to us