Flutter 入门 - 滚动视图

402 阅读2分钟

ListView

构造方法

ListView()

适合数量少的,一下子全部创建出来

return ListView(
      children: [
        ListTile( // 类似于 UITableViewCell
          leading: Icon(Icons.people),
          title: Text("Title - "),
          subtitle: Text("Subtitle"),
          trailing: Icon(Icons.delete),
          onTap: () { //点击方法
            print('sss');
          },
        ),
        Divider(
          height: 0.5,
          thickness: 0.5,
        ),
        ListTile(
          leading: Icon(Icons.people),
          title: Text("Title - "),
          subtitle: Text("Subtitle"),
          trailing: Icon(Icons.delete),
        ),
        Divider(
          height: 0.5,
          thickness: 0.5,
        ),
        ListTile(
          leading: Icon(Icons.people),
          title: Text("Title - "),
          subtitle: Text("Subtitle"),
          trailing: Icon(Icons.delete),
        ),
        Divider(
          height: 0.5,
          thickness: 0.5,
        ),
        ListTile(
          leading: Icon(Icons.people),
          title: Text("Title - "),
          subtitle: Text("Subtitle"),
          trailing: Icon(Icons.delete),
        ),
        Divider(
          height: 0.5,
          thickness: 0.5,
        ),
      ],
    );

ListView.builder

动态创建,视图可见时创建,可以设置行高

return ListView.builder(
        itemExtent: 50, //行高
        itemCount: 100, //item 个数
        itemBuilder: (BuildContext cxt, int index) {
          return Column(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              Text("text:$index"),
              Text("ssss"),
              Divider(
                height: 0.5,
                thickness: 0.5,
                color: Colors.red,
              ),
            ],
          );
        });

ListView.separated

相对于 ListView.builder 多了分割线, 目前看是自动计算行高

return ListView.separated(
        itemBuilder: (BuildContext ct, int index) {
          return ListTile(
            leading: Icon(Icons.people),
            title: Text("Title - $index"),
            subtitle: Text("Subtitle"),
            trailing: Icon(Icons.delete),
            onTap: () {
              print('点击了 - 第$index行');
            },
          );
        },
        // 分割线对象
        separatorBuilder: (BuildContext ct, int index) {
          return Divider(//可以直接 Divider()
            height: 0.5,//分割线占据的高度
            thickness: 0.5,//分割线高度
          );
        },
        itemCount: 100);

GridView

构造方法

GridView.count

和 ListView() 构造方法一样,适合小数量的,一下子全部加载出来

return GridView.count(
      mainAxisSpacing: 8,//主轴间距
      crossAxisSpacing: 8,//交叉轴间距
      primary: false,
      crossAxisCount: 4,//交叉轴 item 个数
      children: [
        Container(
          child: Text("sss"),
          // color: Color.fromRGBO(Random().nextInt(256), Random().nextInt(256),
          // Random().nextInt(256), 1)
          color: Color.fromARGB(Random().nextInt(256), Random().nextInt(256),
              Random().nextInt(256), Random().nextInt(256)),
        ),
        Container(
            child: Text("sss"),
            color: Color.fromRGBO(Random().nextInt(256), Random().nextInt(256),
                Random().nextInt(256), 1)),
        Container(
            child: Text("sss"),
            color: Color.fromRGBO(Random().nextInt(256), Random().nextInt(256),
                Random().nextInt(256), 1)),
        Container(
            child: Text("sss"),
            color: Color.fromRGBO(Random().nextInt(256), Random().nextInt(256),
                Random().nextInt(256), 1)),
        Container(
            child: Text("sss"),
            color: Color.fromRGBO(Random().nextInt(256), Random().nextInt(256),
                Random().nextInt(256), 1)),
        Container(
            child: Text("sss"),
            color: Color.fromRGBO(Random().nextInt(256), Random().nextInt(256),
                Random().nextInt(256), 1)),
      ],
    );

GridView.builder

必须实现 gridDelegate 代理方法,又有两个代理方法可选

固定交叉轴 item 个数

  • SliverGridDelegateWithFixedCrossAxisCount 交叉轴 item 最大宽度
  • SliverGridDelegateWithMaxCrossAxisExtent

