Flutter 中 PageController 的提供者状态管理
Provider state management for PageController in Flutter
我用PageController做了一个网站来控制一些屏幕的滚动。我制作了一个带有屏幕名称的菜单部分,当按下其中任何一个时,用户将导航到相应的屏幕。
该应用运行良好。但是我重构了菜单按钮,所以我可以控制它的样式,并在将来添加动画。
但是我在重构按钮的时候,无法传递PageController索引,或者nextPage函数。
这就是我想到使用提供程序包的原因。但是,我之前没有打包,而且我的设置似乎很复杂。因为我应该将 PageController 状态传递给按钮,并且按钮应该发送带有新数字的 nextPage 函数。
我怎样才能做到这一点?
这是我的代码:
按钮:
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: () {}
);
}
}
主要布局:
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])
]
)
)
)
]
)
);
}
}
提前致谢...
编辑:
我关注了@EdwynZN 的回答,非常有帮助。但是我必须像这样将索引从 MainLayout 传递到 NavigationButton:
主要布局:
NavigationButton(title: _sectionsName[index], index: index)
导航按钮:
将其添加到构造函数中:this.index。
这是 class: final int index;
终于:
onTap: () {
controller.animateToPage(widget.index, curve: Curves.easeIn, duration: Duration(milliseconds: 500));
}
我希望有一天这会对某人有所帮助...
使用 Provider,您可以使用 ChangeNotifierProvider.value
包装需要 PageController 的小部件
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])
]
)
)
),
),
那么所有的NavigationButton都可以作为inheretedWidget访问pageController
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: () {}
);
}
}
我用PageController做了一个网站来控制一些屏幕的滚动。我制作了一个带有屏幕名称的菜单部分,当按下其中任何一个时,用户将导航到相应的屏幕。
该应用运行良好。但是我重构了菜单按钮,所以我可以控制它的样式,并在将来添加动画。
但是我在重构按钮的时候,无法传递PageController索引,或者nextPage函数。
这就是我想到使用提供程序包的原因。但是,我之前没有打包,而且我的设置似乎很复杂。因为我应该将 PageController 状态传递给按钮,并且按钮应该发送带有新数字的 nextPage 函数。
我怎样才能做到这一点?
这是我的代码:
按钮:
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: () {}
);
}
}
主要布局:
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])
]
)
)
)
]
)
);
}
}
提前致谢...
编辑:
我关注了@EdwynZN 的回答,非常有帮助。但是我必须像这样将索引从 MainLayout 传递到 NavigationButton:
主要布局: NavigationButton(title: _sectionsName[index], index: index)
导航按钮: 将其添加到构造函数中:this.index。 这是 class: final int index;
终于:
onTap: () {
controller.animateToPage(widget.index, curve: Curves.easeIn, duration: Duration(milliseconds: 500));
}
我希望有一天这会对某人有所帮助...
使用 Provider,您可以使用 ChangeNotifierProvider.value
包装需要 PageController 的小部件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])
]
)
)
),
),
那么所有的NavigationButton都可以作为inheretedWidget访问pageController
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: () {}
);
}
}