I have this:
class PageService {
static int CurrentPage = 0;
}
And I have this:
import 'package:flutter/material.dart';
import '../services/page_service.dart';
class NavigationMenu extends StatefulWidget {
const NavigationMenu({super.key});
@override
State<NavigationMenu> createState() => _NavigationMenuState();
}
class _NavigationMenuState extends State<NavigationMenu> {
@override
Widget build(BuildContext context) {
return NavigationBar(
destinations: const [
NavigationDestination(
icon: Icon(
Icons.home,
color: Colors.white,
),
label: "Home"),
NavigationDestination(icon: Icon(Icons.forum), label: "Forums"),
],
backgroundColor: const Color.fromARGB(255, 154, 15, 5),
onDestinationSelected: (int index) {
setState(() {
PageService.CurrentPage = index;
int test = PageService.CurrentPage;
print("SETTING $test");
});
},
selectedIndex: PageService.CurrentPage,
);
}
}
Then in my main, I have this:
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'BeastBurst',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.red,
),
home: const BeastBurst(title: 'BeastBurst'),
);
}
}
class BeastBurst extends StatefulWidget {
const BeastBurst({super.key, required this.title});
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
@override
State<BeastBurst> createState() => _BeastBurstState();
}
class _BeastBurstState extends State<BeastBurst> {
int _counter = 0;
bool _loggedIn = false;
List<Widget> pages = const [HomePage(), Forums()];
@override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
body: pages[PageService.CurrentPage],
// This trailing comma makes auto-formatting nicer for build methods.
);
}
}
When I navigate over the navigation menu I see the output of print like:
SETTING 1
SETTING 0
SETTING 1
SETTING 1
However, page switching does not happen unless I press CRTL S
on the VSCode editor.
Looks like it reads the value of PageService.CurrentPage
only on the editor save.
This issue happened once I made PageService.CurrentPage
static. Any idea why is that and how can I fix it?
CodePudding user response:
Actually here, in your NavigationMenu
class you're updating the state of the class and not it's parent class, in which you're using the NavigationMenu
, which is why the state of the parent class isn't' changed and the build method isn't recalled and the updated value of PageService.CurrentIndex
isn't referenced again.
In the class where you have used the NavigationMenu
:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
bottomNavigationBar: NavigationMenu(
onDestinationSelected: (index) {
setState(() {
PageService.CurrentPage = index;
int test = PageService.CurrentPage;
print("SETTING $test");
});
},
),
body: pages[PageService.CurrentPage],
);
}
Updated NavigationMenu
class:
class NavigationMenu extends StatefulWidget {
final Function(int) onDestinationSelected;
const NavigationMenu({super.key, required this.onDestinationSelected});
@override
State<NavigationMenu> createState() => _NavigationMenuState();
}
class _NavigationMenuState extends State<NavigationMenu> {
@override
Widget build(BuildContext context) {
return NavigationBar(
destinations: const [
NavigationDestination(
icon: Icon(
Icons.home,
color: Colors.white,
),
label: "Home"),
NavigationDestination(icon: Icon(Icons.forum), label: "Forums"),
],
backgroundColor: const Color.fromARGB(255, 154, 15, 5),
onDestinationSelected: widget.onDestinationSelected,
selectedIndex: PageService.CurrentPage,
);
}
}
Alternate solution:
In your NavigationMenu
class, change:
onDestinationSelected: (int index) {
setState(() {
PageService.CurrentPage = index;
int test = PageService.CurrentPage;
print("SETTING $test");
});
}
to:
onDestinationSelected: (int index) {
final parentState = context.findAncestorStateOfType<_MyHomePageState>();
parentState?.setState(() {
PageService.CurrentPage = index;
int test = PageService.CurrentPage;
print("SETTING $test");
});
}
Note: Change _MyHomePageState
to your class state in which you're using the NavigationMenu
.
CodePudding user response:
You need to make main widget as StatefulWidget
while will update the UI here too. I am using a callback method instead of global variable.
class NavigationMenu extends StatefulWidget {
const NavigationMenu({super.key, required this.selected});
final Function(int) selected;
//....
onDestinationSelected: (int index) {
widget.selected(index);//update parent callback
setState(() {});
},
selectedIndex: PageService.CurrentPage,
);
}
And use case
class _ExampleScreenState extends State<ExampleScreen> {
int activeIndex = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
bottomNavigationBar: NavigationMenu(
selected: (p0) {
//PageService.CurrentPage=0;
activeIndex = p0;
setState(() {});
},
),
body: [Text("a"), Text("B")][activeIndex] //PageService.CurrentPage