首页 > 解决方案 > 带有 ScrollController 的嵌套 ListView 不滚动

问题描述

我正在构建一个带有自定义导航栏的小部件,其中包括Stack主体和导航栏。

@override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        _buildBody(),
        _buildNavigationBar(),
      ],
    );
  }

正文由ListView带有标题的a 和ListView.builder嵌套在内容下方的a 组成。

Widget _buildBody() {
    return ListView(
      padding: EdgeInsets.only(top: 44.0 + MediaQuery.of(context).padding.top),
      controller: _scrollController,
      children: [
        Opacity(
          opacity: 1.0 - _navigationBarOpacity,
          child: Padding(
            padding: const EdgeInsets.only(bottom: 15.0),
            child: _buildHeaderTitle(
              title: widget.title,
              fontSize: _largeFontSize,
              fontWeight: _largeFontWeight,
              color: widget.color,
            ),
          ),
        ),
        ListView.builder(
          padding: EdgeInsets.zero,
          shrinkWrap: true,
          physics: NeverScrollableScrollPhysics(),
          itemCount: widget.itemCount,
          itemBuilder: (context, index) {
            return widget.itemBuilder(context, index);
          },
        ),
      ],
    );
  }

ScrollController在主要/根目录上使用 aListView来淡入和淡出我的导航栏。这按预期工作。

但是,添加ScrollControllerListView停止任何滚动/弹跳交互。我怎样才能解决这个问题?

ScrollController _scrollController = ScrollController();

@override
  void initState() {
    super.initState();

    _scrollController.addListener(() {
      setState(() {
        double min = 0.0;
        double max = 25.0;
        _navigationBarOpacity = (_scrollController.offset - min) / (max - min);
        if (_navigationBarOpacity < 0) _navigationBarOpacity = 0;
        if (_navigationBarOpacity > 1) _navigationBarOpacity = 1;
      });
    });  
  }

有趣的是,如果我将 移动ScrollController到 nestedt ListView.builder,根会ListView滚动/弹跳,但是我不能再根据偏移量调整 UI,因为它是错误的ListView

另一个有趣的地方,ListView如果它的孩子超过它的高度,根会正常滚动。但是,在某些情况下它不会出现这种情况,我希望它会在拉动时反弹。


更新

即使我删除了 stack 和 nested ListView,一个简单的单数ListViewScrollController也不会在拖动时滚动,没有它,它会。这是需要解决的根本问题。

@override
  Widget build(BuildContext context) {
    return ListView(
        padding: EdgeInsets.only(top: 44.0 + MediaQuery.of(context).padding.top),
        controller: _scrollController,
        children: [
          Opacity(
            opacity: 1.0 - _navigationBarOpacity,
            child: Padding(
              padding: const EdgeInsets.only(bottom: 15.0),
              child: _buildHeaderTitle(
                title: widget.title,
                fontSize: _largeFontSize,
                fontWeight: _largeFontWeight,
                color: widget.color,
              ),
            ),
          ),
        ],
      );
  }

标签: flutterlistviewnestedscrollcontroller

解决方案


通过将父级包装ListView在.PrimaryScrollControllerprimary = trueListView

这允许PrimaryScrollController管理控制器,但ListView保持典型的滚动行为,因为它不再管理ScrollController.

请参阅 Flutter 文档:https ://api.flutter.dev/flutter/widgets/ScrollView/primary.html


推荐阅读