美文网首页flutter
CustomScrollView

CustomScrollView

作者: 乐狐 | 来源:发表于2022-07-12 08:57 被阅读0次
    CustomScrollView.png
    • CustomScrollView: 提供一个公共 Scrollable 和 Viewport 组合多个 Sliver,实现统一滑动,子元素都为Sliver。
    Sliver名称 功能 对应滚动组件
    SliverList 列表 ListView
    SliverFixedExtentList 项目高度固定列表 ListView 指定itemExtent
    SliverPrototypeExtentList 根据原型生成高度固定的列表 ListView 指定prototypeItem
    SliverAnimatedList 添加/删除列表项时执行动画 AnimatedList
    SliverGrid 网格 GridView
    SliverFillViewport 子组件可填满屏幕 PageView
    Sliver名称 对应RenderBox
    SliverAppBar AppBar
    SliverPadding Padding
    SliverToBoxAdapter 将 RenderBox 适配为 Sliver
    SliverPersistentHeader 滑至顶部固定
    SliverVisibility、SliverOpacity Visibility、Opacity
    SliverFadeTransition FadeTransition
    SliverLayoutBuilder LayoutBuilder
    • 建议使用 SliverPersistentHeader 代替 SliverAppBar。
    import 'package:flutter/material.dart';
    
    void main() {
      runApp(const MaterialApp(
        debugShowCheckedModeBanner: false,
        home: SliverPersistentHeaderWidget(title: "测试"),
      ));
    }
    
    class CustomScrollViewWidget extends StatefulWidget {
      const CustomScrollViewWidget({Key? key}) : super(key: key);
    
      @override
      State<StatefulWidget> createState() => _CustomScrollViewWidgetState();
    }
    
    class _CustomScrollViewWidgetState extends State<CustomScrollViewWidget> {
      final List<String> _items = List<String>.generate(100, (i) => "Item1 $i");
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text('CustomScrollView'),
          ),
          //两个滚动组件自己独立的 Scrollable、Viewport和Sliver
          body: Column(children: [
            Container(
              height: 80,
              decoration: const BoxDecoration(color: Colors.deepOrange),
              child: GridView.count(
                crossAxisCount: 5,
                childAspectRatio: 1.0,
                children: const [
                  Icon(Icons.add),
                  Icon(Icons.add),
                  Icon(Icons.add),
                  Icon(Icons.add),
                  Icon(Icons.add),
                  Icon(Icons.add),
                  Icon(Icons.add),
                  Icon(Icons.add),
                ],
              ),
            ),
            Expanded(
              child: ListView.builder(
                itemBuilder: (BuildContext context, int index) {
                  return ListTile(title: Text('${_items[index]} abc'));
                },
                itemCount: _items.length,
              ),
            ),
          ]),
        );
      }
    }
    
    class CustomScrollView2Widget extends StatefulWidget {
      const CustomScrollView2Widget({Key? key}) : super(key: key);
    
      @override
      State<StatefulWidget> createState() => _CustomScrollView2WidgetState();
    }
    
    class _CustomScrollView2WidgetState extends State<CustomScrollView2Widget> {
      SliverFixedExtentList listSliver = SliverFixedExtentList(
        delegate: SliverChildBuilderDelegate((ctx, index) {
          return ListTile(
            title: Text("$index"),
          );
        }, childCount: 10),
        itemExtent: 56,
      );
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text('CustomScrollView'),
          ),
          body: CustomScrollView(
            slivers: [listSliver, listSliver],
          ),
        );
      }
    }
    
    class CustomScrollView3Widget extends StatelessWidget {
      const CustomScrollView3Widget({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Material(
          child: CustomScrollView(
            slivers: [
              SliverAppBar(
                //滑动到顶端时会固定住
                //pinned: true,
                expandedHeight: 200.0,
                title: const Text('Demo'),
                flexibleSpace: FlexibleSpaceBar(
                  background: Image.network(
                    "https://upload.jianshu.io/admin_banners/web_images/5055/348f9e194f4062a17f587e2963b7feb0b0a5a982.png?imageMogr2/auto-orient/strip|imageView2/1/w/1250/h/540",
                    fit: BoxFit.cover,
                  ),
                ),
              ),
              //可单独滚动的组件
              SliverToBoxAdapter(
                child: Container(
                  height: 100,
                  decoration: const BoxDecoration(color: Colors.deepOrange),
                  child: PageView(
                    children: const [
                      Text("PageViewA 横向滑动"),
                      Text("PageViewB 横向滑动")
                    ],
                  ),
                ),
              ),
              SliverPadding(
                padding: const EdgeInsets.all(8.0),
                sliver: SliverGrid(
                  //Grid
                  gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: 2,
                    mainAxisSpacing: 10.0,
                    crossAxisSpacing: 10.0,
                    childAspectRatio: 4.0,
                  ),
                  delegate: SliverChildBuilderDelegate(
                    (BuildContext context, int index) {
                      return Container(
                        alignment: Alignment.center,
                        color: Colors.cyan[100 * (index % 9)],
                        child: Text('grid item $index'),
                      );
                    },
                    childCount: 20,
                  ),
                ),
              ),
              SliverFixedExtentList(
                itemExtent: 50.0,
                delegate: SliverChildBuilderDelegate(
                  (BuildContext context, int index) {
                    return Container(
                      alignment: Alignment.center,
                      color: Colors.lightBlue[100 * (index % 9)],
                      child: Text('list item $index'),
                    );
                  },
                  childCount: 20,
                ),
              ),
            ],
          ),
        );
      }
    }
    
    class SliverPersistentHeaderWidget extends StatefulWidget {
      final String title;
    
      const SliverPersistentHeaderWidget({Key? key, required this.title})
          : super(key: key);
    
      @override
      State<SliverPersistentHeaderWidget> createState() =>
          SliverPersistentHeaderState();
    }
    
    class SliverPersistentHeaderState extends State<SliverPersistentHeaderWidget> {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Material(
            child: CustomScrollView(
              slivers: [
                buildSliverList(),
                SliverPersistentHeader(
                  pinned: true, //滑到顶部固定
                  delegate: PersistentHeaderDelegate(
                    maxHeight: 60,
                    minHeight: 40,
                    child: buildHeader(1),
                  ),
                ),
                buildSliverList(),
                SliverPersistentHeader(
                  pinned: true, //滑到顶部固定
                  delegate: PersistentHeaderDelegate.fixedHeight(
                    height: 40,
                    child: buildHeader(2),
                  ),
                ),
                buildSliverList(),
                SliverPersistentHeader(
                  pinned: true, //滑到顶部固定
                  delegate: PersistentHeaderDelegate.fixedHeight(
                    height: 40,
                    child: buildHeader(3),
                  ),
                ),
              ],
            ),
          ),
        );
      }
    
      Widget buildSliverList([int count = 18]) {
        return SliverFixedExtentList(
            delegate: SliverChildBuilderDelegate(
              (context, index) {
                return ListTile(title: Text('$index'));
              },
              childCount: count,
            ),
            itemExtent: 50);
      }
    
      Widget buildHeader(int i) {
        return Container(
          color: Colors.lightBlue.shade200,
          alignment: Alignment.centerLeft,
          child: Text(" PersistentHeader $i"),
        );
      }
    }
    
    typedef SliverHeaderBuilder = Widget Function(
        BuildContext context, double shrinkOffset, bool overlapsContent);
    
    class PersistentHeaderDelegate extends SliverPersistentHeaderDelegate {
      PersistentHeaderDelegate({
        required this.maxHeight,
        this.minHeight = 0,
        required Widget child,
      })  : builder = ((a, b, c) => child),
            assert(minHeight <= maxHeight && minHeight >= 0);
    
      //最大和最小高度相同
      PersistentHeaderDelegate.fixedHeight({
        required double height,
        required Widget child,
      })  : builder = ((a, b, c) => child),
            maxHeight = height,
            minHeight = height;
    
      //自定义builder时使用
      PersistentHeaderDelegate.builder({
        required this.maxHeight,
        this.minHeight = 0,
        required this.builder,
      });
    
      final double maxHeight;
      final double minHeight;
      final SliverHeaderBuilder builder;
    
      @override
      Widget build(
          BuildContext context, double shrinkOffset, bool overlapsContent) {
        Widget child = builder(context, shrinkOffset, overlapsContent);
        assert(() {
          if (child.key != null) {
            print('${child.key}: shrink: $shrinkOffset,overlaps:$overlapsContent');
          }
          return true;
        }());
        return SizedBox.expand(child: child);
      }
    
      @override
      double get maxExtent => maxHeight;
    
      @override
      double get minExtent => minHeight;
    
      @override
      bool shouldRebuild(covariant SliverPersistentHeaderDelegate old) {
        return old.maxExtent != maxExtent || old.minExtent != minExtent;
      }
    }
    

    相关文章

      网友评论

        本文标题:CustomScrollView

        本文链接:https://www.haomeiwen.com/subject/kmnubrtx.html