美文网首页
Flutter入门05 -- 滚动组件

Flutter入门05 -- 滚动组件

作者: zyc_在路上 | 来源:发表于2022-01-18 11:28 被阅读0次
  • 滚动组件有ListViewGridViewSliver

ListView

  • ListView创建的方式通常有三种,分别为ListView()ListView.builder()ListView.separated()
ListView创建方式
  • 第一种方式:ListView()
  • 案例代码:
import 'package:flutter/material.dart';

void main() => runApp(SFMyApp());

class SFMyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: SFHomePage());
  }
}

class SFHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text("基础widget")), body: SFHomeContent());
  }
}

class SFHomeContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView(
      scrollDirection: Axis.vertical,
      itemExtent: 100,//设置Item的高度
      children: List.generate(100, (index) {
        return ListTile(
          leading: Icon(Icons.people),
          trailing: Icon(Icons.delete),
          title: Text("联系人${index+1}"),
          subtitle: Text("联系人电话号码:19991604555"),
        );
      }),
    );
  }
}
  • ListTile组件就是ListView的Item;
  • itemExtent:设置Item的高度;
  • 效果图如下:
image.png
  • 通过ListView()创建,会一次性创建100个Item,这样性能比较差,其适用于Item个数确定,且数量较少的情况下才会采用;

  • 第二种方式:ListView.builder()

  • ListView.builder()不会一次性创建所有Item,而是需要展示的Item才会去创建,性能较好;

  • 案例代码如下:

class SFHomeContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView.builder(
        itemCount: 100,
        itemExtent: 50,
        itemBuilder: (BuildContext ctx, int index){
          return Text("Hello World!!! ${index}",style: TextStyle(fontSize: 20),);
    }
    );
  }
}
  • 第三种方式: ListView.separated()
  • 案例代码如下:
class SFHomeContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView.separated(
        itemBuilder: (BuildContext ctx, int index){
          return Text("Hello World!!! ${index}",style: TextStyle(fontSize: 20),);
        },
        //分割线
        separatorBuilder: (BuildContext ctx,int index){
          return Divider(color: Colors.red,indent: 20,endIndent: 20,thickness: 5);
        },
        itemCount: 100
    );
  }
}
  • itemBuilder:创建Item;
  • separatorBuilder:创建分割线;

GridView

  • GridView的创建方式有:GridView()GridView.builder()
  • 案例代码一:GridView()+ SliverGridDelegateWithFixedCrossAxisCount
class SFHomeContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GridView(
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 3,
        childAspectRatio: 1.5,
        crossAxisSpacing: 8,
        mainAxisSpacing: 8
      ),
      children:
        List.generate(100, (index) {
           return Container(
             color: Color.fromARGB(255, Random().nextInt(256), Random().nextInt(256), Random().nextInt(256)),
           );
        }),
    );
  }
}
  • SliverGridDelegateWithFixedCrossAxisCount:交叉轴方向上item数量固定,其宽度根据屏幕的宽度与item的数量进行计算;

    • crossAxisCount:item的个数;
    • childAspectRatio:item的宽高比;
    • crossAxisSpacing:交叉轴方向上 item之间的间距;
    • mainAxisSpacing:主轴方向上 item之间的间距;
  • 案例代码二:GridView()+ SliverGridDelegateWithMaxCrossAxisExtent

class SFHomeContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GridView(
      gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
        maxCrossAxisExtent: 220,
        crossAxisSpacing: 8,
        mainAxisSpacing: 8,
        childAspectRatio: 1.5
      ),
      children: List.generate(100, (index) {
        return Container(
          color: Color.fromARGB(255, Random().nextInt(256), Random().nextInt(256),Random().nextInt(256)),
        );
      })
    );
  }
}
  • SliverGridDelegateWithMaxCrossAxisExtent:交叉轴方向上的设置item宽度,个数不固定;

    • maxCrossAxisExtent:item的最大宽度;
  • 案例代码三:GridView.builder() + SliverGridDelegateWithFixedCrossAxisCount

class SFHomeContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GridView.builder(
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 3,
          crossAxisSpacing: 8,
          mainAxisSpacing: 8
        ),
        itemBuilder: (BuildContext ctx,int index){
          return Container(
            color: Color.fromARGB(255, Random().nextInt(256), Random().nextInt(256),Random().nextInt(256)),
          );
        }
    );
  }
}

Slivers -- CustomScrollView

  • CustomScrollView:自定义滚动组件,需要传入Slivers即Sliver数组,我们知道ListViewGridView都是继承自BoxScrollView,而BoxScrollView是一个抽象类,从源码来看ListViewGridView在察创建的过程中都需要执行buildSlivers方法,其内部调用buildChildLayout方法,这是一个抽象方法,分别由ListViewGridView来实现,最终提供一个Sliver数组,其中ListView提供的Sliver为SliverFixedExtentList或者是SliverListGridView提供的Sliver为SliverGrid

  • 案例代码:单个Sliver

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

void main() => runApp(SFMyApp());

class SFMyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: SFHomePage());
  }
}

class SFHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text("基础widget")),
        body: SFHomeContent());
  }
}

class SFHomeContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return SliverDemo1();
  }
}

