Roku List Development

The You.i Roku Cloud provides a custom component, ComponentScrollingView, to replicate the behavior of the You.i Platform list in the BrightScript client. This component, which is also the default, supports most list functionality that is available on other You.i Platform supported platforms.

Update List Contents

Whenever possible, it’s best to fetch all your list content and populate your lists before the first screen export. This reduces the amount of time it takes for your user to see the items in your list.

The following code snippet demonstrates how to populate your list before you start exporting:

Promise.all(requests)
  .then(results =>
    results.reduce((accumulator, curentValue) =>
    accumulator.concat(curentValue)))
  .then((results) => {
    this.setState({
      assets: results,
      data: listData
    });
  })
  .catch((error) => {
    console.error(error)
  });

For designs with large lists of lists, loading all of the content up front may take too long and result in failed Roku certification due to screens taking too long to load.

The You.i Roku Cloud has two ways to update your app’s list contents after an export has occurred:

  • Automatic detection
  • Manual export with replaceSubTree(C++) or exportSubTree(React Native).

Some Changes to Lists of Lists Are Automatically Detected

List items added or removed from the parent list of a list of lists are automatically detected by You.i Roku Cloud. The server updates the Roku client to reflect these changes without modifying any unchanged content. Single lists are also updated automatically (but carousel lists and grid lists are an exception).

Applying the automatic detection, which updates the Roku client, is fast if no other changes being applied to the scene tree around the same time. For example, automatic detection performance is slow when changes within a list (for example, adding a new item to the list of lists) are made at the same time as changes outside the list (for example, adding a button). Making bigger changes like this causes a large chunk of the Scene, including the entire list of lists, to be re-exported. This results in a poor user experience, which can be avoided if you ensure no changes are made to the rest of the scene at the same time as you are updating the contents of your list.

List items added or removed from child lists, grid lists, or carousel lists must be exported using exportSubTree (React Native) or ReplaceSubTree (C++).

You can look at the Roku client logs or Roku server logs to confirm if automatic detection is working. The mentioned commands are displayed in the Roku client or server logs only in the case of automatic detection. For Roku client, you will see UpdatedListContentCommand in the logs as shown below:

Roku client logs displaying if automatic detection works or not

For Roku server, you will see updatedListContent mentioned in the server logs as shown below:

Roku server logs displaying if automatic detection works or not

You can also check the export folder, located at <appname>/youi/build/<platform>/Debug/, that will contain a new file called _UpdatedListContent.json with data if automatic detection is working. To know more about how to work with Roku logs, see Working with Roku Logs.

Note There is a known issue affecting focus feedback while a list update is in progress. If an application modifies properties on a list item or uses the React Native Animated API for focus feedback, the list update changes aren’t applied while a list update is in progress. This can result in focus appearing to jump over list items. This issue does not affect FocusIn and FocusOut animations exported from After Effects.

When to Manually Export List Changes

If the contents of list is not refreshed automatically, the application must use the ReplaceSubtree (C++) or exportSubtree (React Native) methods for the changes to be reflected on the Roku client. This results in the entire list being re-exported, not just the items that have changed.

As described above, You.i Roku Cloud automatically detects if an entire list item within a list of lists gets added or deleted. However, if the contents of a child list are changed or nodes are added or removed from a list without child lists, your app needs to manually export those changes, replacing the entire list. Passing a node within a list as a parameter to ReplaceSubtree or exportSubtree results in replacing the entire list item that node belongs to. Replacing a single list item in this manner should generally be performant, although modifying list items simultaneously may slow the down the performance.

The following examples illustrate adding a single list item at a time and re-exporting every time a new item is added, which may result in poor user experience. To improve user experience, your app needs logic to determine how many list items to add at a time and how to populate lists based on the data flow. For example, if a list with ~10 list items works smoothly, but adding more list items results in poor user experience (depending on how big or complex is the list items data), then you need to test these scenarios thoroughly for your app to avoid poor user experience or Roku certification failure.

exportSubTree (React Native)

import {
  NativeModules,
  findNodeHandle,
  FlatList
  } from 'react-native'
const Cloud = NativeModules.Cloud;
...
<FlatList
  ref={(ref) => this._listRef = ref}
  data={this.state.listData}
  onEndReached={() => {
    this.state.listData.push{[NEW_LIST_ITEM_DATA]};
    this.setState({listData: this.state.listData});
    Cloud.exportSubtree(listRefHandle, true);
  }}
 ...
/>

ReplaceSubTree (C++)

class MainScreen{
    
    CYIListView m_singleRowList;
}

void MainScreen::AddListItem()
{
    CYINodeAdapter *pAdapter = m_singleRowList->GetAdapter();
    size_t itemsCount = pAdapter->GetItemsCount();
    pAdapter->ItemAddedAtIndex(itemsCount);
    CYICloud::GetInterface().ReplaceSubtree(m_singleRowList);
}

Performance

Due to the nature of the platform, list design may have to be simplified for Roku. Complex designs may have performance issues, such as long screen loading times and slow scrolling. Performance can be especially impacted by scrolling between lists in a list of lists, and loading and rendering many views. Performance for both these areas is specified in the Roku Certification requirements.

Reducing the number of items in your lists, especially in lists of lists, will improve performance, as well as reducing the complexity of the list items themselves. If the size of your lists is based on the dynamically fetched data, it should be capped to avoid the screens taking an unexpectedly long time to load.

