带有 SliverAppBar 的 ScrollablePositionedList 无法正常工作

Posted

技术标签:

【中文标题】带有 SliverAppBar 的 ScrollablePositionedList 无法正常工作【英文标题】:ScrollablePositionedList with SliverAppBar not working properly 【发布时间】:2020-05-17 09:47:39 【问题描述】:

This is a repository 创建一个最小的可重现示例

ScrollablePositionedList.builder 被滚动时,我想隐藏SliverAppBar。这是我在这里包含的相关代码。

          NestedScrollView(
              headerSliverBuilder: (context, innerBoxIsScrolled) => [
                    SliverAppBar(
                      backgroundColor: Colors.blue,
                      expandedHeight: 112,
                      snap: true,
                      pinned: false,
                      floating: true,
                      forceElevated: true,
                      actions: <Widget>[
                        IconButton(
                          icon: Icon(Icons.event),
                        )
                      ],
                      flexibleSpace: SafeArea(
                        child: Column(
                          children: <Widget>[
                            Container(
                              height: kToolbarHeight,
                              child: Column(
                                crossAxisAlignment: CrossAxisAlignment.center,
                                mainAxisAlignment: MainAxisAlignment.center,
                                children: <Widget>[
                                  Text(
                                    'Title',
                                    style: Theme.of(context)
                                        .textTheme
                                        .title
                                        .copyWith(
                                            fontSize: 16, color: Colors.white),
                                  ),
                                  SizedBox(
                                    height: 2,
                                  ),
                                  Text(
                                    'Date',
                                    style: Theme.of(context)
                                        .textTheme
                                        .caption
                                        .copyWith(
                                            fontSize: 10, color: Colors.white),
                                  ),
                                  SizedBox(
                                    height: 2,
                                  ),
                                  Text(
                                    'Another Text',
                                    style: Theme.of(context)
                                        .textTheme
                                        .subtitle
                                        .copyWith(
                                            fontSize: 14, color: Colors.white),
                                  ),
                                ],
                              ),
                            ),
                            Expanded(
                              child: Container(
                                height: kToolbarHeight,
                                width: MediaQuery.of(context).size.width,
                                color: Colors.white,
                                child: Row(
                                  mainAxisAlignment:
                                      MainAxisAlignment.spaceEvenly,
                                  children: <Widget>[
                                    Text(
                                      'Prev',
                                    ),
                                    Text(
                                      'Next',
                                    )
                                  ],
                                ),
                              ),
                            )
                          ],
                        ),
                      ),
                    )
                  ],
              body: ScrollablePositionedList.builder(
                  physics: ScrollPhysics(),
                  itemPositionsListener: itemPositionListener,
                  itemScrollController: _itemScrollController,
                  initialScrollIndex: 0,
                  itemCount: 500,
                  itemBuilder: (BuildContext ctxt, int index) 
                    return Container(
                        margin: EdgeInsets.all(16)
                        ,
                        child: Text('$index'));
                  )),

到目前为止,我尝试了两种方法都无法正常工作,

方法 1

我将physics: ScrollPhysics(), 添加到ScrollablePositionedList.builder

输出:

方法 2

我将physics: NeverScrollableScrollPhysics(), 添加到ScrollablePositionedList.builder

SliverAppBar 这次隐藏了,但现在我无法滚动到ScrollablePositionedList.builder 的最后,我的列表中有 500 个项目,但它只能滚动到第 14 个项目,请参阅输出。此外,它在滚动时滞后太多

输出:

提前致谢。

【问题讨论】:

您为什么不尝试基于 customScroll 视图的方法,如此处所示。 flutter.dev/docs/cookbook/lists/floating-app-bar 因为ScrollablePositionedList 允许滚动到特定项目。 这里有同样的问题,为什么 Flutter 团队之外的任何东西都不起作用,太令人沮丧了。除了核心 Flutter UI 之外的任何东西都不能一直运行良好 【参考方案1】:

这是一个基本的解决方法:

使用 ItemsPositionsListener 监听列表滚动到的当前项目。 然后创建布尔值来检查滚动方向和数量。 这些条件控制 AnimatedContainer 控制自定义标题的高度。 这是作为子项放置在 Column 中,标题位于灵活小部件中,因此可滚动列表正确占用动画前后的空间。