return GridView.builder(
        itemCount: 100,

        //交叉轴固定 item 个数
        // gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        //     crossAxisCount: 2, //交叉轴的 item 个数
        //     mainAxisSpacing: 8, //上下
        //     crossAxisSpacing: 8, //左右
        //     childAspectRatio: 1.0),

        //交叉轴 item 最大宽度
        gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
            maxCrossAxisExtent: 100, //交叉轴的item 最大宽度
            mainAxisExtent: 100),
        itemBuilder: (BuildContext cxt, int index) {
          return Container(
            child: Center(
              child: Text("$index"),
            ),
            color: Color.fromARGB(Random().nextInt(256), Random().nextInt(256),
                Random().nextInt(256), Random().nextInt(256)),
          );
        });

Slivers

我们通常把 Slivers 放在一个 CustomScrollView 里面, CustomScrollView有一个属性slivers, 里面放一些 sliver (切片)

Sliver 通常翻译为裂片,薄片,你可以将每一个独立的滚动视图当做一个 sliver 有下面几种 sliver:

  • SliverList: 就是之前使用的 ListView
  • SliverGrad: 就是之前使用的 GridView
  • SliverPadding: 设置 Sliver的内边距, 滚动的时候内边距可以跟着滚动
  • SliverAppBar: 添加一个 AppBar, 通常用来作为 CustomScrollView 的 HeaderView
  • SliverSafeArea: 设置内容显示在安全区域

SliverAppBar

    SliverAppBar(
          pinned: true, // nav 是否固定
          expandedHeight: 200, //最小就是nav 高度44 大的话下拉文字会跟着变大
          flexibleSpace: FlexibleSpaceBar(
            title: Text("Joho - SliverAppBar"),
            background: Image.asset(
              "images/snow.jpeg",
              fit: BoxFit.cover,
            ),
          ),
        ),

SliverList

child: CustomScrollView(
    //slivers == children
    slivers: [ 
       SliverList(
        delegate: SliverChildBuilderDelegate(
         (BuildContext cxt, int index) {
          return ListTile(
           leading: Icon(Icons.people),
           title: Text("联系人: $index"),
          );
         },
         childCount: 100,
        ),
       )
      ],
     ),

SliverGrid

    SliverGrid(
            delegate: SliverChildBuilderDelegate((BuildContext ct, int index){
              return Container(
                color: Color.fromRGBO(Random().nextInt(256),
                    Random().nextInt(256), Random().nextInt(256), 1),
                child: Text("Grid - $index"),
              );}, 
            childCount: 10),
            
            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 2, 
                mainAxisSpacing: 8, 
                crossAxisSpacing: 8
                )
           ),

监听滚动

ScrollController

  • 监听滚动,但不知道何时开始滚动
  • 增加监听:controller.addListener
  • 当前偏移量:controller.offset
  • 回到顶部 _controller.animateTo(0,duration:Duration(seconds:1),curve:Curves.ease);
ScrollController _controller = ScrollController();

 @override
  void initState() {
    super.initState();
    _controller.addListener(() { //添加监听
        print("${_controller.offset}");
    });
  }

CustomScrollView(
        //scrollview 绑定 controller
       controller: _controller,
)
//滚动
_controller.animateTo(0,
                      duration: Duration(seconds: 1), curve: Curves.ease);

NotificationListener

可以监听滚动状态

  • ScrollStartNotification 开始滚动
  • ScrollUpdateNotification 正在滚动
  • ScrollEndNotification 滚动结束

滚动距离

  • 当前滚动距离:notifation.metrics.pixels
  • 总共滚动长度:notifation.metrics.maxScrollExtent
Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Joho'),
        ),
        body: Container(
          child: NotificationListener(
            onNotification: (ScrollNotification notifation) {
              if (notifation is ScrollStartNotification) {
                print("开始滚动...");
              } else if (notifation is ScrollUpdateNotification) {
                print("正在滚动");
                //当前滚动距离
                final currentPixel = notifation.metrics.pixels;
                //最大长度
                final totalPixel = notifation.metrics.maxScrollExtent;
              } else if (notifation is ScrollEndNotification) {
                print("结束滚动...");
              }
              return false;
            },
            child: xxxx,
        }
     )