Flutter ListView使用

Flutter 小知识:ListView使用

  • ListView参数介绍
  • ScrollController的使用
  • ListTile
  • ListView全选
  • ListView多选
  • ListView单选
  • ListView优化

灵魂烈焰中死神降临,生命不断流逝,枯萎,只求不要带走那对你最后的一丝思念。——沙漠死神

先来看看今天的最终效果吧:

效果图(1.1):

Flutter ListView使用_第1张图片

咋们先来学习ListView,若果你对ListView比较熟悉,直接跳过这段吧~

ListView参数介绍

加粗是必须传参数

ListView参数 类型 说明
scrollDirection Axis 滑动方向
Axis.vertical(默认)
Axis.horizontal
itemExtent double 表示的是子Widget之间的距离
当scrollDirection = Axis.vertical itemExtent代表的是高度
当scrollDirection = Axis.horizontal itemExtent代表的是宽度
padding EdgeInsetsGeometry 内边距
primary bool 当条目不足时 true可以尝试滚动 false不可以滚动
physics ScrollPhysics 滑动类型
BouncingScrollPhysics() 拉到ListView最底部有回弹效果
ClampingScrollPhysics() 包裹内容不会回弹
NeverScrollableScrollPhysics() 滑动禁止
cacheExtent double 预加载区域
reverse bool 是否倒序显示 默认正序 false 倒序true
controller ScrollController 滑动控制器,监听ListView滑动距离等
children List 子Widget

在来看看代码:

Bean辅助类:

class ListViewBean{
  //是否选中
  bool ischeck = false;
  //标题
  String title;
  ListViewBean(this.ischeck, this.title,);
}

ListViewTextWidget类:



class ListViewTextWidget extends StatefulWidget {
  @override
  _ListViewTextWidgetState createState() => _ListViewTextWidgetState();
}

class _ListViewTextWidgetState extends State<ListViewTextWidget> {
 List<ListViewBean> _list = [];

  @override
  void initState() {
    super.initState();
	 //初始化30个条目
    for (int i = 0; i <= 30; i++) {
      _list.add(new ListViewBean(false, "$i"));
    }
  }
  @override
  Widget build(BuildContext context) {
		return child: Container(
            child: _buildListView(),
          );
	}

	Widget _buildListView() {
		return ListView(
			  //子Widget
      		  children: initData(),
		);
	}
	
	List<Widget> initData() {
	    List<Widget> mlist = [];
	     _list.forEach((e) => {
          mlist.add( buildItem(e) )
        });
   		 return mlist;
	}

 ///[e] 当前的Widget
  Widget buildItem(ListViewBean e) {
    return Container(
      decoration: BoxDecoration(
        border: Border(
          bottom: BorderSide(color: Colors.lightBlueAccent,width: 0.5)
        )
      ),
      alignment: Alignment.center,
      child: Row(
        children: [
          Expanded(
            child: Text("第${e.title}个元素"),
          ),
          RaisedButton(
            color: e.ischeck ? Colors.black : Colors.red,
            onPressed: () {
            },
            child: Text(
              e.ischeck ? "已收藏" : "未收藏",
              style: TextStyle(color: Colors.white),
            ),
          )
        ],
      ),
    );
  }
}

这段代码很简单,在定义一个辅助类,在initState()中初始化30条数据,然后赋值给ListView,来看看效果吧:

效果图(1.2):

来看看内几种滑动效果:

  • ClampingScrollPhysics() 拉到ListView最底部有回弹效果
    效果图(1.3):

  • NeverScrollableScrollPhysics()滑动禁止
    效果图(1.4):
    Flutter ListView使用_第2张图片

  • ClampingScrollPhysics(默认) 包裹内容不会回弹
    效果图(1.5):

ScrollController的使用

 ScrollController scrollController = ScrollController();

 scrollController.addListener(() {
      ///scrollController.position.maxScrollExtent  ListView滑动的最大距离
      ///scrollController.position.pixels  现在滑动的距离
      if (scrollController.position.maxScrollExtent ==
       scrollController.position.pixels) {
        print(scrollController.....maxScrollExtent ..pixels);
      }
    });
    
	  @override
	  void dispose() {
  	 	  scrollController.dispose();
  		  super.dispose();
	  }

  • scrollController.position.maxScrollExtent ListView滑动的最大距离
  • scrollController.position.pixels 现在滑动的距离

