Flutter 中 PageController 的 Provider 状态管理
Posted
技术标签:
【中文标题】Flutter 中 PageController 的 Provider 状态管理【英文标题】:Provider state management for PageController in Flutter 【发布时间】:2021-08-27 13:58:07 【问题描述】:我用 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。 而这个类:final int index;
终于:
onTap: ()
controller.animateToPage(widget.index, curve: Curves.easeIn, duration: Duration(milliseconds: 500));
我希望有一天这会对某人有所帮助......
【问题讨论】:
你到底想完成什么?您希望 NavigationButton 在 PageController 更改时做出反应,并且在那里还有一个 PageController 的实例,以便您可以在 NavigationButton 中使用 nextPage ? (我想使用提供者) 感谢您的评论和您的时间...我将 NavigationButton 重构为另一个类,以便我可以设置它的样式。单击该按钮时,应导航到另一个屏幕(页面)。而且,按钮在被点击后应该会改变颜色。 【参考方案1】:使用 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: ()
);
【讨论】:
非常感谢您的帮助并花时间回答我的问题。我试过你的代码,但抛出了这个错误:NoSuchMethodError:null 上的无效成员:'round'。我试图自己解决它,但不能..我该如何解决这个问题? 另外,当我尝试将 ChangeNotifierProvider.value 放在树上时,提供者找不到它。我该如何解决这个问题?我在哪里可以学习和了解提供程序包?我之前找到的所有来源都没有完全传达主题,而且总是缺少一些东西。 我也尝试了一些东西,我想我应该和你分享一下:我将索引更改为 double,散列出 controller.page.round();,然后创建 int newIndex = index .toInt();和controller.animateToPage(newIndex,曲线:Curves.easeIn,持续时间:持续时间(毫秒:500));在 onTap 里面。但是,我收到此错误: NoSuchMethodError: invalid member on null: 'toInt' 我也在 didChangeDependencies(): index = 0; controller.addListener(() setState(() index = controller.page.toInt(); ); ); 我终于解决了..我会更新我的问题,我会将您的答案标记为已接受..但是,如果您从他们那里知道任何学习提供者的好资源,请分享他们和我一起。真是太感谢你了……以上是关于Flutter 中 PageController 的 Provider 状态管理的主要内容,如果未能解决你的问题,请参考以下文章
在 Flutter 的 PageView 模块中没有正确设置 PageController。弹出职位非空错误
无法在 Flutter 中的 PageController 上跳转到页面
Flutter自定义Widget—随滑动改变高度的PageView