Navigating Screen Stacks in Roku: A Guide to Creating and Managing Multiple Screens Using Arrays and SceneGraph Components.

Amitdogra
4 min readJan 15, 2024

--

Navigating between different screens is a fundamental aspect of creating a seamless user experience in Roku applications. In this blog post, we’ll explore an effective approach to screen navigation using a Screen Controller in Roku SceneGraph.

Imagine a scenario where your Roku application has multiple screens like Home, Settings, and Info, each providing unique functionalities. How can we handle the transition between these screens smoothly and maintain a clean navigation history? The answer lies in a well-designed Screen Controller that not only simplifies the process but also enhances the overall user experience.

Let’s visualize the app structure:

                            +--------------+
| main.brs |
+--------------+
|
v
+----------------+
| MainScene |
+----------------+
|
v
+---------------------+
| ScreenController |
+---------------------+
||
+--------------------------------+
| BaseScreen |
+--------------------------------+
| | |
v v v
+--------------+ +--------------+ +--------------+
| Home | | Setting | | Info |
+--------------+ +--------------+ +--------------+
  • main.brs represents your main BrightScript file.
  • MainScene is a SceneGraph component that you use to create scenes.
  • ScreenController is a component responsible for managing the logic related to showing and hiding screens.
  • Home, Setting, and Info are screens that extend from BaseScreen.

ScreenController.xml

<?xml version="1.0" encoding="UTF-8"?>
<component name="ScreenController" extends="Group">
<script type="text/brightscript"
uri="pkg:/components/ScreenController/ScreenController.brs" />
<script type="text/brightscript"
uri="pkg:/components/ScreenController/ScreenControllerKeyEvents.brs" />
<children>
<Group id="screens" />
</children>
</component>

ScreenController.brs

sub init()
? "fun init() ScreenController"

' Initialize the screen stack and find the "screens" node in the XML
m.screenStack = []
m.screens = m.top.findNode("screens")

' Initialize the first screen (HomeScreen)
initScreen()
end sub

sub initScreen()
' Create a child screen (HomeScreen) and add it to the screen stack
screen = m.screens.createChild("HomeScreen")
addScreenToHistory(screen)
end sub

sub addScreenToHistory(screen as object)
' Hide the current screen (if any) and observe its "close" field
current = m.screenStack.peek()
if current <> invalid then
current.visible = false
end if
screen.observeField("close", "backToPreviewScreen")

' Add the new screen to the screen stack, make it visible, and set focus
m.screenStack.push(screen)
screen.visible = true
screen.setFocus(true)
end sub

function backToPreviewScreen() as boolean
' Pop the current screen from the stack
screen = m.screenStack.pop()
if screen <> invalid then
' Remove the screen from the parent node
m.screens.removeChild(screen)
' Get the new current screen
screen = m.screenStack.peek()
if screen <> invalid then
' Show the new current screen and set focus
screen.visible = true
screen.setFocus(true)
return true
else
' screen is empty, handle this acc to your need
end if
end if
return false
end function



' handle back key event to exit app
function onKeyEvent(key as string, press as boolean) as boolean
if press then
if key = "back" then
' screen stack empty , use this flag to exit your app
if not backToPreviewScreen() then
'handle this according to your requirement
end if
return true
end if
end if
return false
end function
  • addScreenToHistory: Hide the previous screen ( if any ), Observe the "close" field of the current screen, add the new screen to the screen stack, make it visible, and sets focus to true.
  • backToPreviewScreen: Removes the current screen from the stack, removes it from the parent node, gets the new current screen, and shows it with focus. If the stack is empty, you can add your logic.
Screen Navigation Flow in Roku

+-------------------------------------+
| ScreenController |
| +-------------------------------+ |
| | Screen Stack (Array) | |
| | ------------------------ + | |
| | | HomeScreen | | |
| | |------------------------| | |
| | | SettingsScreen | | |
| | +------------------------+ | |
| +-------------------------------+ |
| |
| +-------------------------------+ |
| | Event Handling | |
| | ------------------------ | |
| | | onKeyEvent for Navigation| | |
| | |------------------------| | |
| | | onButtonPress for Actions| | |
| | +------------------------+ | |
| +-------------------------------+ |
| |
| +-------------------------------+ |
| | Screen Rendering | |
| | ------------------------- | | |
| | | Scene Graph Components | | |
| | |-------------------------| | |
| | |HomeScreen,SettingsScreen| | |
| | +------------------------ + | |
| +-------------------------------+ |
+-------------------------------------+


- Screen Stack: Stack holding screens for navigation history.
- ScreenController: Manages screen creation, navigation, and stack.
- Event Handling: Handles key events for navigation and actions.
- Screen Rendering: Utilizes Scene Graph components for UI rendering.

This code manages a stack of screens, allowing navigation between them. The observeField function is used to detect when a screen should be closed or when the back button is pressed.

--

--

Amitdogra

Passionate Roku developer with a love for web technologies and backend wizardry. 🚀 ✨ #Android #Streaming #Roku #Web #Nodejs