Storyteller ships multiple Flutter widgets that mirror the native list experiences. Each widget wraps a platform view, so the iOS and Android SDKs render the UI while Flutter manages sizing, layout, and callbacks.
Initialize successfully before mounting a list. Use published content and category/collection identifiers for the same API key. Row views need a positive height or bounded parent constraints; scrollable grids need bounded width and height. Non-scrollable grids size themselves from native measurements or the Android grid layout calculation.
Published Flutter 12.2.0 uses Android 12.2.0 / iOS 11.9.1.
The Dart configuration and native constructor defaults below were checked for
an earlier 12.1.2 development snapshot (Android 12.1.2 / iOS 11.8.0)
and 11.6.5 (Android 11.6.4 / iOS 11.6.1).
Check Changelog when comparing versions.
StorytellerStoriesRowView(categories:const['YOUR_CATEGORY_ID'],cellType:'square',// or 'round'height:220,onTileTapped:(tile)=>debugPrint('Tapped ${tile.id}'),onDataLoadStarted:()=>debugPrint('Loading stories...'),onDataLoadComplete:(success,error,dataCount){if(!success){debugPrint('Stories failed to load: $error');}elseif(dataCount==0){debugPrint('No published stories in this category');}else{debugPrint('Loaded $dataCount stories');}},);
Both widgets expose optional callbacks:
onDataLoadStarted()
onDataLoadComplete(bool success, dynamic error, int dataCount) – error is a native error map when present, with type and message (and an optional Android causeMessage)
onTileTapped(StorytellerTileType tileType)
onPlayerDismissed()
StorytellerTileType is either StorytellerStoryTile or StorytellerClipTile. Both expose id, categories, and categoryDetails when the native SDK provides category metadata. From Flutter 12.1.2, both also expose the tapped content's title, its one-based tileIndex in the displayed list and its custom metadata. Clip tiles also expose collectionId.
The same callbacks are available on Stories and Clips rows/grids. onTileTapped observes the native tap; it does not replace the native player-opening action. Tile kind is StorytellerTileKind.story or .clip; id is always present, while category metadata, title, tileIndex, metadata and a clip's collectionId can be null. metadata is null when the content omitted it and empty when it supplied no entries.
The grid constructors require isScrollable; row constructors do not. categories (Stories) and collectionId (Clips) are nullable in Dart, but specify a valid identifier for a predictable content selection. cellType supports square/round, uiStyle supports light/dark/auto, and omitted values use native configuration/theme defaults. displayLimit limits displayed tiles; visibleTiles controls layout, including partial tiles. height is a Flutter row-layout value, not a native content parameter. context is Map<String, String> analytics attribution. All optional constructor configuration values default to null in Dart; the bridges/native theme supply effective defaults. Android falls back to square cells, automatic style and an effectively unlimited display limit. iOS leaves absent cell/style/limit/visible-tile values to native configuration and theme.
adConfiguration is fixed when the platform view is created and supported on
Android only. iOS ignores the entire value because its native Clips list
configuration exposes no presentation ad controls. Android defaults pre-roll on
in both compared baselines; omit the nullable value to preserve that native default. For
provider order, null preserves native order, an empty list disables standard
providers for that list presentation, and a populated list restricts and orders
them.
The Showcase feed swaps between rows, grids, and singleton layouts from a single StorytellerItemWidget that wires the callbacks above and hides sections with empty data.
Pass a StorytellerListViewController into any stories or clips list widget when you need to trigger native reloads on demand (for example, after a user signs in or changes preferences).
If you call reloadData before the platform view has been created, the controller queues the request and executes it automatically after the widget is ready.
A queued reload's Future can finish before the platform view attaches; an attached reload's Future acknowledges the request. Use onDataLoadComplete to observe loading success, empty results, or failure. The widget detaches its controller when disposed.
Native content/configuration parameters are fixed at creation. To change categories, collection, theme, style, limits, context, or ad configuration, recreate the widget with a new key; a reload refreshes its existing configuration. See Troubleshooting for blank layouts and Ads for ad module setup.
{"slug": "storyteller-list-views", "page_title": "List Components", "page_url": "StorytellerListViews/", "canonical_url": "/flutter/StorytellerListViews/", "markdown": "# Storyteller List Components\n\nStoryteller ships multiple Flutter widgets that mirror the native list experiences. Each widget wraps a platform view, so the iOS and Android SDKs render the UI while Flutter manages sizing, layout, and callbacks.\n\nInitialize successfully before mounting a list. Use published content and category/collection identifiers for the same API key. Row views need a positive `height` or bounded parent constraints; scrollable grids need bounded width and height. Non-scrollable grids size themselves from native measurements or the Android grid layout calculation.\n\nPublished Flutter `12.2.0` uses Android `12.2.0` / iOS `11.9.1`.\nThe Dart configuration and native constructor defaults below were checked for\nan earlier `12.1.2` development snapshot (Android `12.1.2` / iOS `11.8.0`)\nand `11.6.5` (Android `11.6.4` / iOS `11.6.1`).\nCheck [Changelog](Changelog.md) when comparing versions.\n\n## Stories layouts\n\n| Widget | Description | Common parameters |\n| --- | --- | --- |\n| `StorytellerStoriesGridView` | Scrollable, multi-column grid of stories. | `isScrollable`, `categories`, `cellType`, `uiStyle`, `displayLimit`, `visibleTiles`, `theme`, `context`, `controller` |\n| `StorytellerStoriesRowView` | Horizontal row of story tiles. | `categories`, `cellType`, `uiStyle`, `displayLimit`, `visibleTiles`, `height`, `theme`, `context`, `controller` |\n\nExample usage:\n\n```dart\nStorytellerStoriesRowView(\n categories: const ['YOUR_CATEGORY_ID'],\n cellType: 'square', // or 'round'\n height: 220,\n onTileTapped: (tile) => debugPrint('Tapped ${tile.id}'),\n onDataLoadStarted: () => debugPrint('Loading stories...'),\n onDataLoadComplete: (success, error, dataCount) {\n if (!success) {\n debugPrint('Stories failed to load: $error');\n } else if (dataCount == 0) {\n debugPrint('No published stories in this category');\n } else {\n debugPrint('Loaded $dataCount stories');\n }\n },\n);\n```\n\nBoth widgets expose optional callbacks:\n\n- `onDataLoadStarted()`\n- `onDataLoadComplete(bool success, dynamic error, int dataCount)` \u2013 `error` is a native error map when present, with `type` and `message` (and an optional Android `causeMessage`)\n- `onTileTapped(StorytellerTileType tileType)`\n- `onPlayerDismissed()`\n\n`StorytellerTileType` is either `StorytellerStoryTile` or `StorytellerClipTile`. Both expose `id`, `categories`, and `categoryDetails` when the native SDK provides category metadata. From Flutter 12.1.2, both also expose the tapped content's `title`, its one-based `tileIndex` in the displayed list and its custom `metadata`. Clip tiles also expose `collectionId`.\n\nThe same callbacks are available on Stories and Clips rows/grids. `onTileTapped` observes the native tap; it does not replace the native player-opening action. Tile `kind` is `StorytellerTileKind.story` or `.clip`; `id` is always present, while category metadata, `title`, `tileIndex`, `metadata` and a clip's `collectionId` can be null. `metadata` is null when the content omitted it and empty when it supplied no entries.\n\nThe grid constructors require `isScrollable`; row constructors do not. `categories` (Stories) and `collectionId` (Clips) are nullable in Dart, but specify a valid identifier for a predictable content selection. `cellType` supports `square`/`round`, `uiStyle` supports `light`/`dark`/`auto`, and omitted values use native configuration/theme defaults. `displayLimit` limits displayed tiles; `visibleTiles` controls layout, including partial tiles. `height` is a Flutter row-layout value, not a native content parameter. `context` is `Map<String, String>` analytics attribution. All optional constructor configuration values default to `null` in Dart; the bridges/native theme supply effective defaults. Android falls back to square cells, automatic style and an effectively unlimited display limit. iOS leaves absent cell/style/limit/visible-tile values to native configuration and theme.\n\n## Clips layouts\n\n| Widget | Description | Common parameters |\n| --- | --- | --- |\n| `StorytellerClipsGridView` | Grid of clips sourced from a collection. | `isScrollable`, `collectionId`, `cellType`, `uiStyle`, `displayLimit`, `visibleTiles`, `theme`, `context`, `adConfiguration`, `controller` |\n| `StorytellerClipsRowView` | Horizontal reel of clips. | `collectionId`, `cellType`, `uiStyle`, `displayLimit`, `visibleTiles`, `height`, `theme`, `context`, `adConfiguration`, `controller` |\n\nExample usage:\n\n```dart\nconst StorytellerClipsRowView(\n collectionId: 'collection',\n cellType: 'square',\n height: 220,\n context: {'placement': 'custom_placement'},\n adConfiguration: StorytellerClipsAdConfiguration(\n preRollEnabled: true,\n bottomBannerEnabled: true,\n betweenClipsAdProviderOrder: [StorytellerAdProvider.gam],\n ),\n);\n```\n\n`adConfiguration` is fixed when the platform view is created and supported on\nAndroid only. iOS ignores the entire value because its native Clips list\nconfiguration exposes no presentation ad controls. Android defaults pre-roll on\nin both compared baselines; omit the nullable value to preserve that native default. For\nprovider order, `null` preserves native order, an empty list disables standard\nproviders for that list presentation, and a populated list restricts and orders\nthem.\n\nThe Showcase feed swaps between rows, grids, and singleton layouts from a single [`StorytellerItemWidget`](https://github.com/getstoryteller/storyteller-showcase-flutter/blob/main/lib/screens/home/widgets/storyteller_item_widget.dart#L9) that wires the callbacks above and hides sections with empty data.\n\n## Controlling list refresh\n\nPass a `StorytellerListViewController` into any stories or clips list widget when you need to trigger native reloads on demand (for example, after a user signs in or changes preferences).\n\n```dart\nclass CategoryStories extends StatefulWidget {\n const CategoryStories({super.key});\n\n @override\n State<CategoryStories> createState() => _CategoryStoriesState();\n}\n\nclass _CategoryStoriesState extends State<CategoryStories> {\n final _controller = StorytellerListViewController();\n\n @override\n Widget build(BuildContext context) {\n return StorytellerStoriesRowView(\n categories: const ['recommended'],\n controller: _controller,\n );\n }\n\n Future<void> refreshStories() async {\n await _controller.reloadData();\n }\n}\n```\n\nIf you call `reloadData` before the platform view has been created, the controller queues the request and executes it automatically after the widget is ready.\n\nA queued reload's `Future` can finish before the platform view attaches; an attached reload's `Future` acknowledges the request. Use `onDataLoadComplete` to observe loading success, empty results, or failure. The widget detaches its controller when disposed.\n\nNative content/configuration parameters are fixed at creation. To change categories, collection, theme, style, limits, context, or ad configuration, recreate the widget with a new key; a reload refreshes its existing configuration. See [Troubleshooting](Troubleshooting.md) for blank layouts and [Ads](Ads.md) for ad module setup.\n", "copy_markdown_include_header": false, "base_path": "", "ai_dir": "ai", "missing_payload_behavior": "empty"}