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: () {}
    );
  }
}