这个属性常用于监听ListView是否滑动到最底部,从而加载更多属性.

效果图(1.6):
Flutter ListView使用_第3张图片

其他属性都非常简单,大家自己动手试一下吧~

ListView中还有自带的ListTile

ListTile

ListTile参数 类型 说明
tileColor Color 背景色会把圆角覆盖掉!!
subtitle Widget 副标题
dense bool 将字体缩小
leading Widget 左边图标
trailing Wdiget 末尾图标设置
contentPadding EdgeInsetsGeometry 内边距
title Widget 主标题
onTap GestureTapCallback 单击事件
onLongPress GestureLongPressCallback 长按事件
selected bool 如果选中,则颜色会跟随主题颜色
enabled bool 禁止点击事件
_item("拍照",  "拍照哦"),
_item("从相册选择",  "选取照片哦"),
/**
   *  title 主标题
   *  subTitle 副标题
   */
  _item(String title,  String subTitle) {
    return ListTile(
        tileColor: Colors.teal,//背景色会把圆角覆盖掉!!
        //背景色
        subtitle: Text(subTitle),
        //副标题
        dense: true,
        //将字体缩小
        leading: Icon(Icons.ac_unit_outlined, size: 25,),
        //左边显示图片
        trailing: Icon(Icons.android),
        //末尾显示图片
        contentPadding: EdgeInsets.all(3),
        //内边距 默认16
        title: Text( title,),
        selected: true,//如果选中,则颜色会跟随主题颜色
        enabled: true,//禁止点击事件
      );
  }

效果图(1.7):
Flutter ListView使用_第4张图片

走到这里的话ListView已经了解的差不多了,接下来完成今天的效果吧:

ListView全选

ListViewBean辅助类:

class ListViewBean{
  //是否选中
  bool ischeck = false;
  //标题
  String title;
  ListViewBean(this.ischeck, this.title,);
}

收藏按钮 e为当前点击的Widget

 List<ListViewBean> _list = [];
 
///[e] 为当前点击的Widget
 RaisedButton( color: e.ischeck ? Colors.black : Colors.red,
            onPressed: () {
              setState(() {
                  //全选
                  _list.forEach((element) {
                     e.ischeck = element.ischeck = !element.ischeck;
                  });
              });
            },
            child: Text(
              e.ischeck ? "已收藏" : "未收藏",
              style: TextStyle(color: Colors.white),
            ),
          )

全选最为简单,当点击任意一个的时候,控制所有的按钮,实现颜色的转换.

//循环所有的Widget
 _list.forEach((element) {
 		//  e.ischeck 为当前Widget
 		// element.ischeck 为_list循环的Widget
       e.ischeck = element.ischeck = !element.ischeck;
});

这段代码不理解的记得在评论区留言哦~

效果图(1.7)

Flutter ListView使用_第5张图片

ListView多选

 List<ListViewBean> _list = [];
 
///[e] 为当前点击的Widget
 RaisedButton( color: e.ischeck ? Colors.black : Colors.red,
            onPressed: () {
              setState(() {
                //多选
                  initMultipleChoice(e);
              });
            },
            child: Text(
              e.ischeck ? "已收藏" : "未收藏",
              style: TextStyle(color: Colors.white),
            ),
          )

//用来存储当前点击值
List<String> _lsitcheck = [];

 //多选
  void initMultipleChoice(ListViewBean e) {
    //多选
    if (!e.ischeck) {
      _lsitcheck.add("${e.title}");
    } else {
      _lsitcheck.remove("${e.title}");
    }
    Toast.toast(context, msg: "${_lsitcheck.toString()}");

    e.ischeck = !e.ischeck;
  }

多选也比较好理解,先判断当前是否选中

  • 如果选中的话就添加到_lsitcheck集合里面
  • 如果再点击当前选中的话就从_lsitcheck集合中删除掉在Toast出来即可

这段代码不理解的记得在评论区留言哦~

效果图(1.8)
Flutter ListView使用_第6张图片

ListView单选

代码:

