I am using footer menu to navigate som page aside the main home page which already has AppBar with a title, I want it to be overridden.
I want it, if I navigate from Home page to meditation page, I want the menu to overridden to "MEDITATION".
Here's my footer menu:
class Footer extends StatefulWidget {
// Footer({Key? key}) : super(key: key);
#override
_FooterState createState() => _FooterState();
}
class _FooterState extends State<Footer> {
var _selectedIndex = 0;
final pages = [
Dashboard(),
Health(),
Meditation(),
Sleep(),
Sounds(),
];
#override
void initState() {
super.initState();
_selectedIndex = 0;
}
#override
Widget build(BuildContext context) {
// return GestureDetector(
return Scaffold(
bottomNavigationBar: Container(
decoration: BoxDecoration(boxShadow: [
BoxShadow(
color: dbShadowColor,
offset: Offset.fromDirection(3, 1),
spreadRadius: 1,
blurRadius: 5)
]),
child: Db5BottomNavigationBar(
items: <Db5BottomNavigationBarItem>[
Db5BottomNavigationBarItem(icon: db5_ic_home),
Db5BottomNavigationBarItem(icon: db5_ic_heart),
Db5BottomNavigationBarItem(icon: db5_ic_meditate),
Db5BottomNavigationBarItem(icon: db5_ic_sleep),
Db5BottomNavigationBarItem(icon: db5_ic_sounds),
],
currentIndex: _selectedIndex,
unselectedIconTheme: IconThemeData(color: db5_icon_color, size: 24),
selectedIconTheme: IconThemeData(color: db5_colorPrimary, size: 24),
onTap: (int index) {
setState(() {
_selectedIndex = index;
});
},
type: Db5BottomNavigationBarType.fixed,
),
),
body: SafeArea(
child: pages[_selectedIndex],
),
);
// );
}
}
Here's my Meditation Page code:
class Meditation extends StatefulWidget {
Meditation({Key? key}) : super(key: key);
#override
_MeditationState createState() => _MeditationState();
}
class _MeditationState extends State<Meditation> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0.0,
backgroundColor: appStore.scaffoldBackground,
centerTitle: true,
title: Text(
"Meditate",
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white,
fontSize: 20,
),
)),
body: Container(
alignment: Alignment.topLeft,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.only(),
child: text(
meditation_text_title,
),
)
],
),
),
),
);
}
}
This is how I rendered my footer on the main HOME PAGE:
return Scaffold(
appBar: AppBar(
backgroundColor: db5_white,
iconTheme: IconThemeData(color: sh_textColorPrimary),
actions: <Widget>[
IconButton(
icon: Icon(Icons.search),
onPressed: () {},
),
],
title: text(title,
textColor: sh_colorPrimary,
fontFamily: fontBold,
fontSize: textSizeNormal),
),
body: Stack(
children: <Widget>[
Dashboard(),
Footer(),
],
),
);
Am I doing it wrongly?
Here's how you should implement your screens.
// Name the class whatever you like
class ScreensController extends StatefulWidget {
const ScreensController({Key? key}) : super(key: key);
#override
_ScreensControllerState createState() => _ScreensControllerState();
}
class _ScreensControllerState extends State<ScreensController> {
int _selectedIndex = 0;
List<String> mainScreensTitles = [
'Dashboard',
'Health',
'Meditation',
'Sleep',
'Sounds'
];
List<Widget> screens= [
Dashboard(),
Health(),
Meditation(),
Sleep(),
Sounds(),
];
#override
Widget build(BuildContext context) {
return Scaffold(
// Indexed stack is used to prevent page rebuilds when navigating between the
//screens
body: IndexedStack(
index: _selectedIndex,
children: screens,
),
bottomNavigationBar: BottomNavigationBar(
//Toggle these booleans if needed
showSelectedLabels: false,
showUnselectedLabels: false,
onTap: (newScreenIndex) {
setState(() {
_selectedIndex = newScreenIndex;
});
},
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home_outlined),
label: mainScreensTitles[0],
),
BottomNavigationBarItem(
icon: Icon(Icons.favorite_outline),
label: mainScreensTitles[1],
),
BottomNavigationBarItem(
icon: Icon(Icons.person_outline),
label: mainScreensTitles[2],
),
BottomNavigationBarItem(
icon: Icon(Icons.person_outline),
label: mainScreensTitles[3],
),
BottomNavigationBarItem(
icon: Icon(Icons.person_outline),
label: mainScreensTitles[4],
),
],
currentIndex: _selectedIndex,
),
);
}
}
Implementation of some of your screens:
Dashboard & Meditation:
class Dashboard extends StatelessWidget {
const Dashboard({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Dashboard'),
),
body: Center(child: Text('Dashboard coming soon')),
);
}
}
class Meditation extends StatelessWidget {
const Meditation({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Meditation'),
),
body: Center(child: Text('Meditation coming soon')),
);
}
}
Related
I am trying to apply persistent_bottom_nav_bar but I keep getting error. I got similar answers and tried to follow https://pub.dev/packages/persistent_bottom_nav_bar
These are the errors that I keep getting.
The method '_BottomBarState' isn't defined for the type 'BottomBar'. & 1 positional argument(s) expected, but 0 found.
class BottomBar extends StatefulWidget {
const BottomBar({Key? key}) : super(key: key);
#override
State<BottomBar> createState() => _BottomBarState();
}
PersistentTabController _controller = PersistentTabController(initialIndex: 0);
//Screens for each nav items.
List<Widget> _NavScreens() {
return [
HomeScreen(),
const Text("History"),
];
}
List<PersistentBottomNavBarItem> _navBarsItems() {
return [
PersistentBottomNavBarItem(
icon: Icon(FluentSystemIcons.ic_fluent_home_regular),
title: "Home",
activeColorPrimary: Colors.blueGrey,
),
PersistentBottomNavBarItem(
icon: Icon(Icons.favorite),
title: ("History"),
activeColorPrimary: CupertinoColors.activeGreen,
),
];
}
#override
Widget build(BuildContext context) {
return Center(
child: PersistentTabView(
controller: _controller,
screens: _NavScreens(),
items: _navBarsItems(),
confineInSafeArea: true,
backgroundColor: Colors.white,
handleAndroidBackButtonPress: true,
resizeToAvoidBottomInset: true,
hideNavigationBarWhenKeyboardShows: true,
decoration: NavBarDecoration(
borderRadius: BorderRadius.circular(10.0),
),
popAllScreensOnTapOfSelectedTab: true,
navBarStyle: NavBarStyle.style9,
),
);
}
This is the original bottom bar that I want to keep fixed in all screens
class _BottomBarState extends State<BottomBar> {
int _selectedIndex = 0;
static final List<Widget> _widgetOptions = <Widget>[
HomeScreen(),
const Text("History"),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
//print('Tapped index is: ${_selectedIndex}');
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: _widgetOptions[_selectedIndex],
),
bottomNavigationBar: Column(
mainAxisSize: MainAxisSize.min,
children: [
BottomNavigationBar(
currentIndex: _selectedIndex,
onTap: _onItemTapped,
...............................
items: const [
BottomNavigationBarItem(
icon: Icon(FluentSystemIcons.ic_fluent_home_regular),
label: "Home"),
BottomNavigationBarItem(
icon: Icon(FluentSystemIcons.ic_fluent_history_regular),
label: "History"),
],),],),);}}
How to apply presistent bottom bar to my project without changing the design? Why am I reciving this error and how to fix it.
persistent_bottom_nav_bar.dart
import 'package:flutter/material.dart';
import 'bottom_nav_bar.dart';
class MyPersistentBottomNavBar extends StatelessWidget {
const MyPersistentBottomNavBar({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Persistent Bottom Nav Bar',
debugShowCheckedModeBanner: false,
theme: ThemeData(primarySwatch: Colors.deepPurple),
home: const BottomNavBar(),
);
}
}
bottom_nav_bar.dart :
import 'package:flutter/material.dart';
import 'package:persistent_bottom_nav_bar_v2/persistent-tab-view.dart';
import 'pages/home_page.dart';
import 'pages/explore_page.dart';
import 'pages/add_page.dart';
import 'pages/inbox_page.dart';
import 'pages/shopping_page.dart';
class BottomNavBar extends StatelessWidget {
const BottomNavBar({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
PersistentTabController controller;
controller = PersistentTabController(initialIndex: 0);
List<Widget> _buildScreens() {
return [
const HomePage(),
const ExplorePage(),
const AddPage(),
const InboxPage(),
const ShoppingPage(),
];
}
List<PersistentBottomNavBarItem> _navBarsItems() {
return [
PersistentBottomNavBarItem(
icon: const Icon(Icons.home),
title: ("Home"),
activeColorPrimary: Colors.deepPurple,
inactiveColorPrimary: Colors.grey,
),
PersistentBottomNavBarItem(
icon: const Icon(Icons.explore),
title: ("Explore"),
activeColorPrimary: Colors.deepPurple,
inactiveColorPrimary: Colors.grey,
),
PersistentBottomNavBarItem(
icon: const Icon(Icons.add, color: Colors.white),
activeColorPrimary: Colors.deepPurple,
inactiveColorPrimary: Colors.grey,
),
PersistentBottomNavBarItem(
icon: const Icon(Icons.email),
title: ("Inbox"),
activeColorPrimary: Colors.deepPurple,
inactiveColorPrimary: Colors.grey,
),
PersistentBottomNavBarItem(
icon: const Icon(Icons.shopping_bag),
title: ("Shop"),
activeColorPrimary: Colors.deepPurple,
inactiveColorPrimary: Colors.grey,
),
];
}
return PersistentTabView(
context,
controller: controller,
screens: _buildScreens(),
items: _navBarsItems(),
confineInSafeArea: true,
backgroundColor: Colors.white, // Default is Colors.white.
handleAndroidBackButtonPress: true, // Default is true.
resizeToAvoidBottomInset:
true, // This needs to be true if you want to move up the screen when keyboard appears. Default is true.
stateManagement: true, // Default is true.
hideNavigationBarWhenKeyboardShows:
true, // Recommended to set 'resizeToAvoidBottomInset' as true while using this argument. Default is true.
decoration: NavBarDecoration(
borderRadius: BorderRadius.circular(10.0),
colorBehindNavBar: Colors.white,
),
popAllScreensOnTapOfSelectedTab: true,
popActionScreens: PopActionScreensType.all,
itemAnimationProperties: const ItemAnimationProperties(
// Navigation Bar's items animation properties.
duration: Duration(milliseconds: 200),
curve: Curves.ease,
),
screenTransitionAnimation: const ScreenTransitionAnimation(
// Screen transition animation on change of selected tab.
animateTabTransition: true,
curve: Curves.ease,
duration: Duration(milliseconds: 200),
),
navBarStyle:
NavBarStyle.style15, // Choose the nav bar style with this property.
);
}
}
Please see code for other pages from the GitHub URL below:
https://github.com/md-siam/package_of_the_day/tree/master/lib/51_persistent_bottom_nav_bar/pages
I have tried this code.It runs fine, can you please try?
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:minawill/ui/home/home.dart';
class BottomBar extends StatefulWidget {
const BottomBar({Key? key}) : super(key: key);
#override
State<BottomBar> createState() => _BottomBarState();
}
class _BottomBarState extends State<BottomBar> {
int _selectedIndex = 0;
static final List<Widget> _widgetOptions = <Widget>[
HomeScreen(),
const Text("History"),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
//print('Tapped index is: ${_selectedIndex}');
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: _widgetOptions[_selectedIndex],
),
bottomNavigationBar: Column(
mainAxisSize: MainAxisSize.min,
children: [
BottomNavigationBar(
currentIndex: _selectedIndex,
onTap: _onItemTapped,
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.add),
label: "Home"),
BottomNavigationBarItem(
icon: Icon(Icons.phone),
label: "History"),
],),],),);}
}
i have added a photo of my output.Please check
import 'dart:js';
import 'package:google_fonts/google_fonts.dart';
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyStatefulWidget(),
);
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int _selectedIndex = 0;
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
// ignore: prefer_final_fields
static List<Widget> _widgetOptions = <Widget>[
Container(
child: ElevatedButton(
child: const Text('Open route'),
onPressed: () {
Navigator.push(
**This is where the error occurs: I am unsure of how to access or use context within list widgets**
context, // ********THIS IS WHERE THE ERROR IS******
MaterialPageRoute(builder: (context) => const SecondRoute()),
);
},
),
),
Text(
'Index 1: Business',
style: optionStyle,
),
Text(
'Index 2: School',
style: optionStyle,
),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('OBTAIN'),
),
body: Center(
child: _widgetOptions.elementAt(_selectedIndex),
),
drawer: Drawer(
// Add a ListView to the drawer. This ensures the user can scroll
// through the options in the drawer if there isn't enough vertical
// space to fit everything.
child: ListView(
// Important: Remove any padding from the ListView.
padding: EdgeInsets.zero,
children: [
const DrawerHeader(
decoration: BoxDecoration(
color: Colors.blue,
),
child: Text('Drawer Header'),
),
ListTile(
title: const Text('Item 1'),
onTap: () {
// Update the state of the app
// ...
// Then close the drawer
Navigator.pop(context);
},
),
ListTile(
title: const Text('Item 2'),
onTap: () {
// Update the state of the app
// ...
// Then close the drawer
Navigator.pop(context);
},
),
],
),
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
label: 'Business',
),
BottomNavigationBarItem(
icon: Icon(Icons.school),
label: 'School',
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.amber[800],
onTap: _onItemTapped,
),
);
}
}
class SecondRoute extends StatelessWidget {
const SecondRoute({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Second Route'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('Go back!'),
),
),
);
}
}
How would I navigate to a new route inside a list widget? (Line 41: context,) is where the issue occurs.
The issue is you are trying to get context direct under state class. There is trick can be done using late keyword or do inside initState. (You can't use static)
Also avoid using context like this when ever possible.
"It breaks the context chain, which means you're violating the build system's contract." - And this variable wont be responde to update untill you reintalize this variable inisde setState.
late List<Widget> _widgetOptions = <Widget>[
Container(
child: ElevatedButton(
child: const Text('Open route'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const SecondRoute()),
);
},
),
),
Text(
'Index 1: Business',
style: optionStyle,
),
Text(
'Index 2: School',
style: optionStyle,
),
];
I have used NestedScrollView and SliverAppBar to hide app bar when scrolling. In the body of NestedScrollView, I have CustomScrollView with a PageStorageKey but when I have switched back to events tab, scroll position is lost. I cannot understand it. Could you please help me?
home_screen.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:liveitup/app/screens/HomeScreen/drawer_icon.dart';
import 'package:liveitup/app/screens/HomeScreen/drawer_page.dart';
import 'package:liveitup/app/screens/HomeScreen/tabs/bottom_navigation.dart';
import 'package:liveitup/app/screens/HomeScreen/tabs/tab_item.dart';
import 'package:liveitup/app/screens/HomeScreen/tabs/tab_navigators/event_tab_navigator.dart';
import 'package:liveitup/app/screens/HomeScreen/tabs/tab_navigators/message_tab_navigator.dart';
import 'package:liveitup/app/screens/HomeScreen/tabs/tab_navigators/notification_tab_navigator.dart';
import 'package:liveitup/blocs/UserBloc/bloc.dart';
import '../../../constants.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
var _currentTab = TabItem.events;
void _selectTab(TabItem tabItem) {
setState(() => _currentTab = tabItem);
}
#override
Widget build(BuildContext context) {
var scaffoldKey = GlobalKey<ScaffoldState>();
UserBloc _userBloc = BlocProvider.of<UserBloc>(context);
return Scaffold(
backgroundColor: Colors.blue,
drawer: DrawerPage(),
key: scaffoldKey,
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
expandedHeight: 0,
pinned: false,
floating: true,
forceElevated: innerBoxIsScrolled,
backgroundColor: Colors.green,
leading: GestureDetector(
onTap: () => scaffoldKey.currentState?.openDrawer(),
child: const DrawerIcon()),
title: const Center(
child: Text(app_name),
),
actions: [
//Icon(Icons.search),
(_currentTab == TabItem.events)
? Icon(Icons.filter)
: Container(),
],
),
];
},
body: Builder(builder: (BuildContext context) {
if (_currentTab == TabItem.events) {
return CustomScrollView(
key: const PageStorageKey<TabItem>(TabItem.events),
slivers: [
SliverList(
delegate: SliverChildListDelegate([
for (var index = 1; index < 1000; index++)
Text(
index.toString(),
textAlign: TextAlign.center,
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: 40.0,
letterSpacing: 2.0,
wordSpacing: 100.0,
),
),
])),
],
);
} else if (_currentTab == TabItem.messages) {
return const Center(
child: Text('message list'),
);
} else if (_currentTab == TabItem.notifications) {
return const Center(
child: Text('notitifcatiion list'),
);
}
return Text('notitifcatiion list');
}),
),
bottomNavigationBar: BottomNavigation(
currentTab: _currentTab,
onSelectTab: _selectTab,
),
);
}
}
tab_item.dart
import 'package:flutter/material.dart';
enum TabItem { events, messages, notifications }
const Map<TabItem, String> tabName = {
TabItem.events: 'events',
TabItem.messages: 'messages',
TabItem.notifications: 'notifications',
};
botom_navigation.dart
import 'package:flutter/material.dart';
import 'package:liveitup/app/screens/HomeScreen/tabs/tab_item.dart';
class BottomNavigation extends StatelessWidget {
BottomNavigation({required this.currentTab, required this.onSelectTab});
final TabItem currentTab;
final ValueChanged<TabItem> onSelectTab;
#override
Widget build(BuildContext context) {
return BottomNavigationBar(
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
icon: Icon(
Icons.home,
color: currentTab == TabItem.events ? Colors.black : Colors.grey,
),
label: tabName[TabItem.events],
),
BottomNavigationBarItem(
icon: Icon(
Icons.message,
color: currentTab == TabItem.messages ? Colors.black : Colors.grey,
),
label: tabName[TabItem.messages],
),
BottomNavigationBarItem(
icon: Icon(
Icons.notifications,
color: currentTab == TabItem.notifications
? Colors.black
: Colors.grey,
),
label: tabName[TabItem.notifications],
),
],
onTap: (index) => onSelectTab(
TabItem.values[index],
),
currentIndex: currentTab.index,
//selectedItemColor: Colors.black,
);
}
}
This is the code without error messages:
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
#override
State<MyStatefulWidget> createState() => BottomNavigation();
}
/// This is the private State class that goes with MyStatefulWidget.
class BottomNavigation extends State<MyStatefulWidget> {
int _selectedIndex = 0;
List<Widget> _widgetOptions= <Widget>[
Text('Home'),
Text('Message')
];
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
void _onItemTapped(int index) {
setState(() {
_selectedIndex=index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
IconButton(icon: Icon(Icons.search), onPressed: () {}),
],
),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image:
AssetImage("assets/OptimizeYourFood/OptimizeYourFood2.png"),
fit: BoxFit.cover,
),
color: Colors.transparent)
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.local_dining),
label: 'Reduce',
),
BottomNavigationBarItem(
icon: Icon(FontAwesomeIcons.recycle),
label: 'Reuse and recycle',
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.amber[800],
onTap: _onItemTapped,
),
);
}
}
[Nothing comes out of bottom navigation bar items][1]
..................................................................................................................................................................................................This is the end. This is the end. This is the end. This is the end. This is the end.
New Code
New Picture
You are changing the index but not the UI. use _widgetOptions on body. You can directly use body:_widgetOptions[_selectedIndex ] .
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
#override
State<MyStatefulWidget> createState() => BottomNavigation();
}
/// This is the private State class that goes with MyStatefulWidget.
class BottomNavigation extends State<MyStatefulWidget> {
int _selectedIndex = 0;
List<Widget> _widgetOptions = <Widget>[Text('Home'), Text('Message')];
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
void _onItemTapped(int index) {
print("tapped $index");
setState(() {
_selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
IconButton(icon: Icon(Icons.search), onPressed: () {}),
],
),
body: Column(
children: [
_widgetOptions[_selectedIndex]
// Container(
// decoration: BoxDecoration(
// image: DecorationImage(
// image:
// AssetImage("assets/OptimizeYourFood/OptimizeYourFood2.png"),
// fit: BoxFit.cover,
// ),
// color: Colors.transparent)),
],
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.local_dining),
label: 'Reduce',
),
BottomNavigationBarItem(
icon: Icon(Icons.ac_unit),
// Icon(FontAwesomeIcons.recycle),
label: 'Reuse and recycle',
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.amber[800],
onTap: _onItemTapped,
),
);
}
}
It will use the items array index.
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem( // <- index 0
icon: Icon(Icons.local_dining),
label: 'Reduce',
),
BottomNavigationBarItem( // <- index 1
icon: Icon(FontAwesomeIcons.recycle),
label: 'Reuse and recycle',
),
...
],
I am working on a flutter application where I need to redirect to the first screen on BottomNavigationBar when the user presses back from any other screen of the remaining BottomNavigationBar screens. For now, I have added redirecting event on a simple button, will replace this on _onWillPop event.
Please find the code below:
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
final PageStorageBucket bucket = PageStorageBucket();
Widget currentScreen = HomeFragment();
int currentTab = 0;
static int selectedIndexN = 0;
static const TextStyle optionStyle = TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
List<Widget> _widgetOptions1 = <Widget>[
HomeFragment(),
LoginFargment(),
SignUpFargment(),
ProfileFargment(),
];
void changeTabMethod(int index) {
print('changeTabMethod is called');
setState(() {
selectedIndexN = index;
});
print('changeTabMethod is called : selectedIndexN : $selectedIndexN');
}
#override
Widget build(BuildContext context) {
return Scaffold(
// return GetBuilder<DashboardController>(
body: Center(
child: _widgetOptions1.elementAt(selectedIndexN),
),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
currentIndex: selectedIndexN,
onTap: changeTabMethod,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
label: 'Login',
),
BottomNavigationBarItem(
icon: Icon(Icons.school),
label: 'SignUp',
),
BottomNavigationBarItem(
icon: Icon(Icons.school),
label: 'Profile',
),
],
),
);
}
}
Profile screen code:
class ProfileFargment extends StatefulWidget {
#override
_ProfileFragmentState createState() => _ProfileFragmentState();
}
class _ProfileFragmentState extends State<ProfileFargment> {
#override
Widget build(BuildContext context) {
return Scaffold(
body:SafeArea(
child: Container(
padding: EdgeInsets.all(20.0),
height: double.infinity,
width: double.infinity,
color: Colors.teal,
child: GestureDetector(
onTap: () {
//Calling method changeTabMethod(0)
HomeScreen().createState().changeTabMethod(0);
},
child: Container(
margin: EdgeInsets.only(top: 20.0),
height: 40.0,
width: 150.0,
color: Colors.white,
child: Center(child: Text('Profile'),),
),
),
),
),
);
}
}
On the other hand, when I call changeTabMethod from a ProfileFragment screen, it will enter into changeTabMethod but couldn't execute the setState method. So my tab is not changing.
You can consider this console report:
changeTabMethod is called is only printed the second print after setState was not executed.
Can you please let me know what or where I am doing anything wrong?
Thanks in advance :-)
Try below code. By passing function as parameter you can trigger function on home page from any other page.
Home screen code:
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
final PageStorageBucket bucket = PageStorageBucket();
// Widget currentScreen = HomeFragment();
int currentTab = 0;
static int selectedIndexN = 0;
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
Widget _widgetOptions1(int index) {
switch (index) {
case 0:
return ProfileFargment(onButtonPressed: changeTabMethod);
case 1:
return Container(child: Text("Page - 2 "));
case 2:
return Container(child: Text("Page - 3 "));
default:
return Container();
}
}
void changeTabMethod(int index) {
print('changeTabMethod is called');
setState(() {
selectedIndexN = index;
});
print('changeTabMethod is called : selectedIndexN : $selectedIndexN');
}
#override
Widget build(BuildContext context) {
return Scaffold(
// return GetBuilder<DashboardController>(
body: Center(
child: _widgetOptions1(selectedIndexN),
),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
currentIndex: selectedIndexN,
onTap: changeTabMethod,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
label: 'Login',
),
BottomNavigationBarItem(
icon: Icon(Icons.school),
label: 'SignUp',
),
BottomNavigationBarItem(
icon: Icon(Icons.school),
label: 'Profile',
),
],
),
);
}
}
Profile screen code:
class ProfileFargment extends StatefulWidget {
final void Function(int) onButtonPressed;
const ProfileFargment({Key key, this.onButtonPressed});
#override
_ProfileFragmentState createState() => _ProfileFragmentState();
}
class _ProfileFragmentState extends State<ProfileFargment> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
padding: EdgeInsets.all(20.0),
height: double.infinity,
width: double.infinity,
color: Colors.teal,
child: GestureDetector(
onTap: () {
//Calling method changeTabMethod(0)
// HomeScreen().createState().changeTabMethod(0);
widget.onButtonPressed(0);
},
child: Container(
margin: EdgeInsets.only(top: 20.0),
height: 40.0,
width: 150.0,
color: Colors.white,
child: Center(
child: Text('Profile'),
),
),
),
),
),
);
}
}
This is actually quite simple, you just need to pass the function off to the child widget.
So your ProfileFragment will take a variable called changeTab of type Function(int):
Function(int) changeTab;
ProfileFragment(this.changeType); // Constructor
You pass that off when you create the widget inside the _HomeScreenState:
List<Widget> _widgetOptions1 = <Widget>[
…
ProfileFargment(changeTabMethod),
];
Then you can call the function directly in the _ProfileFragmentState:
onTap: () => widget.changeTab(0);