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:

  1. 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.
  2. 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.
  3. Styling:
    • We use StyleSheet.create to define our styles.
    • scaledPixels is used for font sizes to ensure proper scaling on different TV screens.

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 and Text 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