beamer
beamer copied to clipboard
How to beam to tab in BottomNavigationBar?
Hello,
I would like to beam to a specific tab, but for some reason I can't get it to work.
This does not do anything: Beamer.of(context) .beamToNamed(kHomeRecognitionTabRoute);
It only logs in the main delegate as routes: /home/recognition
-
kHomeRoute
:/home
-
kHomeRecognitionTabRoute
:/home/recognition
This is my main delegate
final routerDelegate = BeamerDelegate(
initialPath: kSplashRoute,
routeListener: (RouteInformation routeInformation, BeamerDelegate delegate) {
Logger().info(
routeInformation.location ?? '',
category: 'routes',
);
},
transitionDelegate: const NoAnimationTransitionDelegate(),
locationBuilder: (routeInformation, _) {
if (routeInformation.location == null) {
return NotFound();
}
switch (routeInformation.location) {
case kSplashRoute:
return SplashLocation(routeInformation);
case kLoginDomainRoute:
return LoginLocation(routeInformation);
}
if (routeInformation.location!.startsWith(kHomeRoute)) {
return HomeLocation(routeInformation);
}
return NotFound();
},
);
HomeLocation
class HomeLocation extends BeamLocation<BeamState> {
HomeLocation(RouteInformation routeInformation) : super(routeInformation);
@override
List<String> get pathPatterns => [
kHomeRoute,
];
@override
List<BeamPage> buildPages(BuildContext context, BeamState state) => [
const BeamPage(
key: ValueKey('home'),
title: 'Home',
type: BeamPageType.scaleTransition,
child: HomeScreen(),
)
];
}
HomeScreen
final beamerHomeKey = GlobalKey<BeamerState>();
final routerDelegate = BeamerDelegate(
locationBuilder: RoutesLocationBuilder(
routes: {
kHomeRoute: (context, state, data) => const HomeTabs(),
kHomeNotificationsRoute: (context, state, data) => const BeamPage(
child: NotificationsScreen(),
type: BeamPageType.slideRightTransition,
),
},
),
);
class HomeScreen extends ConsumerStatefulWidget {
const HomeScreen({super.key});
@override
HomeScreenState createState() => HomeScreenState();
}
class HomeScreenState extends ConsumerState<HomeScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const CustomAppBar(),
body: Beamer(
key: beamerHomeKey,
routerDelegate: routerDelegate,
),
);
}
}
HomeTabs
final _routerDelegates = [
BeamerDelegate(
initialPath: kHomeHomeTabRoute,
routeListener:
(RouteInformation routeInformation, BeamerDelegate delegate) {
Logger().info(
routeInformation.location ?? '',
category: 'routes_home_tabs',
);
},
locationBuilder: (routeInformation, _) {
return TabHomeLocation(routeInformation);
},
),
BeamerDelegate(
initialPath: kHomeRecognitionTabRoute,
locationBuilder: (routeInformation, _) {
return TabRecognitionLocation(routeInformation);
},
),
BeamerDelegate(
initialPath: kHomeIncentivesTabRoute,
locationBuilder: (routeInformation, _) {
return TabIncentivesLocation(routeInformation);
},
),
BeamerDelegate(
initialPath: kHomeMoreTabRoute,
locationBuilder: (routeInformation, _) {
return TabMoreLocation(routeInformation);
},
),
];
class HomeTabs extends ConsumerStatefulWidget {
const HomeTabs({Key? key}) : super(key: key);
@override
HomeState createState() => HomeState();
}
class HomeState extends ConsumerState<HomeTabs> {
int currentIndex = 0;
@override
Widget build(BuildContext context) {
var tr = ref.watch(localizationProvider).translations;
return Scaffold(
body: IndexedStack(
index: currentIndex,
children: [
Beamer(
routerDelegate: _routerDelegates[0],
),
Beamer(
routerDelegate: _routerDelegates[1],
),
Beamer(
routerDelegate: _routerDelegates[2],
),
Beamer(
routerDelegate: _routerDelegates[3],
),
],
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: currentIndex,
items: [
BottomNavigationBarItem(
label: tr['global.home'],
icon: const Icon(
Icons.home,
),
),
BottomNavigationBarItem(
label: tr['global.recognitions'],
icon: const Icon(
Icons.handshake,
),
),
BottomNavigationBarItem(
label: tr['global.gifts'],
icon: const Icon(
Icons.card_giftcard,
),
),
BottomNavigationBarItem(
label: tr['global.more'],
icon: const Icon(
Icons.person,
),
),
],
onTap: (index) {
if (index != currentIndex) {
setState(() => currentIndex = index);
_routerDelegates[currentIndex].update(rebuild: false);
}
},
),
);
}
}
What am I doing wrong so I can navigate to the tab from anywhere?
Thanks!
I had to do the same, I ended up using Bloc (Already used for other stuff in my app)
I created a NavigationBloc
, with a ChangeTabEvent
, and listening for this event in the HomeTabs
Class using BlocListener
.
Then you can call the same logic you got in your onTap
Method
@vixez Hi! Did you manage to find the answer?
I had to do the same, I ended up using Bloc (Already used for other stuff in my app) I created a
NavigationBloc
, with aChangeTabEvent
, and listening for this event in theHomeTabs
Class usingBlocListener
. Then you can call the same logic you got in youronTap
Method
Hello @alanlanglois
I'm also using Bloc in my app, but I'm struggling with nested routes and beamer key placement. Could you provide a code example of your implementation?
Sure, It's a lot of file, I'll make it short if you have any struggle with my explaination let me know. I have a NavigationBloc (Using Freezed to minimize the boilerplate):
- a NavigationEvent :
const factory NavigationEvent.openSection(SectionName sectionId) = _OpenSectionEvent;
- a NavigationState :
const factory NavigationState.openSection(SectionName sectionId) = _OpenSection;
- the NavigationBloc itself just pass the event to a state:
on<NavigationEvent>((event, emit) {
event.when(
openSection: (sectionId, subSectionId, directSub) {
emit(const NavigationState.initial());
emit(NavigationState.openSection(sectionId, subSectionId, directSub));
}
});
And then you have your navigation UI component :
Widget build(BuildContext context) {
ThemeData theme = Theme.of(context);
return Scaffold(
// use an IndexedStack to choose which child to show
body: IndexedStack(
index: _currentIndex,
sizing: StackFit.expand,
children: [
// use Beamer widgets as children
Beamer(
key: _beamerKey0,
backButtonDispatcher: BeamerBackButtonDispatcher(
delegate: _routerDelegates[0]!,
routerDelegate: _routerDelegates[0]!,
),
Beamer(
key: _beamerKey1,
routerDelegate: _routerDelegates[1]!,
),
Beamer(
key: _beamerKey2,
routerDelegate: _routerDelegates[2]!,
),
Beamer(
key: _beamerKey3,
routerDelegate: _routerDelegates[3]!,
),
],
),
bottomNavigationBar: buildBottomNavigationBar(context, theme));
}
Widget buildBottomNavigationBar(BuildContext context, ThemeData theme) {
//There you add your bloc listener
return BlocListener<NavigationBloc, NavigationState>(
listener: (context, state) {
state.whenOrNull(
openSection: (sectionName,) {
int? sectionId = Const.getSectionId(sectionName); //you could also use int I prefer use const :)
(sectionId != null)
? _handleOnTabNav(sectionId, subSection: subSection, directSub: directSub)
: null;
});
},
),
child: // your navigation bottom bar
}
/// And finally the method that change the tab section and the focus on nested nav
_handleOnTabNav(int index) {
if (_currentIndex != index && index >= 0 && index < _routerDelegates.length) {
setState(() {
_prevIndex = _currentIndex; // for back navigation if I remember well
_currentIndex = index;
});
_routerDelegates[index]
}
}