simple_tv_navigation 0.0.1+34
simple_tv_navigation: ^0.0.1+34 copied to clipboard
A highly optimized TV navigation system for Flutter applications, providing efficient ID-based focus management for TVs, set-top boxes, and game consoles.
simple_tv_navigation #
A highly optimized TV navigation system for Flutter applications, providing efficient ID-based focus management for TVs, set-top boxes, and game consoles.
Features #
- ID-based navigation: Navigate between UI elements using unique IDs
- Direction-based focus management: Define clear navigation paths with up, down, left, and right connections
- Dynamic navigation paths: Support for dynamic navigation paths that can change at runtime
- Autofocus support: Automatically focus elements when they appear
- Keyboard navigation: Built-in support for remote control and keyboard arrow keys
- Focus visualization: Customizable focus highlighting
- Scroll to focused element: Automatically scrolls to bring focused elements into view
- Focus events: Callbacks for focus, blur, selection, and navigation events
- BLoC architecture: Clean, testable architecture using Flutter BLoC pattern
Installation #
Add to your pubspec.yaml
:
dependencies:
simple_tv_navigation: ^0.0.1+28
Usage #
Basic Setup #
Wrap your app with the TvNavigationProvider
:
void main() {
runApp(
TvNavigationProvider(
child: MyApp(),
),
);
}
Creating Focusable Elements #
Add focusable elements to your UI:
TVFocusable(
id: 'button1',
leftId: 'sidebar_item',
rightId: 'button2',
upId: 'top_menu',
downId: 'bottom_button',
showDefaultFocusDecoration: true,
onSelect: () {
// Handle selection
print('Button 1 selected');
},
child: Container(
padding: const EdgeInsets.all(16),
color: Colors.blue,
child: const Text('Button 1'),
),
)
Custom Focus Styling #
Use the builder to create custom focus effects:
TVFocusable(
id: 'custom_button',
builder: (context, isFocused, child) {
return AnimatedContainer(
duration: const Duration(milliseconds: 200),
transform: isFocused
? Matrix4.identity()..scale(1.1)
: Matrix4.identity(),
decoration: BoxDecoration(
color: isFocused ? Colors.red : Colors.grey,
borderRadius: BorderRadius.circular(8),
boxShadow: isFocused
? [BoxShadow(color: Colors.red.withOpacity(0.5), blurRadius: 10)]
: null,
),
padding: const EdgeInsets.all(16),
child: Text(
'Custom Button',
style: TextStyle(
color: Colors.white,
fontWeight: isFocused ? FontWeight.bold : FontWeight.normal,
),
),
);
},
)
Dynamic Navigation Paths #
Use dynamic ID callbacks for complex navigation scenarios:
TVFocusable(
id: 'dynamic_button',
dynamicLeftId: () {
// Return different IDs based on state
return isSpecialCase ? 'special_button' : 'normal_button';
},
child: Text('Dynamic Navigation'),
)
Programmatic Navigation #
Control focus programmatically using context extensions:
// Move focus in a direction
context.moveFocus(TvFocusDirection.right);
// Set focus to a specific element
context.setFocus('settings_button');
// Select currently focused element
context.selectCurrent();
// Check if element is focused
bool isFocused = context.isElementFocused('my_button');
// Enable/disable TV navigation
context.setTvNavigationEnabled(false);
Advanced Features #
Managing Multiple Navigation Areas #
For complex UIs with multiple navigation areas (like sidebars and main content):
- Use separate TvNavigationProvider widgets for each area
- Enable/disable navigation areas as needed
// In your sidebar state:
context.setTvNavigationEnabled(true); // Enable sidebar navigation
// In your content area:
context.setTvNavigationEnabled(false); // Disable content navigation
Controlling System Focus #
The package includes functionality to exclude Flutter's system focus when using TV navigation. This prevents interference between the TV navigation system and Flutter's default focus system:
// Enable exclude focus (default is true)
context.disableFocus();
// Disable exclude focus
context.enableFocus();
When exclude focus is enabled (the default), Flutter's system focus will be prevented while TV navigation is active, ensuring a consistent navigation experience.
Focus Management with Lists #
When working with dynamic lists, generate unique IDs and connections:
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
final String itemId = 'item_$index';
return TVFocusable(
id: itemId,
upId: index > 0 ? 'item_${index - 1}' : null,
downId: index < items.length - 1 ? 'item_${index + 1}' : null,
child: ListTile(title: Text(items[index])),
);
},
)
License #
This project is licensed under the MIT License - see the LICENSE file for details.