I am using GoRouter with Stateful Shell Navigation with multiple StatefulShellRoute
s (StatefulShellRoute.indexedStack
), and several StatefulShellBranch
es under each. The shell used for routing depends on the role of the user.
Here is the code for one of those shell routes:
StatefulShellRoute.indexedStack(
builder: (context, state, navigationShell) {
return ScaffoldWithNestedNavigationRole1(
navigationShell: navigationShell);
},
branches: [
// Home
StatefulShellBranch(
navigatorKey: _role1shellNavigatorKeyHome,
routes: [
GoRoute(
path: '/home_role1',
pageBuilder: (context, state) => const NoTransitionPage(
child: HomeScreenRole1(
title: 'This is Role 1'),
),
routes: [
GoRoute(
path: 'cars_list',
builder: (context, state) => const ItemListScreen(
title: 'Cars List',
itemType: 'Car',
),
routes: [
GoRoute(
path: 'item/:id',
builder: (context, state) {
final id = state.pathParameters['id'];
return ItemScreen(
itemType: 'Car', itemId: id!);
},
)
]),
GoRoute(
path: 'vehicles_list',
builder: (context, state) => const VehiclesListScreen(),
routes: [
GoRoute(
path: ':id',
builder: (context, state) {
final id = state.pathParameters['id'];
return VehicleScreen(vehicleId: id.toString());
},
)
]),
GoRoute(
path: 'boats_list',
builder: (context, state) => const ItemListScreen(
title: 'Boats List',
itemType: 'Boat',
),
routes: [
GoRoute(
path: 'item/:id',
builder: (context, state) {
final id = state.pathParameters['id'];
return ItemScreen(
itemType: 'Boat', itemId: id!);
},
)
]),
GoRoute(
path: 'theme',
builder: (context, state) => const ThemeScreen(),
),
GoRoute(
path: 'youtube',
builder: (context, state) => const YoutubeScreen()
)
])
]),
// Health Record
StatefulShellBranch(
navigatorKey: _role1shellNavigatorKeyHealthRecord,
routes: [
GoRoute(
path: '/health_record_role1',
name: 'health-record-role1',
pageBuilder: (context, state) => const NoTransitionPage(
child: HealthRecordScreen(
title: 'Role 1',
)),
)
]),
// Clinic
StatefulShellBranch(
navigatorKey: _role1shellNavigatorKeyClinic,
routes: [
GoRoute(
path: '/clinic_role1',
name: 'clinic-role1',
pageBuilder: (context, state) => const NoTransitionPage(
child: ClinicScreen(
title: 'Role 1',
)),
)
]),
]),
and ScaffoldWithNestedNavigationRole1
is below, where an appBar
and bottomNavigationBar
are specified:
class ScaffoldWithNestedNavigationRole1 extends StatelessWidget {
const ScaffoldWithNestedNavigationRole1(
{super.key, required this.navigationShell});
final StatefulNavigationShell navigationShell;
void _goBranch(int index) {
print('_goBranch: ${navigationShell.route.branches[0].routes[0]}');
navigationShell.goBranch(index,
initialLocation: index == navigationShell.currentIndex);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const CommonAppBar(),
body: navigationShell,
bottomNavigationBar: NavigationBar(
selectedIndex: navigationShell.currentIndex,
destinations: const [
NavigationDestination(icon: Icon(Icons.home), label: 'Home1'),
NavigationDestination(
icon: Icon(Icons.medical_information), label: 'Record1'),
NavigationDestination(
icon: Icon(Icons.local_hospital), label: 'Clinic1')
],
onDestinationSelected: _goBranch,
),
);
}
}
One of my screens plays a YouTube video using package youtube_player_flutter. When the user selects the YouTube full screen option, the video orientation changes to landscape (correct behavior), however, the appBar
and bottomNavigationBar
don’t hide. I want the appBar
and bottomNavigationBar
to hide when the YouTube video is full screen.
If I rotate the device itself to landscape, the appBar
and bottomNavigationBar
still don’t hide.
I’ve tried a couple of different approaches to hide the appBar
and bottomNavigationBar
:
A. SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);
- tried calling it in initState(), but it had no affect
B. OrientationBuilder
- when device is landscape, set appBar and bottomNavigationBar heights to 0
- did not work
Code is below:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:youtube_player_flutter/youtube_player_flutter.dart';
class YoutubeScreen extends StatefulWidget {
const YoutubeScreen({super.key});
@override
State<YoutubeScreen> createState() => _YoutubeScreenState();
}
class _YoutubeScreenState extends State<YoutubeScreen> {
late YoutubePlayerController _controller;
@override
void initState() {
super.initState();
_controller = YoutubePlayerController(
initialVideoId: '5Peo-ivmupE',
flags: const YoutubePlayerFlags(
autoPlay: true,
mute: false,
),
);
// SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);
}
@override
Widget build(BuildContext context) {
final ytPlayer = YoutubePlayerBuilder(
player: YoutubePlayer(
controller: _controller,
showVideoProgressIndicator: true,
progressIndicatorColor: Colors.amber,
progressColors: const ProgressBarColors(
playedColor: Colors.amber,
handleColor: Colors.amberAccent,
),
onReady: () {
_controller.addListener(() {});
},
),
builder: (context, player) => player,
);
return OrientationBuilder(
builder: (context, orientation) {
if (orientation == Orientation.portrait) {
return Scaffold(
resizeToAvoidBottomInset: true,
body: ytPlayer
);
} else {
return Scaffold(
appBar: const PreferredSize(
preferredSize: Size.fromHeight(0),
child: SizedBox(height: 0),
),
bottomNavigationBar: const SizedBox(height: 0),
body: ytPlayer
);
}
}
);
}
}
Demo:
Now, I’m stuck. I can’t figure out how to hide the appBar
and bottomNavigationBar
when the YouTube video is full screen.
Looking for suggestions… anyone know how to accomplish this?
Thank you.