You.i React Native Apps

Both VirtualizedList and FlatList are supported for Roku. Import the Cloud module to ensure that APIs required for Roku are available. Use Cloud Module’s isCloudServer to conditionally execute code blocks for Roku.

Overriding the Default Focus for Lists in You.i React Native Apps

In some situations, you may want to override the default focus behavior for lists on Roku. When a user sees a list for the first time, you may want to place focus on the first item in the list, but when the user returns to this list, you may want to place focus on the last-selected item. As another example, when a user leaves a list and enters a navigation panel, you might want to place focus on the current tab in the panel or on the first panel. To handle these types of cases, you can manually set focus relationships.

Apps Using the After Effects Workflow

There are two ways to override the default focus behavior for lists when using the After Effects workflow for a app. If both options are used, the first takes precedence.

1. Use the Cloud Module

You can control where focus moves when a user enters or exits a list (ListRef) with the setIncomingFocusStyle() method and the setOutgoingFocusStyle() method of the Cloud module.

2. Add Hints to Your After Effects Compositions

By default, when a user enters a list, focus is placed on the first item in the list. To override this behavior, you can add a hint as a comment on your After Effects composition:

Screen capture showing focus hints in After Effects

When a user enters a list, there are three hints you can use:

  • incomingFocusStyle:closest: Move focus to the closest list item. The closest item is computed locally on the client to keep request latency low.
  • incomingFocusStyle:previousItem: Move focus to the item that was selected the last time this list had focus. The list item is computed locally on the client to keep request latency low.
  • incomingFocusStyle:server: The You.i Engine Cloud server computes where focus should go inside the list. This setting gives you focus behavior that exactly matches other platforms, but it results in higher network request latency.

When a user leaves a list, there are three hints you can use:

  • outgoingFocusStyle:closest: Move focus to the node closest to the list item, based on the size of the list item. The node is computed locally on the client to keep request latency low.

    Set focus to the item closest to the list item

  • outgoingFocusStyle:focusMap: Move focus to the node closest to the list, based on the size of the list. The node is computed locally on the client to keep request latency low. This setting is equivalent to the Cloud module method Cloud.setOutgoingFocusStyle(findNodeHandle(this.listRef), "closestToList").

    Image

  • outgoingFocusStyle:server: The You.i Engine Cloud server computes where focus should go outside the list. This setting gives you focus behavior that exactly matches other platforms, but it results in higher network request latency.

Apps Using JSX

When using JSX, you can control where focus moves when a user enters or exits a list with the setIncomingFocusStyle() method and the setOutgoingFocusStyle() method of the Cloud module.

You.i Engine One C++ Apps

Consider the following when working with You.i Platform apps for Roku:

  • If an exported list is empty, such as Search Screen, call CYICloud::GetInterface.ReplaceSubtree(pList) once the list has content to ensure that the content is refreshed.
  • Grid lists can only scroll in one direction. This means that you can’t make a grid that’s larger than the screen in both dimensions. ComponentScrollingView is not suitable for developing an EPG, but you can use a separate EPG component.
  • It’s not possible to replace a single child list; the parent list must be replaced.

Overriding the Default Focus for Lists in You.i Engine One C++ Apps

In some situations, you may want to override the default focus behavior for lists on Roku. When a user sees a list for the first time, you may want to place focus on the first item in the list, but when the user returns to this list, you may want to place focus on the last-selected item. As another example, when a user leaves a list and enters a navigation panel, you might want to place focus on the current tab in the panel or on the first panel. To handle these types of cases, you can manually set focus relationships.

By default, when a user enters a list, focus is placed on the first item in the list. To override this behavior, you can add a hint as a comment on your After Effects composition:

Screen capture showing focus hints in After Effects

When a user enters a list, there are three hints you can use:

  • incomingFocusStyle:closest: Move focus to the closest list item. The closest item is computed locally on the client to keep request latency low.
  • incomingFocusStyle:previousItem: Move focus to the item that was selected the last time this list had focus. The list item is computed locally on the client to keep request latency low.
  • incomingFocusStyle:server: The You.i Engine Cloud server computes where focus should go inside the list. This setting gives you focus behavior that exactly matches other platforms, but it results in higher network request latency.

When a user leaves a list, there are three hints you can use:

  • outgoingFocusStyle:closest: Move focus to the node closest to the list item, based on the size of the list item. The node is computed locally on the client to keep request latency low.

    Set focus to the item closest to the list item

  • outgoingFocusStyle:focusMap: Move focus to the node closest to the list, based on the size of the list. The node is computed locally on the client to keep request latency low. This setting is equivalent to the Cloud module method Cloud.setOutgoingFocusStyle(findNodeHandle(this.listRef), "closestToList").

    Image

  • outgoingFocusStyle:server: The You.i Engine Cloud server computes where focus should go outside the list. This setting gives you focus behavior that exactly matches other platforms, but it results in higher network request latency.

Legacy C++ Apps

The following limitations apply to Roku lists in C++ apps:

  • An ideal Roku list item template consists of four to eight views.
  • Various scrollTo functions, such as scrollToEnd, scrollToIndex, scrollToItem, and scrollToOffset, do not work on carousel lists.
  • Calling scrollTo functions repeatedly on a list with magnets results in unexpected behavior.
  • You.i TV recommends using non-animated scrolling if you’re scrolling across many list items. Animated scrolling will result in a poor user experience.