虽然这个很基础,没有使用NestedScrollView,但它继续使用ScrollablePositionedList,并根据设置的滚动条件,通过一个滑入滑出的header实现类似的效果。

提供以防万一对其他人有帮助,直到根本问题得到解决...:)


import 'package:flutter/material.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';

class ScrollAllWords extends StatefulWidget 
  const ScrollAllWords(
    Key? key,
    required this.list,
  ) : super(key: key);

  final List<String> list;

  @override
  State<ScrollAllWords> createState() => _ScrollAllWordsState();


class _ScrollAllWordsState extends State<ScrollAllWords> 

/// use this listener to control the header position.
  final _itemPositionsListener = ItemPositionsListener.create();

///Can also use the ItemScrollController to animate through the list (code omitted)
final _itemScrollController = ItemScrollController();


  /// Gets the current index the list has scrolled to.
  int _currentIndex = 0;

  /// Compares against current index to determine the scroll direction.
  int _shadowIndex = 0;


  bool _reverseScrolling = false;
  bool _showHeader = true;

  @override
  void initState() 

    /// Set up the listener.
    _itemPositionsListener.itemPositions.addListener(() 
      checkScroll();
    );

    super.initState();
  

  void checkScroll() 
    /// Gets the current index of the scroll.
    _currentIndex =
        _itemPositionsListener.itemPositions.value
            .elementAt(0)
            .index;

    /// Checks the scroll direction.
    if (_currentIndex > _shadowIndex) 
      _reverseScrolling = false;
      _shadowIndex = _currentIndex;
    
    if (_currentIndex < _shadowIndex) 
      _reverseScrolling = true;
      _shadowIndex = _currentIndex;
    

    /// Checks whether to show or hide the scroller (e.g. show when scrolled passed 15 items and not reversing).
    if (!_reverseScrolling && _currentIndex > 15) 
      _showHeader = false;
     else 
      _showHeader = true;
    

    setState(() );
  

  @override
  Widget build(BuildContext context) 

    return Column(
      children: [
        AnimatedContainer(
          duration: const Duration(milliseconds: 120),
          height: _showHeader ? 200 : 0,
          curve: Curves.easeOutCubic,

          child: Container(
            color: Colors.red,
            height: size.height * 0.20,
          ),
        ),

        Flexible(
          child: ScrollablePositionedList.builder(
            itemScrollController: _itemScrollController,
            itemPositionsListener: _itemPositionsListener,
            itemCount: widget.list.length,
            itemBuilder: (context, index) 
              return ListTile(
                title: Text(widget.list[index]),
              );
            ,
          ),
        ),

      ],
    );
  

【讨论】:

【参考方案2】:
    It works for me
    //create list of global keys

     List<GlobalKey> _formKeys = [];
    
    
    //assign keys from your list
    
    for(int i=0 ;i< syourlist.length;i++)
    final key = GlobalKey();
    _formKeys.add(key);
    
    
    //in list view give key as below
    
    key:_formKeys[index]
    
    
    //on button click
    
     Scrollable.ensureVisible(_formKeys[index].currentContext);

【讨论】:

您的答案可以通过额外的支持信息得到改进。请编辑以添加更多详细信息,例如引文或文档。您可以在帮助中心找到有关如何编写好的答案的更多信息。见【如何回答】***.com/questions/how-to-answer) 我在你的代码中没有看到ScrollablePositionedList【参考方案3】:

自己回答问题

这个问题没有解决办法。我创建了一个问题here

看起来 ScrollablePositionedListSliverAppBar 无法正常工作,直到 Flutter Team 未将 shrinkwrap 属性添加到 ScrollablePositionedList

添加shrinkwrap 的功能请求已创建here

【讨论】:

您好,您找到其他解决方案了吗?谢谢!

以上是关于带有 SliverAppBar 的 ScrollablePositionedList 无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章

滚动带有ScrollController的CustomScrollView时,SliverAppbar仍然可见

带有标签的Flutter SliverAppBar覆盖内容

使 SliverAppBar 具有图像作为背景而不是颜色

向下滚动时隐藏的 Flutter TabBar 和 SliverAppBar

SliverAppBar 介绍及使用

Flutter 中的 SliverAppBar 和 SliverPersistentHeader 有啥区别?