[- Flutter 基础篇 -] ListView的使用

2020-04-30 15:19:25 浏览数 (1)

1.ListView 的基本使用

ListView 是一个盛放多个孩子的容器。我们从下面的例子开始介入:


1.1:三个构造
  • 使用ListView构造方法

和Flex,Wrap类似,将子元素一个一个按顺序排列。

代码语言:javascript复制
var caverStyle= TextStyle(fontSize: 18, shadows: [//文字样式
  Shadow(
      color: Colors.white, offset: Offset(-0.5, 0.5), blurRadius: 0)
]);
var show = ListView(//ListView的构造方法
  padding: EdgeInsets.all(8.0),//边距
  children: <Widget>[//孩子们
    Container(
      height: 50,
      color: Color(0xffff0000),
      child: Center(child: Text('红色',style: caverStyle,)),
    ),
    Container(
      height: 50,
      color: Color(0xffFFFF00),
      child: Center(child: Text('黄色',style: caverStyle,)),
    ),
    Container(
      height: 50,
      color: Color(0xff00FF00),
      child: Center(child: Text('绿色',style: caverStyle,)),
    ),
    Container(
      height: 50,
      color: Color(0xff0000FF),
      child: Center(child: Text('蓝色',style: caverStyle,)),
    ),
  ],
);

  • 使用ListView.builder方法构造

使用builder方法对List或Map数据进行批量生成。

代码语言:javascript复制
const colorMap = {//数据来源
  0xffff0000: "红色",
  0xffFFFF00: "黄色",
  0xff00FF00: "绿色",
  0xff0000FF: "蓝色",
};
var caverStyle= TextStyle(fontSize: 18, shadows: [//文字样式
  Shadow(
      color: Colors.white, offset: Offset(-0.5, 0.5), blurRadius: 0)
]);
var show = ListView.builder(//使用builder方法进行构造
    padding: EdgeInsets.all(8.0),
    itemCount: colorMap.length,//条目的个数
    itemBuilder: (BuildContext context, int index) {//条目构造器
      return Container(
        height: 50,
        color: Color(colorMap.keys.toList()[index]),
        child: Center(
            child: Text(
          '${colorMap.values.toList()[index]}',
          style: caverStyle,
        )),
      );
    });

  • 使用ListView.separated方法构造

separated方法和builder类似,但是可以通过separatorBuilder属性创建分隔线。

代码语言:javascript复制
const colorMap = {//数据来源
  0xffff0000: "红色",
  0xffFFFF00: "黄色",
  0xff00FF00: "绿色",
  0xff0000FF: "蓝色",
};
var caverStyle = TextStyle(fontSize: 18, shadows: [//文字样式
  Shadow(color: Colors.white, offset: Offset(-0.5, 0.5), blurRadius: 0)
]);
var show = ListView.separated(//使用separated方法进行构造
  padding: EdgeInsets.all(8.0),
    itemBuilder: (context, index) {//条目构造器
      return Container(
        height: 50,
        color: Color(colorMap.keys.toList()[index]),
        child: Center(
            child: Text(
          '${colorMap.values.toList()[index]}',
          style: caverStyle,
        )),
      );
    },
    separatorBuilder: (context, index) {//分隔线构造器
      return Container();
    },
    itemCount: colorMap.length);

2.ListView进阶使用
2.1:完成条目的封装

比较简单,我也不分析这么布局了,直接上代码。

  • 信息描述类
代码语言:javascript复制
class PoemItem {
  ImageProvider image;//图片
  var title;//标题
  var author;//作者
  var summary;//摘要
  PoemItem({this.image, this.title, this.author, this.summary});
}
  • 条目的封装