RaisedButton(
            color: e.ischeck ? Colors.black : Colors.red,
            onPressed: () {
              setState(() {
                  //单选
                  initSingleChoice(e);
              });
            },
            child: Text(
              e.ischeck ? "已收藏" : "未收藏",
              style: TextStyle(color: Colors.white),
            ),
          )

 //单选
  void initSingleChoice(ListViewBean e) {
    e.ischeck = !e.ischeck;
    _list.forEach((element) {
      //若当前有选中的按钮
      if (element.ischeck == e.ischeck && e.ischeck == true) {
        //无论有没有选中 都将改成未选中
        element.ischeck = false;
        //选中
        e.ischeck = true;
        Toast.toast(context, msg: e.title);
      }
    });
  }

这段代码相对于这篇文章我觉得是最难的了

   e.ischeck = !e.ischeck;
   _list.forEach((element) {
      //若当前有选中的按钮
      if (element.ischeck == e.ischeck && e.ischeck == true) {
        //无论有没有选中 都将改成未选中
        element.ischeck = false;
        //选中
        e.ischeck = true;
        Toast.toast(context, msg: e.title);
      }

如果当前有选中的

则将选中的都改成未选中的(element.ischeck = false;)

然后在设置当前选中的(e.ischeck = true;)

这段话太绕口了,我给大家举一个例子:

如果当前选中的为1,3,6,那么循环的时候,第1,3,6个元素就会走到if()

if (element.ischeck == e.ischeck && e.ischeck == true) {
        //无论有没有选中 都将改成未选中
        element.ischeck = false;
        //选中
        e.ischeck = true;
        Toast.toast(context, msg: e.title);
      }

方法里面,将当前的1,3,6号都设置为false, 当前界面上都是未选中,之后在将当前点击的设置为false这样的话就达到了一个单选的效果.


要想看这是为什么我把这两行代码注释掉线看看这样的效果:

   e.ischeck = !e.ischeck;
   _list.forEach((element) {
      //若当前有选中的按钮
      if (element.ischeck == e.ischeck && e.ischeck == true) {
        //无论有没有选中 都将改成未选中
        //element.ischeck = false;
        //选中
       // e.ischeck = true;
        Toast.toast(context, msg: e.title);
      }

效果图(1.9):
Flutter ListView使用_第7张图片

好了,走到这里今天的效果就完成了~

最后再把ListView优化一下

ListView优化

使用场景,当网络请求特别多的时候,优化的话会提高用户使用体验

ListView优化效果:

效果图(1.10):

当前有100条数据,当用户滑动时,显示的是loading

代码:


 bool isLoadingImage = true; //是否滑动
 
NotificationListener(
          child: Container(
            child: ListView(
            .....
            ),
          ),
          onNotification: (notification) {
            ///通知类型
            switch (notification.runtimeType) {
              case ScrollStartNotification:
                print("开始滚动");
                ///在这里更新标识 刷新页面 不加载图片
                isLoadingImage = false;
                break;
              case ScrollUpdateNotification:
                print("正在滚动");
                break;
              case ScrollEndNotification:
                print("滚动停止");

                ///在这里更新标识 刷新页面 加载图片
                setState(() {
                  isLoadingImage = true;
                });
                break;
              case OverscrollNotification:
                print("滚动到边界");
                break;
            }
            return true;
          },
        )

isLoadingImage这个变量就是当前是否在滑动

在ListView设置数据时判断显示的布局:

ListView(
 children: initData(),
)

 List<Widget> initData() {
    List<Widget> mlist = [];

    mlist.add(initButton("单选", 1));
    mlist.add(initButton("多选", 2));
    mlist.add(initButton("全选", 3));

    _list.forEach((e) => {
          mlist.add(
            isLoadingImage
                ? buildItem(e)//显示正常展示布局
                :
                //滑动时显示的LoadingUtil
                Container(
                    alignment: Alignment.center,
                    child: LoadingUtil.loading(context),
                  ),
          )
        });
    return mlist;
  }

这里还是比较简单的,使用NotificationListener对ListView滑动监听,然后通过判断现在是否滑动,设置对应的布局

完整项目

ListView完整代码

loadUtil辅助类

Toast辅助类

这一篇写的有点长了,如果您看到这里,麻烦给点个赞呗,您的点赞就是对我最大的支持,留下您的点赞吧~

Flutter ListView使用_第8张图片

你可能感兴趣的:(Flutter,flutter,listview,dart,listview优化,单选,多选,全选)