Provider state management for PageController in Flutter
Using Provider you could wrap the widget that will need PageController with a ChangeNotifierProvider.value
ChangeNotifierProvider.value(
value: pageController,
Align(
alignment: Alignment.centerRight,
child: Container(
height: 205,
width: 200,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
for (int index = 0; index < _sectionsName.length; index++)
NavigationButton(title: _sectionsName[index])
]
)
)
),
),
Then all NavigationButton can access pageController as an inheretedWidget
class _NavigationButtonState extends State<NavigationButton> {
bool isHovering = false;
PageController controller;
int index;
@override
void didChangeDependencies() {
controller = Provider.of<PageController>(context); //you can read the pagecontroller here
index = controller.page.round(); // will update when the page changes so you can do some logic with colors
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
return InkWell(
child: Container(
decoration: BoxDecoration(
border: isHovering == true
? Border(right: BorderSide(color: Colors.blueGrey, width: 10))
: Border(right: BorderSide.none)
),
child: Text(
widget.title,
style: TextStyle(
color: Colors.white,
fontSize: 25
)
)
),
onHover: (value) {
setState(() {
isHovering = value;
});
},
onTap: () {}
);
}
}
user10033434
Updated on December 22, 2022Comments
-
user10033434 over 1 year
I made a website with PageController to control the scroll of some screens. And I made a menu section with screen names, and when any of them are pressed, the user will navigate to the respective screen.
The app is working fine. But I refactored the menu button so I can control it's style, and to add animation in the future.
But when I refactored the button, I can't pass the PageController index, or the nextPage function.
That's why I thought of using the provider package. However, I didn't the package before, and my setup seems complex. For I should pass the PageController state to the button, and the button should send the nextPage function with a new number.
How can I achieve this?
Here's my code:
The button:
class NavigationButton extends StatefulWidget { const NavigationButton({ Key key, this.title, // this.onPressed }) : super(key: key); final String title; // final VoidCallback onPressed; @override _NavigationButtonState createState() => _NavigationButtonState(); } class _NavigationButtonState extends State<NavigationButton> { bool isHovering = false; @override Widget build(BuildContext context) { return InkWell( child: Container( decoration: BoxDecoration( border: isHovering == true ? Border(right: BorderSide(color: Colors.blueGrey, width: 10)) : Border(right: BorderSide.none) ), child: Text( widget.title, style: TextStyle( color: Colors.white, fontSize: 25 ) ) ), onHover: (value) { setState(() { isHovering = value; }); }, onTap: () {} ); } }
The main layout:
class MainLayout extends StatefulWidget { @override _MainLayoutState createState() => _MainLayoutState(); } class _MainLayoutState extends State<MainLayout> { int _index = 0; int selectedButton; bool isHovering = false; PageController pageController = PageController(); final List<String> _sectionsName = [ "Home", "About", "Services", "Portfolio", "Testimonials", "News", "Contact" ]; @override Widget build(BuildContext context) { return Scaffold( extendBodyBehindAppBar: true, appBar: MediaQuery.of(context).size.width > 760 ? null : AppBar( elevation: 0.0, backgroundColor: Colors.transparent ), drawer: MediaQuery.of(context).size.width < 760 ? DrawerWidget() : null, body: Stack( children: [ // MediaQuery.of(context).size.width < 760 ? Container() : DrawerWidget(), Listener( onPointerSignal: (pointerSignal) { if (pointerSignal is PointerScrollEvent) { if (pointerSignal.scrollDelta.dy > 0) { if(_index < _sectionsName.length) { // int newIndex = _index + 1; // pageController.jumpToPage(newIndex); pageController.nextPage( curve: Curves.easeIn, duration: Duration(milliseconds: 500) ); } } else { if(_index < _sectionsName.length) { // int newIndex = _index - 1; // pageController.jumpToPage(newIndex); pageController.previousPage( curve: Curves.easeIn, duration: Duration(milliseconds: 500) ); } } } }, child: PageView( controller: pageController, scrollDirection: Axis.vertical, physics: NeverScrollableScrollPhysics(), children: [ HeroSection(), AboutSection(), ServicesSection(), PortfolioSection(), TestimonialsSection(), NewsSection(), ContactSection() ], onPageChanged: (index) { _index = index; } ) ), MediaQuery.of(context).size.width < 760 ? Container() : Align( alignment: Alignment.centerRight, child: Container( height: 205, width: 200, child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ for (int index = 0; index < _sectionsName.length; index++) NavigationButton(title: _sectionsName[index]) ] ) ) ) ] ) ); } }
Thanks in advance...
Edit:
I followed @EdwynZN answer, and it was very helpful. But I had to pass the index from MainLayout to NavigationButton like so:
MainLayout: NavigationButton(title: _sectionsName[index], index: index)
NavigationButton: Added this to the constructor: this.index. And this to the class: final int index;
finally:
onTap: () { controller.animateToPage(widget.index, curve: Curves.easeIn, duration: Duration(milliseconds: 500)); }
I hope this will help someone some day...
-
EdwynZN almost 3 yearsWhat exactly do you want to accomplish? you want NavigationButton to react when PageController changes and also have an instance of PageController there so you can use nextPage inside NavigationButton ? (using Provider I suppose)
-
user10033434 almost 3 yearsThanks for your comment and your time... I refactored the NavigationButton to another class so I can style it. The button when clicked, should navigate to another screen (page). And, the button should change color after being clicked.
-
-
user10033434 almost 3 yearsI really appreciate your help and taking time to answer my question. I tried your code, but this error was thrown: NoSuchMethodError: invalid member on null: 'round'. I tried to solve it on my own, but couldn't.. How can I solve this?
-
user10033434 almost 3 yearsAlso, when I tried to put the ChangeNotifierProvider.value up the tree, the provider couldn't find it.. How can I solve this? And where can I study and understand the provider package? All the sources that I found before, didn't quite deliver the subject, and there's always something missing.
-
user10033434 almost 3 yearsAnd I tried a few things also, I think I should share it with you: I changed the index to double, hashed out the controller.page.round();, then created int newIndex = index.toInt(); and controller.animateToPage(newIndex, curve: Curves.easeIn, duration: Duration(milliseconds: 500)); inside onTap. However, I get this error: NoSuchMethodError: invalid member on null: 'toInt'
-
user10033434 almost 3 yearsAlso I tried this inside didChangeDependencies(): index = 0; controller.addListener(() { setState(() { index = controller.page.toInt(); }); });
-
user10033434 almost 3 yearsI solved it at last.. I'll update my question, and I'll mark your answer as accepted.. But please, if you know any good resources to study provider from them, please share them with me. I can't thank you enough...
-
EdwynZN almost 3 yearscode with andrea has some really nice videos and courses that I find really helpful codewithandrea.com/tags/provider