in this link in SF, #martinseal1987 show us how can we use separated widgets link with android fragments.
I implemented this solution on my project and after running project i dont have any problem to show first widgets as an Fragment, but when i press to back button my screen goes to black and couldn't back to previous widgets as an fragment
i think that is should be this:
Problem is on navigateBack and customPop methods and i can attach fragment by pressing on button
import 'package:flutter/material.dart';
void main()
{
runApp(MaterialApp(
title: 'AndroidMonks',
home: Scaffold(
appBar: AppBar(
title: Text('Androidmonks'),
backgroundColor: Colors.orangeAccent,
),
body: Home(),
),
));
}
class Home extends StatefulWidget {
Home({
Key key,
}) : super(key: key);
#override
State<Home> createState()=>_Home();
}
class _Home extends State<Home> {
String title = "Title";
int _currentIndex = 0;
final List<int> _backstack = [0];
#override
Widget build(BuildContext context) {
navigateTo(_currentIndex);
//each fragment is just a widget which we pass the navigate function
List<Widget> _fragments =[Fragment1(),Fragment2(),Fragment3()];
//will pop scope catches the back button presses
return WillPopScope(
onWillPop: () {
customPop(context);
},
child: Scaffold(
body: Column(
children: <Widget>[
RaisedButton(
child:Text('PRESS'),
onPressed: (){
_currentIndex++;
navigateTo(_currentIndex);
},
),
Expanded(
child: _fragments[_currentIndex],
),
],
),
),
);
}
void navigateTo(int index) {
_backstack.add(index);
setState(() {
_currentIndex = index;
});
_setTitle('$index');
}
void navigateBack(int index) {
setState(() {
_currentIndex = index;
});
_setTitle('$index');
}
customPop(BuildContext context) {
if (_backstack.length - 1 > 0) {
navigateBack(_backstack[_backstack.length - 1]);
} else {
_backstack.removeAt(_backstack.length - 1);
Navigator.pop(context);
}
}
//this method could be called by the navigate and navigate back methods
_setTitle(String appBarTitle) {
setState(() {
title = appBarTitle;
});
}
}
class Fragment2 extends StatefulWidget {
#override
State<Fragment2> createState() => _Fragment2();
}
class _Fragment2 extends State<Fragment2> {
#override
Widget build(BuildContext context) {
return Center(
child: RaisedButton(
child: Text("_Fragment2"),
onPressed: (){
}),
);
}
}
class Fragment1 extends StatefulWidget {
#override
State<Fragment1> createState() => _Fragment1();
}
class _Fragment1 extends State<Fragment1> {
#override
Widget build(BuildContext context) {
return Center(
child: Text("_Fragment1"),
);
}
}
class Fragment3 extends StatefulWidget {
#override
State<Fragment3> createState() => _Fragment3();
}
class _Fragment3 extends State<Fragment3> {
#override
Widget build(BuildContext context) {
return Center(
child: Text("_Fragment3"),
);
}
}
I fixed some logic in your code please carefully check the changes, if you have any question don't hesitate, here is the working code
import 'package:flutter/material.dart';
void main()
{
runApp(MaterialApp(
title: 'AndroidMonks',
home: Scaffold(
appBar: AppBar(
title: Text('Androidmonks'),
backgroundColor: Colors.orangeAccent,
),
body: Home(),
),
));
}
class Home extends StatefulWidget {
Home({
Key key,
}) : super(key: key);
#override
State<Home> createState()=>_Home();
}
class _Home extends State<Home> {
String title = "Title";
List<Widget> _fragments =[Fragment1(),Fragment2(),Fragment3()];
int _currentIndex = 0;
final List<int> _backstack = [0];
#override
Widget build(BuildContext context) {
//navigateTo(_currentIndex);
//each fragment is just a widget which we pass the navigate function
//will pop scope catches the back button presses
return WillPopScope(
onWillPop: () {
return customPop(context);
},
child: Scaffold(
body: Column(
children: <Widget>[
RaisedButton(
child:Text('PRESS'),
onPressed: (){
_currentIndex++;
navigateTo(_currentIndex);
},
),
Expanded(
child: _fragments[_currentIndex],
),
],
),
),
);
}
void navigateTo(int index) {
_backstack.add(index);
setState(() {
_currentIndex = index;
});
_setTitle('$index');
}
void navigateBack(int index) {
setState(() {
_currentIndex = index;
});
_setTitle('$index');
}
Future<bool> customPop(BuildContext context) {
print("CustomPop is called");
print("_backstack = $_backstack");
if (_backstack.length > 1) {
_backstack.removeAt(_backstack.length - 1);
navigateBack(_backstack[_backstack.length - 1]);
return Future.value(false);
} else {
return Future.value(true);
}
}
//this method could be called by the navigate and navigate back methods
_setTitle(String appBarTitle) {
setState(() {
title = appBarTitle;
});
}
}
class Fragment2 extends StatefulWidget {
#override
State<Fragment2> createState() => _Fragment2();
}
class _Fragment2 extends State<Fragment2> {
#override
Widget build(BuildContext context) {
return Center(
child: RaisedButton(
child: Text("_Fragment2"),
onPressed: (){
}),
);
}
}
class Fragment1 extends StatefulWidget {
#override
State<Fragment1> createState() => _Fragment1();
}
class _Fragment1 extends State<Fragment1> {
#override
Widget build(BuildContext context) {
return Center(
child: Text("_Fragment1"),
);
}
}
class Fragment3 extends StatefulWidget {
#override
State<Fragment3> createState() => _Fragment3();
}
class _Fragment3 extends State<Fragment3> {
#override
Widget build(BuildContext context) {
return Center(
child: Text("_Fragment3"),
);
}
}
You can achieve this type of navigation using LocalHistoryRoute.of(context).addLocalHistoryEntry and Navigator.pop().
Related
Hi I want to change the icon when pressed button.
So I used provider method.
Icon Widget
class LockeryIcon extends StatelessWidget {
final String text;
LockeryIcon({required this.text});
#override
Widget build(BuildContext context) {
return IconButton(
onPressed: () {
Navigator.of(context).pushNamed(SecondView);
print(text);
},
icon: Icon(context.watch<ProviderA>().isIcon),
);
}
}
Listview builder
class Abc extends StatelessWidget {
final List _lock1 = [
'abc 1',
'abc 2',
'abc 3',
];
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
shrinkWrap: true,
itemCount: _lock1.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(30.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
LockeryIcon(text: _lock1[index]),
],
),
);
},
),
);
}
}
Main Screen
class MainView extends StatelessWidget {
const MainView({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Abc(),
);
}
Second View
class SecondView extends StatelessWidget {
const SecondView({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: TextButton(
onPressed: () {
context.read<LockeryProvider>().change();
Navigator.of(context).pop();
},
child: Text('Done'),
),
);
}
}
Provider
class ProviderA with ChangeNotifier {
IconData _isIcon = Icons.access_time_filled_sharp;
IconData get isIcon => _isIcon;
void change() {
_isIcon = Icons.add_location;
notifyListeners();
}
}
My problem is when I clicked this all the icons are being changed.
Is there a way to pass index to only change the relevant button???
Or my method is not correct?
Please help me on this
Thank you
You have to store an integer in your provider:
class ProviderA with ChangeNotifier {
int _index = -1;
int get isIndex => _index;
void change(int index) {
_index = index;
notifyListeners();
}
}
and check the index in your Icon class like this:
class LockeryIcon extends StatelessWidget {
final String text;
final int listViewIndex;
LockeryIcon({required this.text,required this.listViewIndex});
#override
Widget build(BuildContext context) {
return IconButton(
onPressed: () {
Navigator.of(context).pushNamed(SecondView);
print(text);
},
icon: Icon(context.watch<ProviderA>().isIndex == listViewIndex ? firstIcon:secondIcon),
);
}
}
finally, use the change function in which you press your button.
Learning Flutter and I am building a counter that I would like to use for a cart. I have a problem retrieving the integer value of the counter stateful widget I created and i'd like a Text to update itself with the value of the Counter.
Here is the Code for the Counter
import 'package:flutter/material.dart';
class TheCounter extends StatefulWidget {
int counter = 0;
int get counterValue => counter;
#override
_TheCounterState createState() => _TheCounterState();
}
class _TheCounterState extends State<TheCounter> {
void increaseCounter() {
setState(() {
if (widget.counter >= 0) {
widget.counter++;
}
});
}
void decreaseCounter() {
setState(() {
if (widget.counter > 0) {
widget.counter--;
}
});
}
#override
Widget build(BuildContext context) {
return Row(
children: [
IconButton(icon: Icon(Icons.add), onPressed: increaseCounter),
Text('${widget.counter}'),
IconButton(icon: Icon(Icons.remove), onPressed: decreaseCounter)
],
);
}
}
And here is the main.dart file
import 'package:counter/counter.dart';
import 'package:flutter/material.dart';
void main() {
runApp(Count());
}
class Count extends StatelessWidget {
#override
Widget build(BuildContext context) {
int counting = TheCounter().counterValue;
return MaterialApp(
title: 'Counter',
home: Scaffold(
appBar: AppBar(
title: Text('Counter Test'),
),
body: Column(
children: [
TheCounter(),
Text('$counting'),
TheCounter(),
TheCounter(),
],
),
),
);
}
}
I'd like the Text to update itself with the value of the counter whenever the add or remove button is clicked. What do I do to achieve that?
Firstly, we need to make a decision where the update will happen. In this case the Count widget text need to update.
Therefore, need to convert this as StatefulWidget.
Next thing is how we can retrieve counter from TheCounter widget. You can use callback method, or state management package like provider, riverpod, bloc etc. You can check the doc
Here I am using a function that will get update value on Count whenever the count value change on TheCounter widget.
void main() {
runApp(MaterialApp(title: 'Counter', home: Count()));
}
class Count extends StatefulWidget {
const Count({Key? key}) : super(key: key);
#override
State<Count> createState() => _CountState();
}
class _CountState extends State<Count> {
int initNumberOfCounter = 4;
late List<int> countersValue = List.generate(initNumberOfCounter, (index) => 0);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Counter Test'),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
countersValue.add(0);
});
},
),
body: Column(
children: [
Expanded(
child: ListView.builder(
itemCount: countersValue.length,
itemBuilder: (context, index) {
return Row(
// mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
TheCounter(
initCountValue: countersValue[index],
countValueCallback: (v) {
setState(() {
countersValue[index] = v;
});
},
),
const SizedBox(
width: 40,
),
Text("${countersValue[index]}"),
],
);
},
),
)
],
),
);
}
}
class TheCounter extends StatefulWidget {
final Function(int) countValueCallback;
final int initCountValue;
const TheCounter({
Key? key,
required this.countValueCallback,
this.initCountValue = 0,
}) : super(key: key);
#override
_TheCounterState createState() => _TheCounterState();
}
class _TheCounterState extends State<TheCounter> {
///this use within the current state
late int counter;
#override
void initState() {
super.initState();
///set counter value for the 1st time
counter = widget.initCountValue;
}
void increaseCounter() {
setState(() {
if (counter >= 0) {
counter++;
}
});
/// back to parent widget
widget.countValueCallback(counter);
}
void decreaseCounter() {
setState(() {
if (counter > 0) {
counter--;
}
});
widget.countValueCallback(counter);
}
#override
Widget build(BuildContext context) {
return Row(
children: [
IconButton(icon: Icon(Icons.add), onPressed: increaseCounter),
Text('${counter}'),
IconButton(icon: Icon(Icons.remove), onPressed: decreaseCounter)
],
);
}
}
Version:
Flutter-Version: 1.12.14 channel dev
Dart-Version: 2.7.0
Question:
I wan write a Todo App. when i click floatbutton add a new Todo, but in some cases its not work well.
The problem in Scaffold.body, detials in code.
it work well when i use TodoPage(todoList: _todoList).
_pageList.elementAt(_activeIndex) is not work when i submit textfield .
I found the print('Build Home')print after submit but print('Build TodoPage') not print.
why???
My Code:
import 'package:flutter/material.dart';
void main() => runApp(App());
class App extends StatelessWidget{
#override
Widget build(BuildContext context){
return MaterialApp(
title: 'TodoList',
home: Home(),
);
}
}
class Home extends StatefulWidget{
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home>{
List<String> _todoList = ['a', 'b', 'c'];
TextEditingController _controller;
List<Widget> _pageList;
int _activeIndex;
Widget _curPage;
#override
void initState(){
super.initState();
_activeIndex = 0;
_pageList = [TodoPage(todoList: _todoList,), OtherPage()];
_curPage = _pageList[_activeIndex];
_controller = TextEditingController();
}
#override
Widget build(BuildContext context){
print('build Home');
return Scaffold(
appBar: AppBar(title: Text('Todo'),),
body: _pageList.elementAt(_activeIndex), // this is not work
// body: TodoPage(todoList: _todoList,), // this is work well
floatingActionButton: FloatingActionButton(
onPressed: _openDlg,
child: Icon(Icons.add),
),
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(icon: Icon(Icons.list), title: Text('Todo')),
BottomNavigationBarItem(icon: Icon(Icons.favorite), title: Text('Other')),
],
currentIndex: _activeIndex,
selectedItemColor: Colors.blue,
onTap: _onMenuTap,
),
);
}
_onMenuTap(int index){
setState(() {
_activeIndex = index;
});
}
_openDlg(){
showDialog(
context: context,
builder: (BuildContext context){
return SimpleDialog(
children: <Widget>[
TextField(
controller: _controller,
),
SimpleDialogOption(
child: FloatingActionButton(child: Text('submit'), onPressed: _addTodo,),
)
],
);
}
);
}
_addTodo(){
print(_controller.text);
setState(() {
_todoList.add(_controller.text);
});
}
}
class TodoPage extends StatefulWidget{
TodoPage({Key key, this.todoList}): super(key: key);
List<String> todoList;
_TodoPageState createState() => _TodoPageState();
}
class _TodoPageState extends State<TodoPage>{
#override
void initState(){
super.initState();
}
#override
Widget build(BuildContext context){
print('build TodoPage');
return Column(
children: _buildTodoList(),
);
}
List <Widget> _buildTodoList(){
return widget.todoList.map((todo){
return Text(todo, style: TextStyle(fontSize: 30),);
}).toList();
}
}
class OtherPage extends StatelessWidget{
#override
Widget build(BuildContext context){
return Center(child: Text('Other Page'));
}
}
That is logical.
You are reusing an existing instance of a Widget, and widgets are immutable.
As such, the framework notice that the instance of the widget did not change and doesn't call build to optimize performances.
Your problem being, you violated the rule of widgets being immutable, which makes this optimization break your app.
What you did:
class MyState extends State<MyStatefulWidget> {
SomeWidget myWidget = SomeWidget()..someProperty = "initial value";
void onSomething() {
setState(() {
myWidget.someProperty = "new value";
});
}
#override
Widget build(BuildContext context) {
return myWidget;
}
}
What you should instead do:
class MyState extends State<MyStatefulWidget> {
SomeWidget myWidget = SomeWidget(someProperty: "initial value");
void onSomething() {
setState(() {
myWidget = SomeWidget(someProperty: "new value");
});
}
#override
Widget build(BuildContext context) {
return myWidget;
}
}
Alternatively, just don't cache the widget instance at all.
There is count variable in the first stateful widget, I have passed it to Setting class. And, Setting class passes it toSettingStateBuilder. Then, its value is changed in incrementing() in SettingStateBuilder. I want the updated value to return back to HomePageBody for further work. How can I do that?
The first stateful widget is created as follow:
class HomePage extends StatefulWidget {
#override
HomePageBody createState() => HomePageBody();
}
class HomePageBody extends State<HomePage> {
int count=0;
#override
Widget build(BuildContext context) {
...
new Setting(count);
}
}
The second stateful widget is created as follow:
class Setting extends StatefulWidget {
int count;
Setting(this.count);
#override
SettingStateBuilder createState() => SettingStateBuilder(count);
}
class SettingStateBuilder extends State<Setting> {
int count;
SettingStateBuilder(this.count);
#override
Widget build(BuildContext context) {
return new Container(
new Text(count.toString());
....
onPressed: () => setState(() => incrementing(context))),
);
}
incrementing(context) { count += 1; }
}
You could add a Function property to the Settings widget that will be called when the counter is incremented, and pass that function when you create the widget so in HomePage you can update the counter:
class HomePage extends StatefulWidget {
#override
HomePageBody createState() => HomePageBody();
}
class HomePageBody extends State<HomePage> {
int count = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
MaterialButton(
child: Text('Settings'),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) => Settings(
count,
(newCount) {
setState(
() {
count = newCount;
},
);
},
),
),
);
},
)
],
),
body: Center(
child: Text('$count'),
),
);
}
}
class Settings extends StatefulWidget {
final int count;
final Function(int) onCounterChanged;
Settings(this.count, onCounterChanged);
#override
SettingsStateBuilder createState() => SettingsStateBuilder(count);
}
class SettingsStateBuilder extends State<Settings> {
int count;
SettingsStateBuilder(this.count);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('$count'),
MaterialButton(
child: Text('Increment'),
onPressed: () => setState(
() {
increment();
},
),
),
],
),
),
);
}
increment() {
count += 1;
widget.onCounterChanged(count);
}
}
If you are dealing with a more complex use case I suggest you to read for how to approach state management in Flutter, some resources:
https://flutter.dev/docs/development/data-and-backend/state-mgmt/intro
https://flutter.dev/docs/development/data-and-backend/state-mgmt/options
I'm doing a flutter app with Cupertino, I'm trying to figure out how to recall method initState each time that I navigate to this tab (MapPage).
This method initState() calls other mehtod "initPlatformState()" who asks for the permission location and makes a request to an API, with this result I build a marker per each object's result and show them on the map.
Here is the code of the map page.
https://gist.github.com/GreyHat147/3ea92f4e962218893b84af667452b087
This is the ui.
For CupertinoTabBar you can do as below where create instance of state class and the without creating it again called it only on tap:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
MyHome myHome = new MyHome();
MyNearMe myNearMe = new MyNearMe();
MyMap myMap = new MyMap();
MyNotifications myNotifications = new MyNotifications();
MyWallet myWallet = new MyWallet();
MyHomeState myHomeState = MyHomeState();
MyNearMeState myNearMeState = MyNearMeState();
MyMapState myMapState = MyMapState();
MyNotificationsState myNotificationsState = MyNotificationsState();
MyWalletState myWalletState = MyWalletState();
int indexPrevValue = 0;
class TabBarPage extends StatefulWidget {
TabBarPage({Key key, this.userId})
: super(key: key);
final String userId;
#override
_TabBarPage createState() => new _TabBarPage();
}
class _TabBarPage extends State<TabBarPage> {
_TabBarPage({Key key, this.userId});
final String userId;
void _onTap(int value) {
print('Value => $value');
if(value == 0){
myHomeState.initState();
}
else if(value == 1){
myNearMeState.initState();
}
else if(value == 2){
myMapState.initState();
}
else if(value == 3){
myNotificationsState.initState();
}
else if(value == 4){
myWalletState.initState();
}
indexPrevValue = value;
}
#override
void initState() {
// TODO: implement initState
super.initState();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return CupertinoTabScaffold(
tabBar: CupertinoTabBar(
onTap: _onTap,
activeColor: new Color.fromRGBO(148, 3, 123, 1.0),
items: <BottomNavigationBarItem>[
new BottomNavigationBarItem(
title: new Text('Home'),
icon: new Icon(
Icons.home,
size: 22,
),
),
new BottomNavigationBarItem(
title: new Text('Near me'),
icon: new Icon(
Icons.location_on,
size: 22,
),
),
new BottomNavigationBarItem(
icon: new Icon(
Icons.map,
size: 22,
),
title: new Text('Map')
),
new BottomNavigationBarItem(
title: new Text('Notifications'),
icon: new Icon(
Icons.notifications,
size: 22,
)
),
new BottomNavigationBarItem(
title: new Text('Wallet'),
icon: new Icon(
Icons.account_balance_wallet,
size: 22,
)
),
],
),
tabBuilder: (BuildContext context, int index) {
switch (index) {
case 0:
return CupertinoTabView(
builder: (BuildContext context) {
if(myHomeState == null){
myHomeState = myHome.createState();
}
return myHome.createState().build(context);
},
);
break;
case 1:
return CupertinoTabView(
builder: (BuildContext context) {
if(myNearMeState == null){
myNearMeState = myNearMe.createState();
}
return myNearMe.createState().build(context);
},
);
break;
case 2:
return CupertinoTabView(
builder: (BuildContext context) {
if(myMapState == null){
myMapState = myMap.createState();
}
return myMap.createState().build(context);
},
);
break;
case 3:
return CupertinoTabView(
builder: (BuildContext context) {
if(myNotificationsState == null){
myNotificationsState = myNotifications.createState();
}
return myNotifications.createState().build(context);
},
);
break;
case 4:
return CupertinoTabView(
builder: (BuildContext context) {
if(myWalletState == null){
myWalletState = myWallet.createState();
}
return myWallet.createState().build(context);
},
);
break;
}
},
);
}
}
class MyHome extends StatefulWidget {
#override
MyHomeState createState() => new MyHomeState();
}
class MyHomeState extends State<MyHome> {
#override
void initState() {
super.initState();
print('MyHomeState initState() called');
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("test stream"),
),
body: Container(
padding: EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Text('HOME 1')
],
),
));
}
}
class MyNearMe extends StatefulWidget {
#override
MyNearMeState createState() => new MyNearMeState();
}
class MyNearMeState extends State<MyNearMe> {
#override
void initState() {
super.initState();
print('MyNearMeState initState() called');
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("MyNearMe"),
),
body: Container(
padding: EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Text('My Near Me')
],
),
));
}
}
class MyMap extends StatefulWidget {
#override
MyMapState createState() => new MyMapState();
}
class MyMapState extends State<MyMap> {
#override
void initState() {
super.initState();
print('MyMapState initState() called');
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("MyMap"),
),
body: Container(
padding: EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Text('My Map')
],
),
));
}
}
class MyNotifications extends StatefulWidget {
#override
MyNotificationsState createState() => new MyNotificationsState();
}
class MyNotificationsState extends State<MyNotifications> {
#override
void initState() {
super.initState();
print('MyNotificationsState initState() called');
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("MyNotifications"),
),
body: Container(
padding: EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Text('My Notifications')
],
),
));
}
}
class MyWallet extends StatefulWidget {
#override
MyWalletState createState() => new MyWalletState();
}
class MyWalletState extends State<MyWallet> {
#override
void initState() {
super.initState();
print('MyWalletState initState() called');
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("MyWallet"),
),
body: Container(
padding: EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Text('My Wallet')
],
),
));
}
}
If you want to use another bottom navigation bar instead of cupertino then you can use as below:
I have created a sample example for you where initState() will call every time on tab change whether its same tab or different tab:
First of all import "bmnav: ^0.3.4" library in pubspec.yaml and then copy and paste below code:
import 'package:flutter/material.dart';
import 'package:bmnav/bmnav.dart' as bmnav;
Widget currentScreen = null;
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
currentScreen = MyHomeMapSample();
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState(){
super.initState();
}
int currentTab = 0;
int prevTab = 0;
final PageStorageBucket bucket = PageStorageBucket();
#override
Widget build(BuildContext ctx) {
debugPrint('currentTab: $currentTab');
return Scaffold(
body: PageStorage(child: currentScreen, bucket: bucket),
bottomNavigationBar: SizedBox(height: 58,
child: bmnav.BottomNav(
index: currentTab,
onTap: (i) {
setState(() {
currentTab = i;
currentScreen = getWidget(context, i);
if(prevTab==currentTab){
if(i==0){
MyHomeMapSample map = currentScreen as MyHomeMapSample;
map.createState().initState();
}else if(i==1){
MyHomeWorkouts map = currentScreen as MyHomeWorkouts;
map.createState().initState();
}
else if(i==2){
MyHomeAccount map = currentScreen as MyHomeAccount;
map.createState().initState();
}
}
prevTab = currentTab;
});
},
labelStyle: bmnav.LabelStyle(visible: true),
items: [
bmnav.BottomNavItem(Icons.map, label: 'Map'),
bmnav.BottomNavItem(Icons.cast, label: 'Workouts'),
bmnav.BottomNavItem(Icons.textsms, label: 'Account'),
],
),
),
resizeToAvoidBottomPadding: true,
);
}
Widget getWidget(BuildContext context, int i){
if(i==0){
return MyHomeMapSample();
}
else if(i==1){
return MyHomeWorkouts();
}else if(i==2){
return MyHomeAccount();
}
}
}
class MyHomeMapSample extends StatefulWidget {
MyHomeMapSample({Key key}) : super(key: key);
#override
MapSample createState() => MapSample();
}
class MapSample extends State<MyHomeMapSample> {
var myVariable = 0;
#override
void initState(){
super.initState();
debugPrint('current: MapSample: initState() called!');
}
#override
Widget build(BuildContext context) {
myVariable = myVariable + 1;
return Scaffold(
appBar: AppBar(
title: Text('MapSample'),
),
body: Center(
child: Text('MapSample details + $myVariable'),
),
resizeToAvoidBottomPadding: true,
);
}
}
class MyHomeWorkouts extends StatefulWidget {
MyHomeWorkouts({Key key}) : super(key: key);
#override
Workouts createState() => Workouts();
}
class Workouts extends State<MyHomeWorkouts> {
var myVariable = 0;
#override
void initState(){
super.initState();
debugPrint('current: Workouts: initState() called!');
}
#override
Widget build(BuildContext context) {
myVariable = myVariable + 1;
return Scaffold(
appBar: AppBar(
title: Text('Workouts'),
),
body: Center(
child: Text('Workouts details + $myVariable'),
),
resizeToAvoidBottomPadding: true,
);
}
}
class MyHomeAccount extends StatefulWidget {
MyHomeAccount({Key key}) : super(key: key);
#override
Account createState() => Account();
}
class Account extends State<MyHomeAccount> {
var myVariable = 0;
#override
void initState(){
super.initState();
debugPrint('current: Account: initState() called!');
}
#override
Widget build(BuildContext context) {
myVariable = myVariable + 1;
return Scaffold(
appBar: AppBar(
title: Text('Account'),
),
body: Center(
child: Text('Account details + $myVariable'),
),
resizeToAvoidBottomPadding: true,
);
}
}