代码语言:javascript复制
typedef OnItemClickListener = void Function();
class PoemItemView extends StatelessWidget {
  final PoemItem data;
  final OnItemClickListener onItemClickListener;
  PoemItemView({Key key, this.data, this.onItemClickListener})
      : super(key: key);
  @override
  Widget build(BuildContext context) {
    var headIcon = Container(//左边头部
        decoration: BoxDecoration(
          color: Colors.white,
          shape: BoxShape.circle,
          boxShadow: [
            BoxShadow(
              color: Colors.grey.withOpacity(0.3),
              offset: Offset(0.0, 0.0),
              blurRadius: 3.0,
              spreadRadius: 0.0,
            ),
          ],
        ),
        width: 70,
        height: 70,
        child: Padding(
          padding: EdgeInsets.all(3),
          child: CircleAvatar(
            backgroundImage: data.image,
          ),
        ));
    var center = Column(//中间介绍
      mainAxisAlignment: MainAxisAlignment.center,
      crossAxisAlignment: CrossAxisAlignment.start,
      mainAxisSize: MainAxisSize.min,
      children: <Widget>[
        Text(data.title,
            style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
        Padding(
          padding: EdgeInsets.only(top: 8),
          child: Text(
            "作者:${data.author}",
            style: TextStyle(color: Colors.grey, fontSize: 12),
          ),
        ),
      ],
    );
    var summary = Text(//尾部摘要
      data.summary,
      maxLines: 3,
      overflow: TextOverflow.ellipsis,
      style: TextStyle(color: Colors.grey, fontSize: 12),
    );
    var item = Row(//条目拼合
      mainAxisAlignment: MainAxisAlignment.start,
      children: <Widget>[
        SizedBox(width: 10),
        headIcon,
        Padding(
          padding: EdgeInsets.symmetric(horizontal: 20),
          child: center,
        ),
        Expanded(
          child: summary,
        ),
        SizedBox(width: 10),
      ],
    );
    var result = Card(//卡片化 事件监听
        elevation: 5,
        child: InkWell(
            onTap: onItemClickListener,
            child: Padding(
              padding: EdgeInsets.all(10),
              child: item,
            )));
    return result;
  }
}
复制代码
2.2:ListView的使用

在构造器构造条目时,使用数据对条目进行数据填充,侧达到数据展示效果

代码语言:javascript复制
var data = <PoemItem>[];
for (var i = 0; i < 20; i  ) {
  data.add(PoemItem(
      image: AssetImage("images/wy_200x300.jpg"),
      title: "$i:以梦为马",
      author: "海子",
      summary: "我要做远方的忠诚的儿子,和物质的短暂情人,和所有以梦为马的诗人一样,我不得不和烈士和小丑走在同一道路上"));
}
var show = ListView.builder(
    padding: EdgeInsets.all(8.0),
    itemCount: data.length, //条目的个数
    itemBuilder: (BuildContext context, int index) {
      return PoemItemView(//数据填充条目
        data: data[index],
        onItemClickListener: () {//事件响应
          print(index);
        },
      );
    });
复制代码

2.3:分隔线的添加

这里现将Card组件去掉。separated可以很轻松的实现下划线分隔,并且容易改变长短,颜色 如果你愿意,也可以去定义分隔的组件,专门作为分隔线。而且还能使用索引进行个性化设计

代码语言:javascript复制
var data = <PoemItem>[];
for (var i = 0; i < 20; i  ) {
  data.add(PoemItem(
      image: AssetImage("images/wy_200x300.jpg"),
      title: "$i:以梦为马",
      author: "海子",
      summary: "我要做远方的忠诚的儿子,和物质的短暂情人,和所有以梦为马的诗人一样,我不得不和烈士和小丑走在同一道路上"));
}
var show = ListView.separated(
    padding: EdgeInsets.all(8.0),
    itemCount: data.length, //条目的个数
    itemBuilder: (BuildContext context, int index) {
      return PoemItemView(//数据填充条目
        data: data[index],
        onItemClickListener: () {//事件响应
          print(index);
        },
      );
    },
    separatorBuilder: (BuildContext context, int index) {
  return Padding(padding: EdgeInsets.only(left: 90),child: Divider(height: 1,color: Colors.orangeAccent,),);
},
    );
复制代码

2.4:一个ListView中不同的条目样式。

在抽取条目时,可以定义一个type属性,条目样式由Widget自身决定。

代码语言:javascript复制
var random = Random();
var data = <ChartItem>[];
var strs = [
  "我是要成为编程之王的男人,你是要成为编程之王的女人",
  "凭君莫话封侯事,一将功成万骨枯。你觉得如何?",
  "在苍茫的大海上,狂风卷积着乌云,在乌云和大海之间,海燕像黑色的闪电,在高傲的飞翔。"
];
for (var i = 0; i < 20; i  ) {
  data.add(ChartItem(
      headIcon: AssetImage(
          i.isEven ? "images/wy_200x300.jpg" : "images/icon_head.png"),
      text: strs[random.nextInt(strs.length)],
      type: i.isEven ? ChartType.left : ChartType.right));
}
var show = ListView.builder(
  itemCount: data.length, //条目的个数
  itemBuilder: (BuildContext context, int index) {
    return ChartWidget(//数据填充条目
      chartItem: data[index],
    );
  },
);

比如这里的ChartItem,本身定义了ChartType,在实现ChartWidget的时候,根据类型进行生成相应Widget,从而达到多种样式的效果。

代码语言:javascript复制
enum ChartType { right, left }

class ChartItem {
  ImageProvider headIcon;
  double maxWith;
  ChartType type;
  String text;

