如何为多个 SilverList 或 ListView 项目应用滚动控制器?

How to apply Scroll controller for multiple SilverList or ListView items?

我在互联网上找到了一种在使用 CustomSrollView 水平滚动 FlutterLogo 时隐藏箭头的方法。该功能有效,我想将它放在 ListView.builderSilverList 中,所以我有多个具有滚动功能的小部件,但是一旦我将 CustomScrollView 放在列表中,它的 ListView.builderSilverList 我得到错误:

ScrollController attached to multiple scroll views.
'package:flutter/src/widgets/scroll_controller.dart':
Failed assertion: line 108 pos 12: '_positions.length == 1'

这是完整代码:

class AppView2 extends StatefulWidget {
  const AppView2({
    Key? key,
  }) : super(key: key);

  @override
  _AppViewState createState() => _AppViewState();
}

class _AppViewState extends State<AppView2> {
  late ScrollController _hideButtonController;
  var _isVisible;
 
  @override
  void initState() {
    _isVisible = true;
    _hideButtonController = ScrollController();
    _hideButtonController.addListener(() {
      if (_hideButtonController.position.userScrollDirection ==
          ScrollDirection.reverse) {
        if (_isVisible == true) {
          /* only set when the previous state is false
             * Less widget rebuilds
             */
          print("**** $_isVisible up"); //Move IO away from setState
          setState(() {
            _isVisible = false;
          });
        }
      } else {
        if (_hideButtonController.position.userScrollDirection ==
            ScrollDirection.forward) {
          if (_isVisible == false) {
            setState(() {
              _isVisible = true;
            });
          }
        }
      }
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
        child: Scaffold(
            appBar: AppBar(
              title: Text("Example app bar"),
            ),
            body: CustomScrollView(slivers: <Widget>[
              SliverList(
                delegate: SliverChildBuilderDelegate(
                    (BuildContext context, int index) {
                  return SizedBox(
                    height: 500,
                    child: Stack(
                      children: [
                        CustomScrollView(
                          controller: _hideButtonController,
                          scrollDirection: Axis.horizontal,
                          shrinkWrap: true,
                          slivers: <Widget>[
                            SliverPadding(
                              padding: const EdgeInsets.all(20.0),
                              sliver: SliverList(
                                delegate: SliverChildListDelegate(
                                  <Widget>[
                                    FlutterLogo(
                                      size: 600,
                                    )
                                  ],
                                ),
                              ),
                            ),
                          ],
                        ),
                        Visibility(
                          visible: _isVisible,
                          child: Align(
                            alignment: Alignment.centerRight,
                            child: FloatingActionButton(
                                child: const Icon(Icons.arrow_forward_ios),
                                onPressed: () {}),
                          ),
                        )
                      ],
                    ),
                  );
                }, childCount: 10),
              )
            ])));
  }
}

如何确保 _hideButtonControllerSilverListListView 中的多个小部件一起工作?

不太清楚您要完成什么,但这是抛出错误的原因,也许还有一些建议可以提供帮助。

抛出错误是因为您在侦听器代码中使用了 ScrollControllerposition getter,同时附加了多个位置。这是文档中的引述:

Calling this is only valid when only a single position is attached.

https://api.flutter.dev/flutter/widgets/ScrollController/position.html

您可以在侦听器中使用 positions 并检查附加位置的 any 条件,尽管这可能不是您想要的。

_hideButtonController.addListener(() {
      if (_hideButtonController.positions.any((pos) => pos.userScrollDirection ==
          ScrollDirection.reverse)) {
        if (_isVisible == true) {
          /* only set when the previous state is false
             * Less widget rebuilds
             */
          print("**** $_isVisible up"); //Move IO away from setState
          setState(() {
            _isVisible = false;
          });
        }
      } else {
        if (_hideButtonController.positions.any((pos) => pos.userScrollDirection ==
            ScrollDirection.forward)) {
          if (_isVisible == false) {
            setState(() {
              _isVisible = true;
            });
          }
        }
      }
    });

如果您只想分享在满足单个水平滚动条的条件时隐藏按钮的代码,您最好的选择可能是编写自己的小部件,该小部件拥有自己的 ScrollController您已经拥有的侦听器代码。这允许垂直列表的每个子项对于水平列表都有自己的 ScrollController,从而允许您只隐藏受影响的控制器的按钮:

class LogoHidingScrollView extends StatefulWidget {
  const LogoHidingScrollView({
    Key? key,
  }) : super(key: key);

  _LogoHidingScrollViewState createState() => _LogoHidingScrollViewState();
}

class _LogoHidingScrollViewState extends State<LogoHidingScrollView> {
  final ScrollController _scrollController = ScrollController();
  bool _isVisible = true;

  void initState() {
    _isVisible = true;
    _scrollController.addListener(() {
      if (_scrollController.position.userScrollDirection ==
          ScrollDirection.reverse) {
        if (_isVisible == true) {
          /* only set when the previous state is false
             * Less widget rebuilds
             */
          print("**** $_isVisible up"); //Move IO away from setState
          setState(() {
            _isVisible = false;
          });
        }
      } else {
        if (_scrollController.position.userScrollDirection ==
            ScrollDirection.forward) {
          if (_isVisible == false) {
            setState(() {
              _isVisible = true;
            });
          }
        }
      }
    });
    super.initState();
  }

  Widget build(BuildContext context) {
    return SizedBox(
      height: 500,
      child: Stack(
        children: [
          CustomScrollView(
            controller: _scrollController,
            scrollDirection: Axis.horizontal,
            shrinkWrap: true,
            slivers: <Widget>[
              SliverPadding(
                padding: const EdgeInsets.all(20.0),
                sliver: SliverList(
                  delegate: SliverChildListDelegate(
                    <Widget>[
                      FlutterLogo(
                        size: 600,
                      )
                    ],
                  ),
                ),
              ),
            ],
          ),
          Visibility(
            visible: _isVisible,
            child: Align(
              alignment: Alignment.centerRight,
              child: FloatingActionButton(
                  child: const Icon(Icons.arrow_forward_ios), onPressed: () {}),
            ),
          )
        ],
      ),
    );
  }
}

如果你真的想同步所有那些水平滚动视图之间的滚动行为,你可以看看:https://pub.dev/packages/linked_scroll_controller