Skip to content

What is StorytellerListView (Legacy)#

StorytellerListView is a base abstract class for views displaying lists of Stories or Clips. Soryteller Views are considered Legacy and the support may be removed in near future. Please prefer using Composables instead.

Showcase examples#

The Storyteller SDK offers two implementations of this abstract class:

  • StorytellerStoriesView
  • StorytellerClipsView

Each of these classes has their corresponding rows and grid views as the following:

For Stories

  • StorytellerStoriesRowView
  • StorytellerStoriesGridView

For Clips

  • StorytellerClipsRowView
  • StorytellerClipsGridView

this abstract class contains all abstract attributes and methods that are common to all StorytellerListView implementations.

How to improve the performance of RecyclerView?#

If you use the StorytellerViews in a RecyclerView, using the setViewHolderParent method is not mandatory but can significantly improve the UI performance.

Inside the RecyclerView.Adapter:

...

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
 val itemView = LayoutInflater.from(parent.context).inflate(R.layout.my_item, parent, false)
 return MyViewHolder(itemView, parent)
}
...

Inside the RecyclerView.ViewHolder:

class MyViewHolder(
  private val view: View,
  private val parent: ViewGroup,
): RecyclerView.ViewHolder(view) {

  private val binding = ListStoryRowBinding.bind(view)

  fun onBind(item: Item) {
    binding.storytellerView.setViewHolderParent(parent)
    ...
  }
}

Adding a StorytellerStoriesRowView#

The StorytellerStoriesRowView can be added to your app using XML layout or in code.

XML#

Add a com.storyteller.ui.list.StorytellerStoriesRowView element to your layout

        <com.storyteller.ui.list.StorytellerStoriesRowView
            android:id="@+id/storyRowView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            ...
            />

Code#

  1. Create a StorytellerStoriesRowView instance
      val storyRowView = StorytellerStoriesRowView(context)
  1. Add the created view instance to the view hierarchy
      view.addView(storyRowView)

Recommendations for StorytellerListView Hosting Activity#

Please keep in mind that Stories will open in the activity that displays a status bar only if there is a cutout notch present on the device. In other cases, Stories will open in the activity without a status bar.

Status bar visibility changes can have an impact on shared element transitions between Storyteller List View and Story Viewing Activity. For that reason, we recommend hosting activities to use LAYOUT_STABLE flags as in the code snippet below

 // Storyteller hosting activity onCreate method
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // ~~~~~~~
    window.decorView.systemUiVisibility =
      window.decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
    // ~~~~~~~
}

Further Reading#

Additional Storyteller Methods#

Storyteller has some helper methods which may be useful, see AdditionalMethods for more details.

Implementing Storyteller Callbacks#

StorytellerDelegate has callbacks for events which can be implemented, see StorytellerDelegate for more details.

Implementing StorytellerListView Callbacks#

StorytellerListView has callbacks for events which can be implemented, see StorytellerListViewDelegate for more details.

Configuring a StorytellerStoriesView#

Attributes#

This sections describes attributes common to StorytellerStoriesRowView and StorytellerStoriesGridView. Notes are used to mark if there is a difference in property interpretation.

delegate#

The delegate is the StorytellerListViewDelegate instance for StorytellerListView callbacks (see Implementing StorytellerListViewDelegate methods).

StorytellerStoriesView.ListConfiguration#

The ListConfiguration class is used to configure the StorytellerStoriesRowView and StorytellerStoriesGridView classes. It is a data class that inherits from StorytellerListConfiguration.

Usage:

    val storytellerStoriesRowView = StorytellerStoriesRowView(context)
    storytellerStoriesRowView.configuration = StorytellerStoriesView.ListConfiguration(
      theme = customTheme,
      uiStyle = StorytellerListViewStyle.AUTO,
      displayLimit = 10,
      cellType = StorytellerListViewCellType.SQUARE,
      categories = listOf("category1", "category2", "categoryX"),
      offset = 1,
      context = hashMapOf("placementId" to "home_stories", "location" to "Home"),
    )
cellType#

The cellType is the style of the cell. This can either be ROUND(0) or SQUARE(1). The default value is SQUARE(1).

categories#

The categories attribute is a list of Categories that the list view should show to the user. The default value is an empty list. The categories property can be used to show specific Stories content in the row or grid by supplying a list of valid Categories as strings. Categories can be defined in the CMS. If no Categories are assigned then the content from the default or "Home" Category is displayed.

theme#

