flutter-widget-CustomScrollView

2,604 阅读1分钟

CustomScrollView是可以使用Sliver来自定义滚动模型(效果)的组件。如果需要创建可展开的AppBar,后跟list和Grid,可使用这三种Slivers:SliverAppBar,SliverList和SliverGrid。

class CustomScrollViewDemo extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _CustomScrollViewDemoState();
  }
}

class _CustomScrollViewDemoState extends State<CustomScrollViewDemo> {
  ScrollController scrollController = new ScrollController();
  bool showToTopBtn = false;
  double screenHeight;

  @override
  void initState() {
    super.initState();
    scrollController.addListener(() {
      print(scrollController.positions.length);
      print(scrollController.position.toString());
      if (scrollController.offset < screenHeight && showToTopBtn) {
        setState(() {
          showToTopBtn = false;
        });
      } else if (scrollController.offset >= screenHeight && showToTopBtn == false) {
        setState(() {
          showToTopBtn = true;
        });
      }
    });
  }

  @override
  void dispose() {
    scrollController.dispose();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    screenHeight = MediaQuery.of(context).size.height;
    print("screenHeight = " + screenHeight.toString());
    return Scaffold(
      floatingActionButton: !showToTopBtn
          ? null
          : FloatingActionButton(
              child: Icon(Icons.arrow_upward),
              onPressed: () {
                scrollController.animateTo(0,
                    duration: Duration(milliseconds: 200), curve: Curves.ease);
              },
            ),
      body: CustomScrollView(
        controller: scrollController,
        slivers: <Widget>[
          SliverAppBar(
            leading: Icon(Icons.arrow_back),
            centerTitle: true,
            title: const Text('Demo'),
            pinned: true,
            expandedHeight: 200,
            flexibleSpace: FlexibleSpaceBar(
              background: Image.asset(
                "images/food01.jpeg",
                fit: BoxFit.cover,
              ),
            ),
          ),
          SliverPadding(
            padding: EdgeInsets.all(8),
            sliver: SliverGrid(
              gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(
                  crossAxisCount: 4,
                  mainAxisSpacing: 10,
                  crossAxisSpacing: 10,
                  childAspectRatio: 4),
              delegate:
                  SliverChildBuilderDelegate((BuildContext context, int index) {
                return Container(
                  alignment: Alignment.center,
                  color: Colors.cyan[100 * (index % 9)],
                  child: new Text('grid item $index'),
                );
              }, childCount: 20),
            ),
          ),
          SliverFixedExtentList(
            itemExtent: 50,
            delegate:
                SliverChildBuilderDelegate((BuildContext context, int index) {
              return Container(
                alignment: Alignment.center,
                color: Colors.lightBlue[100 * (index % 9)],
                child: new Text('list item $index'),
              );
            }, childCount: 50),
          )
        ],
      ),
    );
  }
}

上述代码实现了CustomScrollView中嵌套SliverAppBar,SliverPadding,SliverGrid,SliverFixedExtendedList,,并且加入了滑动控制(大于一屏时显示回顶部按钮)

如何想监听滑动进度,我们需要把上述控件包裹在Scrollbar中,通过NotificationListener来将滑动的进度返回。具体代码

class _CustomScrollViewDemoState extends State<CustomScrollViewDemo> {
...;
  String _progress = "0%";
 ...

  @override
  Widget build(BuildContext context) {
    screenHeight = MediaQuery.of(context).size.height;
    print("screenHeight = " + screenHeight.toString());
    return Scaffold(
    ...
      body: Scrollbar(
        child: NotificationListener<ScrollNotification>(
          onNotification: (ScrollNotification notification) {
            double progress = notification.metrics.pixels /
                notification.metrics.maxScrollExtent;
            //重新构建
            setState(() {
              _progress = "${(progress * 100).toInt()}%";
            });
            print("BottomEdge: ${notification.metrics.extentAfter == 0}");
          },
          child: Stack(
            alignment: Alignment.center,
            children: <Widget>[
              CustomScrollView(
                 ....
              ),
              CircleAvatar(
                radius: 30.0,
                child: Text(_progress),
                backgroundColor: Colors.black54,
              )
            ],
          ),
        ),
      ),
    );
  }
}

与之前不同的地方已经标识出来了,结果为