i am new to flutter and i would like to have a shared appBar and bottomNavigationBar
the way i am currently using is implementing them in spearte files and importing them in each screen but i need to make one screen contains the appbar and the bottomNavigationBar and the content of the body renders diffrent views according to the routes and i can't make it at main page because the main page renders welcome screen
in reactJS i was importing the header and footer and make my routes between them how can i make somthing similar in flutter
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: navBar(),
body: SingleChildScrollView(reverse: true, child: ScanPassport()),
bottomNavigationBar: bottomNavigation(),
currentIndex: _selectedIndex,
onTap: _onItemTapped,
showSelectedLabels: false,
showUnselectedLabels: false,
type: BottomNavigationBarType.fixed,
),
);
}
}
A couple of options:
Use MaterialApp() router. There's a tutorial here showing how to refactor your Scaffold() so you don't have duplicate code for appBar, bottomNavigationBar, etc. This is the official Flutter method for view routing.
If you need to swap out your Scaffold() body but can't change your other Scaffold() elements, you can create a widget for the body that takes a "page" value and change what it returns from build() based on the "page" value passed. The widget holding your Scaffold can be stateful and your bottom navigation bar can setState() the page number.
In your context, You can just have a single scaffold homepage screen after logged in success or after welcome screen (depends up app). Once you navigate to homepage, You will have appBar and bottom navigation bar at top and bottom respectively. The remaining portion at center will be your body content of the selected tab. Once you switched the tap on bottom navigation, you should change the content rather than using routes for switching the body content. The current page status will be preserved on homepage.
Related
I have a scenario where I need to use a BottomNavigationBar while ensuring the following:
When changing tabs, where a tab is a particular screen, screens should not refresh, but the state of each screen should be maintained
It must be possible to change tab using both the BottomNavigationBar or Navigator
I am trying to build a proof of concept (on GitHub) considering the above but it is not working as it should be.
In the proof of concept, I have 3 screens:
MainScreen,
Settings
ProfileSettings.
, and only 2 items on the BottomNavigationBar:
MainScreen
Settings
On MainScreen, there is a button that allow navigation to Settings. On Settings, there are two buttons, to Navigate to Settings and ProfileSettings respectively. So ProfileSettings can only be reached from the button on the Settings tab.
If I am on ProfileSettings, I tap on MainScreen on the bottomNavigationBar, once on MainScreen, I tap on Settings, I should see ProfileSettings, this is what I mean by preserving the state.
Below is probably the most important part of the proof of concept. It is part of a page called "PageWithBottomBar.dart" that loads the MainScreen,Settings and ProfileSettings page.
#override
Widget build(BuildContext context) {
....
Scaffold(
appBar: AppBar(title: Text("Trying bottom bar")),
bottomNavigationBar: bottomNavBar,
body: Navigator(
key: _navigatorKey,
onGenerateRoute: (settings){
Widget widget =MainScreen();
if (settings.name == "/main"){
widget = MainScreen();
} else if (settings.name == "/settings"){
widget = Settings();
}
else if (settings.name == "/settings/profile"){
widget = ProfileSettings();
}
return MaterialPageRoute(builder: (context)=> widget,settings: settings);
},
initialRoute: "/main",
),
);
}
Currently, in the proof of concept, I am getting the following problems:
State is not being preserved
When I use Navigator, I can switch to a different tab, but I cannot make a NavigationBarItem active when using Navigator
i´ve an app that should support responsive design.
In the mobile view I am using the scaffold drawer for the main menu:
return Scaffold(
appBar: AppBar(
title: title,
),
drawer: MainMenuDrawer(),
body: body,
);
In the desktop view the menu should always be visible, so i don´t use the drawer propery. Instead of that i´ve added the same menu as widget into a row:
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: true ,
title: title
),
body: Row(
children: [
MainMenuDrawer(),
Expanded(child: body),
],
),
);
The menu has a logout button which sends an event to my authentication bloc and pops all pages from the navigation stack, to get to the first page (login page).
authenticationBloc.add(AuthenticationEvent.loggedOut());
while (Navigator.canPop(context)) {
Navigator.pop(context);
}
The authentication bloc is as singleton:
#singleton
class AuthenticationBloc extends Bloc<AuthenticationEvent, AuthenticationState>
As long as i am using the mobile view, I can logout from everywhere and it´s works as expected.
But when I switch to the desktop view the logout button doesn´t work anymore.
In the debug mode, I can see, that the eventController of the authBloc is already closed, so no event is added:
void add(Event event) {
if (_eventController.isClosed) return; <- isClosed is true
Does anyone know why this happened in the desktop view?
i´ve found the problen In the onTap method of my listitem.
To close the drawer i´ve called the Navigator.pop(context).
But this will cause the previous page to be closed when the menu is used as drawer.
My project is a todo app and I have these parts:
Meetings
Checks
Alarms
and all of these parts have a details screen, add screen, list screen, edit screen and search screen.
I'm tired of creating a separate screen for each section, so I need a way to implement all these screens using inheritance and less code.
Any idea will be great.
Set Navigator route to screen with an argument for the part type you want to render (e.g. Meetings).
Receive that arg in the new screen, then render specific widgets based on that.
For example, set the Navigator to pass the part:
Navigator.of(context).pushNamed(
DetailsScreen.routeName,
arguments: 'details',
);
Then in the new screen, use the argument to render the rest of the page:
final sourcePage = ModalRoute.of(context)!.settings.arguments as String;
// passed from last page
You can use this var to render different elements in the page:
return Scaffold(
appBar: AppBar(
title: Text('$sourcePage'),
backgroundColor: sourcePage.toLowerCase() == 'details'
? Colors.green
: Colors.black26,
),
);
I am developing an app in flutter with few screen I want to add AppBar in home screen and want that appbar to be fixed in all screen, but in the dummy code which i have written the complete screen is getting replaced by that.
Below is the screen
HomeScreen - here i have created appbar
When I click on AddPolicy Button, i get that screen where right now i just have a text but the complete screen gets replaced as below, but I want the header appBar should be fixed. How can I achieve this.
Below is the code
homepage - https://github.com/lodha13/samkit/blob/main/lib/screens/home.dart
AddPolicy page - https://github.com/lodha13/samkit/blob/main/lib/screens/add_policy.dart
You have two opptions:
have a global widget for appbar and use it on each different page,
or
You can have one Scaffold in your main.dart and instead of generating a new one for each page, only change the body parameter using setState. for example:
// have as many widget as you want for each page
const body1 = Text("body1"); //just a simple example, you can change it to whatever you want.
const body2 = Text("body2");
return Scaffold(
appBar: AppBar(
title: const Text('Sample Code'),
),
body: handleBody(selectedIndex)
);
then you can have a function to handle bodies:
handleBody(int index){ // you can pass different input for body selection I have used an int for simplicity
if(index == 1){return body1;}
if(index ==2) {return body2;}
// and so on
}
now with changing the selectedIndex you can show different bodies. Personally, I prefer to have a list of widgets and select one of them based on selectedIndex.
Since i want this to be my layout i was trying to implement it with a showModalBottomSheet but the problem is that this widget only works on the button click as it is showing me error when i am trying to call the method as it is in the initState method. So then I started to work with bottomSheet value present in the scaffold but then the background is being displayed only upto the starting of the bottom sheet creating the distance between the model sheet and the background whereas I want it to overlap like in the image..How should I prepare this layout.
There is no such parameter as "bottomSheet" in Scaffold, there is one called bottomAppBar, which is used for making Bottom Bars like the one on the Youtube Android App. So this should help you make the basic structure.
Use a Stack widget to put widgets on top of each other, in first layer, add the image using the NetworkImage widget, then in the second layer, make a Column, like this:
#override
Widget build() => Scaffold(
body: _body(),
);
_body() => Stack(
children: <Widget>[
NetworkImage(your_url_here),
Column(
children: <Widget>[
_basicDetails(),
_guidePanel(),
]
),
]);
Then create 2 new methods after the _body method like this:
_body() => Stack(...);
_basicDetailsPage() => Container();
_guidePanel() => Container();
Create your layout in these 2 methods. Comment if you need more help :)
For additional help, please join the Facebook Group "Let's Flutter With Dart"