ListView 组件

ListView 组件.png
  • ListView: 可含多个子组件,支持按需加载。
  • ScrollController: 用来控制可滚动组件的滚动位置。
  • Scrollbar: 如果要给可滚动组件添加滚动条,只需 Scrollbar 作为其父组件即可。
  • SingleChildScrollView: 只含单个子组件,建议内容超过屏幕不多时使用,因为它不支持基于Sliver按需加载模型。

常用组合布局

  • Row [ Expanded (ListView) ]
  • Column [ Expanded (ListView) ]
//导入Material UI 组件库
import 'package:flutter/material.dart';

//程序入口
void main() {
  runApp(const MaterialApp(
      debugShowCheckedModeBanner: false, home: ListViewWidget()));
}

class SingleChildScrollViewWidget extends StatelessWidget {
  final String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

  const SingleChildScrollViewWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text("SingleChildScrollView"),
        ),
        //Scrollbar 显示滚动条
        body: Scrollbar(
          child: SingleChildScrollView(
            scrollDirection: Axis.horizontal,
            padding: const EdgeInsets.all(16.0),
            child: Center(
              child: Row(
                  children: str
                      .split("")
                      .map((e) => Text(
                            e,
                            textScaleFactor: 2.0,
                          ))
                      .toList()),
            ),
          ),
        ));
  }
}

class ListViewWidget extends StatefulWidget {
  const ListViewWidget({Key? key}) : super(key: key);

  @override
  State<StatefulWidget> createState() => _ListViewState();
}

class _ListViewState extends State<ListViewWidget> {
  final List<List> _itemList = const [
    ["上海", "1 上海", Icon(Icons.keyboard)],
    ["天津", "2 天津", Icon(Icons.print)],
    ["北京", "3 北京", Icon(Icons.rocket)],
    ["内蒙", "4 内蒙", Icon(Icons.router)],
    ["黑龙江", "5 黑龙江", Icon(Icons.map)],
    ["江苏省", "6 江苏省", Icon(Icons.person)],
    ["浙江省", "7 浙江省", Icon(Icons.percent)],
    ["安徽省", "8 安徽省", Icon(Icons.add)],
    ["江西省", "9 江西省", Icon(Icons.abc)],
    ["山东省", "10 山东省", Icon(Icons.adjust)],
    ["香港", "11 香港", Icon(Icons.add_card)],
    ["澳门", "12 澳门", Icon(Icons.add_card)],
  ];

  //是否显示"返回到顶部"按钮
  bool showToTopBtn = false;
  final List<Widget> _list = [];
  final ScrollController _controller = ScrollController();

  @override
  void initState() {
    super.initState();
    for (int i = 0; i < _itemList.length; i++) {
      _list.add(_buildListData(
          context, _itemList[i][0], _itemList[i][2], _itemList[i][1]));
    }
    //监听滚动事件,打印滚动位置
    _controller.addListener(() {
      //打印滚动位置
      print("offset: ${_controller.offset}");
      if (_controller.offset < 400 && showToTopBtn) {
        setState(() {
          showToTopBtn = false;
        });
      } else if (_controller.offset >= 400 && showToTopBtn == false) {
        setState(() {
          showToTopBtn = true;
        });
      }
    });
  }

  @override
  void dispose() {
    super.dispose();
    //为了避免内存泄露,需要调用_controller.dispose
    _controller.dispose();
  }

  Widget _buildListData(BuildContext context, String titleItem, Icon iconItem,
      String subTitleItem) {
    return ListTile(
      leading: iconItem,
      title: Text(
        titleItem,
        style: const TextStyle(fontSize: 18.0),
      ),
      subtitle: Text(
        subTitleItem,
      ),
      trailing: const Icon(Icons.keyboard_arrow_right),
      onTap: () {
        showDialog(
          context: context,
          builder: (BuildContext context) {
            return AlertDialog(
              title: const Text(
                'ListViewAlert',
                style: TextStyle(
                  color: Colors.black54,
                  fontSize: 18.0,
                ),
              ),
              content: Text('选择的item内容为: $titleItem'),
            );
          },
        );
      },
    );
  }

  Widget _listView(List<Widget> _list) {
    //需提前构建,适合较少数量已知数据
    return ListView(
      //item反向展示
      reverse: true,
      //滚动方向
      scrollDirection: Axis.vertical,
      //填充内边距
      padding: const EdgeInsets.all(10.0),
      //设置item高度
      itemExtent: 100,
      //设置预加载区域
      cacheExtent: 100,
      //是否根据item长度设置ListView的长度
      shrinkWrap: false,
      children: _list,
    );
  }

  Widget _listViewBuilder() {
    //适合列表项目较多或数量不确定时使用
    return ListView.builder(
      //设置item高度
      itemExtent: 100,
      controller: _controller,
      itemBuilder: (context, index) {
        // return _buildListData(context, _itemList[index][0], _itemList[index][2],
        //     _itemList[index][1]);
        //包装后添加分割线
        return Column(
          children: [
            _buildListData(context, _itemList[index][0], _itemList[index][2],
                _itemList[index][1]),
            //绘制分割线
            const Divider(),
          ],
        );
      },
      itemCount: _itemList.length,
    );
  }

  Widget _listViewSeparated() {
    //包含分割
    return ListView.separated(
      itemBuilder: (context, index) {
        print("index: $index");
        //返回 Widget
        return _buildListData(context, _itemList[index][0], _itemList[index][2],
            _itemList[index][1]);
      },
      separatorBuilder: (BuildContext context, int index) {
        return const Divider();
      },
      //必填参数
      itemCount: _itemList.length,
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('ListView 组件'),
      ),
      body: Scrollbar(
        //child: _listView(_list),
        child: _listViewBuilder(),
        //child: _listViewSeparated(),
      ),
      floatingActionButton: !showToTopBtn
          ? null
          : FloatingActionButton(
              child: const Icon(Icons.arrow_upward),
              onPressed: () {
                //跳转到顶部时执行动画
                _controller.animateTo(
                  .0,
                  duration: const Duration(milliseconds: 200),
                  curve: Curves.ease,
                );
              }),
    );
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容