Reputation: 71
The app contains TabBar as well as BottomNavigationBar. When I tried to navigate within the body of tab bar view it navigates full screen.
This is the result I am trying to get when clicked on button- Expected Result
But I am getting this Current Output
Here I have attached the code-
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Traveler"),
bottom: new TabBar(controller: _controller, tabs: <Tab>[
new Tab(text: "NEW"),
new Tab(text: "HOTELS"),
new Tab(text: "FOOD"),
new Tab(text: "FUN"),
]),
),
body: new TabBarView(
controller: _controller,
children: <Widget>[
new NewPage(_index),
new HotelsPage(_index),
new FoodPage(_index),
new FunPage(_index),
],
),
bottomNavigationBar: new BottomNavigationBar(
currentIndex: _index,
onTap: (int _index) {
setState(() {
this._index = _index;
});
},
items: <BottomNavigationBarItem>[
new BottomNavigationBarItem(
icon: new Icon(Icons.home),
title: new Text("Home"),
),
new BottomNavigationBarItem(
icon: new Icon(Icons.favorite),
title: new Text("Favorites"),
),
]),
);
}
}
class NewPage extends StatelessWidget {
final int index;
NewPage(this.index);
@override
Widget build(BuildContext context) {
return new Center(
child: RaisedButton(
onPressed: (){
Navigator.push(context,MaterialPageRoute(builder: (context)=>InsideTabViewPage()), );
},
child: new Text('NewPage, index: $index')),
);
}
}
Upvotes: 3
Views: 13474
Reputation: 231
Just spent some time exploring this issue. I decided to go with the GoRouter and Shell Route approach and put together a simple example in DartPad to test it out based on this.
The only drawback with this first approach is the lack of stateful navigation, i.e. if you go to inner-home and navbar over to settings and back, you're sent back to the base home page, not inner-home. Luckily, StatefulShellRoute exists and I found this example in the github repo. I took some time and worked it into a simpler example as an extension of the previous in this DartPad.
Upvotes: 0
Reputation: 2654
A good solution to this problem is to use the go_router package from pub.dev it's a great package for routing, it's a flutter favorite package
It address specifically the nested routing issue you are asking about, by implementing something they call shell routing you can basically define some routes of your application as having a shell, that shell can be anything, like in your case a Scaffold with a bottomNavigationBar,
When such a route is invoked the Navigation will happen within that shell (having that shell stay in place during the navigation), using another Navigator independent from the Root Navigator of your application
Upvotes: 1
Reputation: 53307
You can achieve this by creating a new Navigator
widget that sits somewhere under the main app navigator,
Here is test example:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData.dark().copyWith(
elevatedButtonTheme: ElevatedButtonThemeData(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.blueGrey[800]),
)),
),
home: MyApp()));
}
//Store this globally
final GlobalKey<NavigatorState> _navKey = GlobalKey<NavigatorState>();
class MyApp extends StatefulWidget {
MyApp({Key? key}) : super(key: key);
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
late final TabController _tabController;
@override
void initState() {
_tabController = TabController(length: 2, vsync: this);
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Nested Navigator'),
bottom: TabBar(
controller: _tabController,
tabs: [
Tab(
child: Text('First Tab'),
),
Tab(
child: Text('Second Tab'),
),
],
),
),
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
BottomNavigationBarItem(
icon: Icon(Icons.favorite), label: 'Favorites'),
],
),
body: Navigator(
key: _navKey,
onGenerateRoute: (_) => MaterialPageRoute(
builder: (_) => TabBarView(
controller: _tabController,
children: [
FirstPage(),
SecondPage(),
],
),
),
),
);
}
}
class FirstPage extends StatelessWidget {
const FirstPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('First Page'),
ElevatedButton(
onPressed: () {
_navKey.currentState!.push(
MaterialPageRoute(
builder: (_) => SubFirstPage(),
),
);
},
child: Text('Go to Nested Page 1'))
],
),
),
);
;
}
}
class SecondPage extends StatelessWidget {
const SecondPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Second Page'),
ElevatedButton(
onPressed: () {
_navKey.currentState!.push(
MaterialPageRoute(
builder: (_) => SubSecondPage(),
),
);
},
child: Text('Go to Nested Page 2'),
)
],
),
),
);
}
}
class SubFirstPage extends StatelessWidget {
const SubFirstPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Nested Page'),
),
body: Center(
child: Text('From First Page'),
),
);
}
}
class SubSecondPage extends StatelessWidget {
const SubSecondPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Second Nested Page'),
),
body: Center(
child: Text('From Second Page'),
),
);
}
}
And the result is:
You can read more about nested navigation in Navigator 1.0 API here
Upvotes: 15