如何阻止被钉住的SliverAppBar覆盖浮动的SliverPersistentHeader?

问题描述 投票:0回答:1

我正在学习Flutter,目前正在尝试制作一个具有酷炫滚动效果的主页。我试图实现一个包含3个元素的CustomScrollView:一个SliverAppBar,一个水平滚动列表和一个SliverList。前两个元素很简单,经过一番努力,我通过使用SliverPersistentHeader实现了水平滚动列表。

然而,我遇到了一个问题。我希望SliverAppBar被钉住,而包含水平滚动列表的SliverPersistentHeader是浮动的。除了浮动元素,一切都很好 有恃无恐 当向下滚动后再向上滚动时,被钉住的那个元素所影响。我基本上是想让浮动元素 "知道 "上面有另一个元素,并在向上滚动时偏移自己。

你可以在这里看到我的代码,同时也可以看到这个问题。https:/dartpad.dev32d3f2a890d4a676decb014744fcc9ba。

确保你点击并拖动滚动,才能看到问题!

我如何解决这个问题?是不是我遗漏了什么导致这个问题?

谢谢您的时间!

flutter dart flutter-layout
1个回答
0
投票
    import 'package:flutter/material.dart';
    import 'package:flutter/rendering.dart';

    void main() {
      runApp(new MyApp());
    }

    class MyApp extends StatefulWidget {
      @override
      _MyAppState createState() => _MyAppState();
    }

    class _MyAppState extends State<MyApp> {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          debugShowCheckedModeBanner: false,
          home: Home(),
        );
      }
    }


// I had to change this class to a StatefulWidget to be able to listen to the scroll event
    class Home extends StatefulWidget {
      @override
      State<StatefulWidget> createState() {
        return _HomeState();
      }
    }

    class _HomeState extends State<Home>  {
// Here I declared the ScrollController for the CustomScrollView
      ScrollController _controller;

// And here is a boolean to check when the user scrolls up or down the view
      bool sliverPersistentHeader = false;

      @override
      void initState() {
        super.initState();
// The ScrollController is initialized in the initState and listens for when the user starts scrolling up and changes the boolean value accordingly
        _controller = ScrollController();
        _controller.addListener(() {
          if (_controller.position.userScrollDirection == ScrollDirection.reverse) {
            setState(() {
              sliverPersistentHeader = false;
            });
          } else {
            setState(() {
              sliverPersistentHeader = true;
            });
          }
        });
      }

      @override
      void dispose() {
        super.dispose();
        _controller.dispose();
      }

      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: CustomScrollView(
            controller: _controller,
            slivers: <Widget>[
              SliverAppBar(
                floating: true,
                pinned: true,
                expandedHeight: 200.0,
                flexibleSpace: FlexibleSpaceBar(
                  centerTitle: true,
                  title: Text('App Title'),
                ),
              ),
              SliverPersistentHeader(
// The SliverPersisitentHeader checks the boolean value and either pins or unpins the the Header
                pinned: sliverPersistentHeader ? true : false,
                delegate: CustomSliver(
                  expandedHeight: 150.0,
                ),
              ),
              SliverList(
                delegate: SliverChildBuilderDelegate(
                  (_, index) => Padding(
                    padding: EdgeInsets.symmetric(vertical: 10.0),
                    child: Container(
                      height: 50.0,
                      color: Colors.amber,
                    ),
                  ),
                ),
              ),
            ],
          ),
          bottomNavigationBar: BottomNavigationBar(
            items: [
              BottomNavigationBarItem(
                icon: Icon(Icons.home),
                title: Text('Tab1'),
              ),
              BottomNavigationBarItem(
                icon: Icon(Icons.home),
                title: Text('Tab2'),
              ),
              BottomNavigationBarItem(icon: Icon(Icons.home), title: Text('Tab3'))
            ],
            currentIndex: 0,
          ),
        );
      }
    }

    class CustomSliver extends SliverPersistentHeaderDelegate {
      final double expandedHeight;

      CustomSliver({@required this.expandedHeight});

      @override
      Widget build(
          BuildContext context, double shrinkOffset, bool overlapsContent) {
        return Scrollbar(
          child: Container(
              color: Theme.of(context).canvasColor,
              padding: EdgeInsets.fromLTRB(10.0, 15.0, 0, 5.0),
              child: ListView.separated(
                shrinkWrap: true,
                physics: BouncingScrollPhysics(),
                scrollDirection: Axis.horizontal,
                itemCount: 10,
                itemBuilder: (BuildContext context, int index) {
                  return Padding(
                    padding: EdgeInsets.only(right: 10.0, top: 10.0, bottom: 10.0),
                    child: Container(
                      width: 100,
                      decoration: BoxDecoration(
                          color: Colors.red,
                          borderRadius: BorderRadius.all(Radius.circular(20.0)),
                          boxShadow: [
                            BoxShadow(
                                color: Colors.black.withOpacity(0.16),
                                offset: Offset(0, 3.0),
                                blurRadius: 6.0),
                          ]),
                      child: Column(
                        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                        crossAxisAlignment: CrossAxisAlignment.center,
                        children: <Widget>[
                          Icon(Icons.navigation),
                          Text(
                            'Category',
                            textAlign: TextAlign.center,
                            style: TextStyle(color: Colors.white),
                          ),
                        ],
                      ),
                    ),
                  );
                },
                separatorBuilder: (BuildContext context, int index) {
                  return SizedBox(width: 5.0);
                },
              )),
        );
      }

      @override
      double get maxExtent => expandedHeight;

      @override
      double get minExtent => 150.0;

      @override
      bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) {
        return true;
      }
    }

我唯一没有做的就是将SliverPersistentHeader动画化成视图,希望你能自己实现。我相信还有其他的方法可以实现,但这个方案应该对你有用。

© www.soinside.com 2019 - 2024. All rights reserved.