  ChartItem({this.headIcon, this.text,this.maxWith = 250,this.type=ChartType.right});
}

class ChartWidget extends StatelessWidget {
  final ChartItem chartItem;

  ChartWidget({Key key, this.chartItem}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    switch (chartItem.type) {
      case ChartType.right:
        return _buildRight();
        break;
      case ChartType.left:
        return _buildLeft();
        break;
    }
  }

3.ListView滑动控制器(上拉刷新和下拉更新)
3.1:滑动控制器ScrollController的使用
代码语言:javascript复制
class _ListViewPageState extends State<ListViewPage> {
  ScrollController _scrollController = ScrollController();//定义变量及初始化

  @override
  void initState() {
    super.initState();
    _scrollController.addListener(() {//添加监听
     print("滑动了:${_scrollController.position.pixels},
     离顶部高:${_scrollController.position.maxScrollExtent}");
    });
  }

  @override
  void dispose() {
    _scrollController.dispose();//销毁控制器
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
   //略同...
    var show = ListView.builder(
        controller: _scrollController,  //使用ScrollController
          //略同...
        );
  }
}
复制代码

3.2:上拉刷新

内置组件:RefreshIndicator,包裹一下即可

代码语言:javascript复制
  return RefreshIndicator(child: show, onRefresh: _onRefresh//使用RefreshIndicator
}

bool isLoading = false;
Future<void> _onRefresh() async {//下拉刷新,异步延迟三秒
  if (isLoading) {
    return;
  }
  await Future.delayed(Duration(seconds: 3), () {
    setState(() {
      isLoading = false;
    });
  });
}

3.3:下拉加载更多
代码语言:javascript复制
_scrollController.addListener(() {
  if (_scrollController.position.pixels ==//说明滑到底部
      _scrollController.position.maxScrollExtent) {
    _loadMore();
  }
});

bool isLoaded = false;

Future<void> _loadMore() async {
  await Future.delayed(Duration(seconds: 3), () {
    setState(() {
        isLoaded=true;
    });
  });
}

var show = ListView.builder(
    controller: _scrollController,
    itemCount: data.length   1, //条目的个数
    itemBuilder: (BuildContext context, int index) {
      if (index == data.length) {
        return Offstage(//使用Offstage控制显隐
            offstage: isLoaded,
            child: Padding(
              padding: EdgeInsets.all(8.0),
              child: Center(
                child: CircularProgressIndicator(),
              ),
            ));
      } else {
        return ChartWidget(
          //数据填充条目
          chartItem: data[index],
        );
      }
    });

4. physics属性

physics对应ScrollPhysics类,其下有6个子类

  • FixedExtentScrollPhysics()NeverScrollableScrollPhysics
代码语言:javascript复制
ListView无法滑动

  • PageScrollPhysics()
代码语言:javascript复制
会根据你的滑动来自动调节,比如你滑的距离小,则自动还原,
到达一定大小,也会自动下滑一个条目

  • BouncingScrollPhysics()
代码语言:javascript复制
顶底会有而外空间,让富有弹性

  • ClampingScrollPhysics()AlwaysScrollableScrollPhysics()
代码语言:javascript复制
顶底会有蓝色阴影

另外还有reverse属性控制数据是否反序,scrollDirection控制ListView的方向

0 人点赞