The theme parameter is used to set the Theme for the StorytellerListView. If theme is set to null, then theme set asStoryteller.theme global property is used. The theme determines how the items within the List View are presented as well as various features of the player once it is launched.

uiStyle#

The uiStyle adjusts whether Storyteller renders in light mode, dark mode or follows the system setting.

uiStyle takes the following values:

  • StorytellerListViewStyle.AUTO - default value, the StorytellerListView will adjust its color scheme automatically according to the current system UI mode
  • StorytellerListViewStyle.LIGHT - force the StorytellerListView to use the light theme
  • StorytellerListViewStyle.DARK - force the StorytellerListView to use the dark theme
displayLimit#

The displayLimit is the maximum amount of tiles that can be shown in the list.

offset#

The offset is the offset to start displaying stories from a specific position in the collection. Default is 0 (start from beginning).

context#

The context parameter is an optional StorytellerAnalyticsContext (which is a HashMap<String, String>) containing integrator-defined key-value pairs for analytics attribution. This context will be included with all analytics events originating from this UI instance. See Analytics for more details.

Dynamic Scaling#

Item tiles will scale dynamically to fit the row or grid view.

The base size of the tiles are:

  • 100dp width x 150dp height for square tiles
  • 76dp width x 105dp height for round tiles

The base size will be used when rendering the row if the dimensions of the row view cannot determine its constraints. The exact dimensions of the row view will depend on how it is defined in the layout view hierarchy, including its parents. In general, tiles will maintain its base proportion and scale up or down to meet view hierarchy constrains.

For the sake of simplicity, examples will be provided using square as 100dp/150dp = 2/3 proportions to make it easier to do calculations.

Example 1#
    <com.storyteller.ui.list.StorytellerStoriesRowView
      app:cellType="square"
      android:layout_width="match_parent"
      android:layout_height="200dp"
      ...
    />

The final item tile size will be ≈ 133dp x 200dp, as 200 dp[h] * 2/3 [w/h] ≈ 133dp

Example 2#
  <LinearLayout
  android:layout_width="match_parent"
  android:layout_height="200dp"
  android:orientation="vertical">
    <com.storyteller.ui.list.StorytellerStoriesRowView
      app:cellType="square"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      ...
    />
  </LinearLayout>

The final item tile size will be ≈ 133dp x 200dp. This is because the StorytellerStoriesRowView is wrapped in a parent view with a height of 200dp and has its size attributes set to match_parent. The system, therefore, expands the row view to fill the height of its parent and scales the width of the tiles accordingly.

Example 3#
  <?xml version="1.0" encoding="utf-8"?>
  <com.storyteller.ui.list.StorytellerStoriesRowView
    app:cellType="square"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    ...
  />

In this case, the final item tile size will be the height of the window. This happens because the StorytellerStoriesRowView is defined as the top-most view and android:layout_height="match_parent" has been set on the view. The system, therefore, expands the row view to fill the window height - and so the resulting item tiles will scale to fit the window height also.

Example 4#
  ...

  <LinearLayout
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical">

    <com.storyteller.ui.list.StorytellerStoriesRowView
      app:cellType="square"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      ...
    />

    ...

  </LinearLayout>

In this case, the final item tile size will be 100dp x 150dp (the base size). Since the StorytellerStoriesRowView has been defined as the child of another view, setting android:layout_height="wrap_content" makes the item tile size 100dp x 150dp (base size).

XML#

Attributes can also be applied in XML.

<com.storyteller.ui.list.StorytellerStoriesRowView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cellType="round"/>

Methods#

reloadData#

The reloadData method starts loading fresh data for all Stories from the API. On completion, it updates the Story data, starts prefetching content and updates the read status of the Stories. The onDataLoadStarted and onDataLoadComplete methods on the StorytellerListViewDelegate are called accordingly (the latter with appropriate data depending on the result of the API requests).

  val storytellerStoriesRowView = StorytellerStoriesRowView(context)
  storytellerStoriesRowView.reloadData()

Configuring a StorytellerClipsView#

Attributes#

This sections describes attributes common to StorytellerClipsRowView and StorytellerClipsGridView. Notes are used to mark if there is a difference in property interpretation

StorytellerListViewDelegate#

StorytellerClipsView.ListConfiguration#

The ListConfiguration class is used to configure the StorytellerClipsRowView and StorytellerClipsGridView classes. It is a data class that inherits from StorytellerListConfiguration.

StorytellerClipsView.ListConfiguration class attributes:

