Extending Your TV App with New Screens
Extending your TV app with new screens is a common task. Let’s walk through the process of adding a new screen to our drawer navigation, step by step.
Step 1: Update the Drawer Items
First, we need to add our new screen to the list of drawer items. This is done in the CustomDrawerContent
component.
Open components/CustomDrawerContent.tsx
and locate the drawerItems
array:
components/CustomDrawerContent.tsx
export default function CustomDrawerContent(props: any) {
// ... (existing code)
const router = useRouter();
const { isOpen: isMenuOpen, toggleMenu } = useMenuContext();
const styles = useDrawerStyles();
const drawerItems = [
{ name: '/', label: 'Home' },
{ name: 'explore', label: 'Explore'},
{ name: 'tv', label: 'TV'},
{ name: 'new', label: 'New Screen'}, // Add this line
];
// ... (rest of the component)
}
Step 2: Create the New Screen Component
Now, we need to create a new file for our screen component. In the app/(drawer)/
directory, create a new file named new.tsx
:
import React, { useCallback, useState } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { SpatialNavigationRoot } from 'react-tv-space-navigation';
import { scaledPixels } from '@/hooks/useScale';
import { SpatialNavigationFocusableView } from 'react-tv-space-navigation';
import { Direction } from '@bam.tech/lrud';
import { DrawerActions, useIsFocused } from '@react-navigation/native';
import { useNavigation } from 'expo-router';
import { useMenuContext } from '@/components/MenuContext';
export default function NewScreen() {
const isFocused = useIsFocused();
const navigation = useNavigation();
const [focusedIndex, setFocusedIndex] = useState(0);
const { isOpen: isMenuOpen, toggleMenu } = useMenuContext();
const onDirectionHandledWithoutMovement = useCallback(
(movement: Direction) => {
console.log("Direction " + movement);
if (movement === 'left' && focusedIndex === 0) {
navigation.dispatch(DrawerActions.openDrawer());
toggleMenu(true);
}
},
[toggleMenu, focusedIndex, navigation],
);
return (
<SpatialNavigationRoot isActive={isFocused}
onDirectionHandledWithoutMovement={onDirectionHandledWithoutMovement}>
<SpatialNavigationFocusableView onSelect={() => console.log('Button pressed!')}>
{({ isFocused }) => (
<View style={[styles.button, isFocused && styles.buttonFocused]}>
<Text style={styles.buttonText}>Click me!</Text>
</View>
)}
</SpatialNavigationFocusableView>
</SpatialNavigationRoot>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#2c3e50',
},button: {
padding: scaledPixels(10),
backgroundColor: '#3498db',
borderRadius: scaledPixels(5),
},
buttonFocused: {
backgroundColor: '#2980b9',
},
buttonText: {
color: '#ffffff',
fontSize: scaledPixels(24),
},
text: {
fontSize: scaledPixels(32),
color: '#ffffff',
},
});
Let’s break down this new screen component:
- Imports:
- We import necessary components from React Native and our custom hooks.
useIsFocused
helps us manage the active state of our screen.scaledPixels
ensures our UI scales correctly on different TV sizes.
- Component Structure:
- We wrap our content in a
SpatialNavigationRoot
component for Focus Management. - The
isActive
prop is set based on whether this screen is currently focused.
- We wrap our content in a
- Styling:
- We use
StyleSheet.create
to define our styles. scaledPixels
is used for font sizes to ensure proper scaling on different TV screens.
- We use
Step 3: Update the Drawer Navigation
Update the app/(drawer)/_layout.tsx
file to include the new screen in the drawer navigation:
<Drawer.Screen
name="new"
options={{
drawerLabel: 'New Screen',
title: 'new',
}}
/>
Customizing Your New Screen
Now that you have a basic new screen, you can customize it further:
- Add more complex layouts using additional
View
andText
components. - Implement TV-specific UI elements like focus-aware buttons or card views.
- Add data fetching or state management if your new screen needs to display dynamic content.
- Implement additional navigation within the screen if needed. Example of adding a focusable button:
import { SpatialNavigationFocusableView } from 'react-tv-space-navigation';
// Inside your component's return statement
<SpatialNavigationFocusableView onSelect={() => console.log('Button pressed!')}>
{({ isFocused }) => (
<View style={[styles.button, isFocused && styles.buttonFocused]}>
<Text style={styles.buttonText}>Click me!</Text>
</View>
)}
</SpatialNavigationFocusableView>
// Add to your styles
button: {
padding: scaledPixels(10),
backgroundColor: '#3498db',
borderRadius: scaledPixels(5),
},
buttonFocused: {
backgroundColor: '#2980b9',
},
buttonText: {
color: '#ffffff',
fontSize: scaledPixels(24),
},
Conclusion
You have added a new screen to the TV App now let’s understand more Focus Management