class SliverDemo1 extends StatelessWidget {
  const SliverDemo1({
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return CustomScrollView(
      slivers: [
        SliverSafeArea(
          sliver: SliverPadding(
            padding: EdgeInsets.all(8),
            sliver: SliverGrid(
              gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 2,
                crossAxisSpacing: 8,
                mainAxisSpacing: 8,
                childAspectRatio: 1.5
              ),
              delegate: SliverChildBuilderDelegate(
                  (BuildContext ctx,int index){
                    return Container(
                      color: Color.fromARGB(255, Random().nextInt(256), Random().nextInt(256),Random().nextInt(256)),
                    );
                  },
                childCount: 100
              ),
            ),
          ),
        )
      ],
    );
  }
}
  • 自定义CustomScrollView,需传入Slivers数组,这里传入的Sliver为SliverGrid

  • 参数gridDelegate:是提供布局信息;

  • 参数delegate:是提供item组件,类型为SliverChildDelegate

  • SliverChildDelegate是抽象类,其作用是用来创建滚动组件的item,其有两个子类分别为SliverChildListDelegateSliverChildBuilderDelegate

    • SliverChildListDelegate:性能较差,item一次性创建所有;
    • SliverChildBuilderDelegate:性能较好,创建需要展示的item;
  • SafeAreaSliverSafeArea的区别:

    • SafeArea:安全区域,让目标组件在安全区域内显示;
    • SliverSafeArea:给Sliver设置安全区域,且在滚动时可以在非安全区域内滚动,而SafeArea不可以;
  • SliverPadding:是Sliver自己的设置内边距的组件;

  • 案例代码:多个Sliver

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

void main() => runApp(SFMyApp());

class SFMyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: SFHomePage());
  }
}

class SFHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        // appBar: AppBar(title: Text("基础widget")),
        body: SFHomeContent());
  }
}

class SFHomeContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return CustomScrollView(
      slivers: [
        SliverAppBar(
          pinned: true,
          expandedHeight: 200,
          flexibleSpace: FlexibleSpaceBar(
            title: Text("Hello World!!",style: TextStyle(fontSize: 25),),
          ),
        ),
        SliverGrid(
          gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
              crossAxisCount: 2,
              crossAxisSpacing: 8,
              mainAxisSpacing: 8,
              childAspectRatio: 2.5
          ),
            delegate: SliverChildBuilderDelegate(
                    (BuildContext ctx,int index){
                  return Container(
                    color: Color.fromARGB(255, Random().nextInt(256), Random().nextInt(256),Random().nextInt(256)),
                  );
                },
                childCount: 10
            ),
        ),
        SliverList(
          delegate: SliverChildBuilderDelegate(
              (BuildContext ctx,int index){
                return ListTile(
                  leading: Icon(Icons.people),
                  title: Text("联系人$index"),
                );
              },
            childCount: 20
          ),
        )
      ],
    );
  }
}
  • slivers数组中传入了SliverAppBarSliverGridSliverList三种类型的Sliver,效果如下:
    image.png

滚动组件的监听

  • 滚动组件的监听通常有两种方式,分别为controllerNotificationListener
controller监听
  • 可以设置默认值offset;
  • 监听滚动,也可以监听滚动的位置;
  • 案例代码:
import 'package:flutter/material.dart';

void main() => runApp(SFMyApp());

class SFMyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: SFHomePage());
  }
}

class SFHomePage extends StatefulWidget {
  @override
  _SFHomePageState createState() => _SFHomePageState();
}

class _SFHomePageState extends State<SFHomePage> {
  ScrollController controller = ScrollController(initialScrollOffset: 300);
  bool isShowFloatButton = false;

  @override
  void initState() {
    super.initState();
    controller.addListener(() {
      print("监听到滚动: ${controller.offset}");
      setState(() {
        isShowFloatButton = controller.offset >= 1000;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("基础widget")),
      body: SFHomeContent(controller),
      floatingActionButton: isShowFloatButton ? FloatingActionButton(
        child: Icon(Icons.arrow_upward),
        onPressed: (){
          controller.animateTo(0, duration: Duration(seconds: 1), curve: Curves.easeIn);
        },
      ) : null,
    );
  }
}

class SFHomeContent extends StatelessWidget {
  final ScrollController controller;
  SFHomeContent(this.controller);

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      controller: controller,
      itemBuilder: (BuildContext ctx, int index) {
        return ListTile(
          leading: Icon(Icons.people),
          title: Text("联系人$index"),
        );
      },
      itemCount: 100,
    );
  }
}
  • 右下角悬浮按钮,当前滚动偏移量>=1000时显示;
NotificationListener监听
  • 案例代码:
import 'package:flutter/material.dart';

void main() => runApp(SFMyApp());

class SFMyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: SFHomePage());
  }
}

class SFHomePage extends StatefulWidget {
  @override
  _SFHomePageState createState() => _SFHomePageState();
}

class _SFHomePageState extends State<SFHomePage> {
  bool isShowFloatButton = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("基础widget")),
      body: SFHomeContent(),
      floatingActionButton: isShowFloatButton
          ? FloatingActionButton(
              child: Icon(Icons.arrow_upward),
              onPressed: () {

              },
            )
          : null,
    );
  }
}

class SFHomeContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return NotificationListener(
      onNotification: (ScrollNotification notification){
        if(notification is ScrollStartNotification){
          print("开始滚动");
        }else if (notification is ScrollUpdateNotification){
          print("正在滚动 -- 总区域:${notification.metrics.maxScrollExtent} 当前位置: ${notification.metrics.pixels}");
        }else if (notification is ScrollEndNotification){
          print("结束滚动");

        }

        return true;
      },
      child: ListView.builder(
        itemBuilder: (BuildContext ctx, int index) {
          return ListTile(
            leading: Icon(Icons.people),
            title: Text("联系人$index"),
          );
        },
        itemCount: 100,
      ),
    );
  }
}

相关文章

网友评论

      本文标题:Flutter入门05 -- 滚动组件

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