Example:

  val storytellerClipsRowView = StorytellerClipRowView(context)
  storytellerClipsRowView.configuration = StorytellerClipsView.ListConfiguration(
  theme = customTheme,
  uiStyle = StorytellerListViewStyle.AUTO,
  displayLimit = 10,
  cellType = StorytellerListViewCellType.SQUARE,
  collection = "collectionId",
  context = hashMapOf("placementId" to "home_clips", "location" to "Home"),
)
  • collection: the Collection that the list view should show to the user. The default value is null.The collection property is used to show specific Clips content in the row or grid by supplying a single Collection as string. Collections can be defined in the CMS. If no Collection is assigned, then no Clips content is displayed.
  • theme: This parameter is used to set the Theme for the StorytellerClipsView. If theme is set to null, then theme set asStoryteller.theme global property is used. The theme determines how the items within the List View are presented as well as various features of the player once it is launched.
  • displayLimit: only display up to this number of tiles in the list.
  • uiStyle: adjust whether Storyteller renders in light mode, dark mode or follows the system setting.

uiStyle takes the following values:

  • StorytellerListViewStyle.AUTO - default value, the StorytellerClipsView will adjust its color scheme automatically according to the current system UI mode
  • StorytellerListViewStyle.LIGHT - force the StorytellerClipsView to use the light theme
  • StorytellerListViewStyle.DARK - force the StorytellerClipsView to use the dark theme

  • context: Optional StorytellerAnalyticsContext (a HashMap<String, String>) containing integrator-defined key-value pairs for analytics attribution. This context will be included with all analytics events originating from this UI instance. See Analytics for more details.

Feed Title#

The feed title in the Clips player can be configured in the CMS for the Collection. This can be a custom title or image.

Dynamic Scaling#

Item tiles will scale dynamically to fit the row or grid view.

The base size of the tiles are:

  • 100dp width x 150dp height for square tiles
  • 76dp width x 105dp height for round tiles

The base size will be used when rendering the row if the dimensions of the row view cannot determine its constraints. The exact dimensions of the row view will depend on how it is defined in the layout view hierarchy, including its parents. In general, tiles will maintain its base proportions and scale up or down to meet view hierarchy constrains.

For the sake of simplicity, examples will be provided using square as 100dp/150dp = 2/3 proportions to make it easier to do calculations.

Example 1#

    <com.storyteller.ui.list.StorytellerClipsRowView
      app:cellType="square"
      android:layout_width="match_parent"
      android:layout_height="200dp"
      ...
    />

The final item tile size will be ≈ 133dp x 200dp, as 200 dp[h] * 2/3 [w/h] ≈ 133dp

Example 2#

  <LinearLayout
  android:layout_width="match_parent"
  android:layout_height="200dp"
  android:orientation="vertical">
    <com.storyteller.ui.list.StorytellerClipsRowView
      app:cellType="square"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      ...
    />
  </LinearLayout>

The final item tile size will be ≈ 133dp x 200dp. This is because the StorytellerRowView is wrapped in a parent view with a height of 200dp and has its size attributes set to match_parent. The system, therefore, expands the row view to fill the height of its parent and scales the width of the tiles accordingly.

Example 3#

  <?xml version="1.0" encoding="utf-8"?>
    <com.storyteller.ui.list.StorytellerClipsRowView
    app:cellType="square"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    ...
  />

In this case, the final item tile size will be the height of the window. This happens because the StorytellerRowView is defined as the top-most view and android:layout_height="match_parent" has been set on the view. The system, therefore, expands the row view to fill the window height - and so the resulting item tiles will scale to fit the window height also.

Example 4#

  ...

  <LinearLayout
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical">

    <com.storyteller.ui.list.StorytellerClipsRowView
      app:cellType="square"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      ...
    />

    ...

  </LinearLayout>

In this case, the final item tile size will be 100dp x 150dp (the base size). Since the StorytellerRowView has been defined as the child of another view, setting android:layout_height="wrap_content" makes the item tile size 100dp x 150dp (base size).

XML#

Views can also be applied in XML.

<com.storyteller.ui.list.StorytellerClipsRowView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>

Methods#

reloadData#

The reloadData method starts loading fresh data for all Clips from the API. On completion, it updates the Clips data, starts prefetching content and updates the read status of the Clips. The onDataLoadStarted and onDataLoadComplete methods on the StorytellerListViewDelegate are called accordingly (the latter with appropriate data depending on the result of the API requests).

val storytellerClipsRowView = StorytellerClipsRowView(context)
storytellerClipsRowView.reloadData()