当前位置: 首页 > wzjs >正文

佛山大良网站建设招聘河南省建筑网官网

佛山大良网站建设招聘,河南省建筑网官网,丽江市建设局官方网站,做网站时怎样申请域名目录 前言:一、实现复杂的ListView列表:1.1 Item布局封装1.2 ListView的使用1.3 增加分割线 二、实现ListView下拉刷新:三、实现上拉加载更多:四、实现下拉刷新、上拉加载更多:五、ListView滚动方向和控制:…

目录

  • 前言:
  • 一、实现复杂的ListView列表:
    • 1.1 Item布局封装
    • 1.2 ListView的使用
    • 1.3 增加分割线
  • 二、实现ListView下拉刷新:
  • 三、实现上拉加载更多:
  • 四、实现下拉刷新、上拉加载更多:
  • 五、ListView滚动方向和控制:
  • 六、总结:

前言:

上一篇文章介绍了,Flutter学习 滚动组件(1):ListView基本使用介绍了ListView基本使用,这篇文章介绍一下进阶使用的方法。

一、实现复杂的ListView列表:

先看效果图:
效果图

1.1 Item布局封装

// list item
class ListItem {ImageProvider image; // 图片var title; // 标题var author; // 作者var summary; // 摘要ListItem({required this.image, this.title, this.author, this.summary});
}// list item界面实现
typedef OnItemClickListener = void Function();class ListItemView extends StatelessWidget {final ListItem data;final OnItemClickListener onItemClickListener;const ListItemView({required Key key, required this.data, required this.onItemClickListener}): super(key: key);Widget build(BuildContext context) {var headIcon = Container(// 左边头部decoration: BoxDecoration(color: Colors.white,shape: BoxShape.circle,boxShadow: [BoxShadow(color: Colors.grey.withOpacity(0.3),offset: const Offset(0.0, 0.0),blurRadius: 3.0,spreadRadius: 0.0,),],),width: 70,height: 70,child: Padding(padding: const EdgeInsets.all(3),child: CircleAvatar(backgroundImage: data.image,),));var center = Column(// 中间介绍mainAxisAlignment: MainAxisAlignment.center,crossAxisAlignment: CrossAxisAlignment.start,mainAxisSize: MainAxisSize.min,children: [Text(data.title,style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),Padding(padding: const EdgeInsets.only(top: 8),child: Text("作者:${data.author}",style: const TextStyle(color: Colors.grey, fontSize: 12),),),],);var summary = Text(// 尾部摘要data.summary,maxLines: 3,overflow: TextOverflow.ellipsis,style: const TextStyle(color: Colors.grey, fontSize: 12),);var item = Row(// 条目拼合mainAxisAlignment: MainAxisAlignment.start,children: [const SizedBox(width: 10),headIcon,Padding(padding: const EdgeInsets.symmetric(horizontal: 20),child: center,),Expanded(child: summary,),const SizedBox(width: 10),],);var result = Card(// 卡片化+事件监听elevation: 5,child: InkWell(onTap: onItemClickListener,child: Padding(padding: const EdgeInsets.all(10),child: item,)));return result;}
}

1.2 ListView的使用

Widget showListView() {var data = [];for (var i = 0; i < 20; i++) {data.add(ListItem(image: const AssetImage("assets/images/android_fly.webp"),title: "$i:指鹿为马",author: "ddup",summary: "公元前210年,秦始皇病死,担任中车府令(掌管皇帝车马)的宦官赵高,不愿让秦始皇的大儿子扶苏继承皇位,而想让秦始皇的小儿子胡亥当皇帝。"));}return ListView.builder(padding: const EdgeInsets.all(8.0),itemCount: data.length, //条目的个数itemBuilder: (BuildContext context, int index) {return ListItemView(//数据填充条目data: data[index],onItemClickListener: () {//事件响应print(index);},key: UniqueKey());});
}class MyApp extends StatelessWidget {final List<String> items;const MyApp({super.key, required this.items});// This widget is the root of your application.Widget build(BuildContext context) {const title = 'ListView的使用';return MaterialApp(debugShowCheckedModeBanner: false,title: title,theme: ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),useMaterial3: true,),home: Scaffold(appBar: AppBar(title: const Text(title),),body:MyHomeBody(),));}
}class MyHomeBody extends StatelessWidget {List<String> list = [];MyHomeBody({super.key}) {}Widget build(BuildContext context) {return showListView();}
}

1.3 增加分割线

// 显示自定义ListView
Widget showListView() {var data = [];for (var i = 0; i < 20; i++) {data.add(ListItem(image: const AssetImage("assets/images/android_fly.webp"),title: "$i:指鹿为马",author: "ddup",summary: "公元前210年,秦始皇病死,担任中车府令(掌管皇帝车马)的宦官赵高,不愿让秦始皇的大儿子扶苏继承皇位,而想让秦始皇的小儿子胡亥当皇帝。"));}return ListView.separated(padding: const EdgeInsets.all(8.0),itemCount: data.length, // 条目的个数itemBuilder: (BuildContext context, int index) {return ListItemView(// 数据填充条目data: data[index],onItemClickListener: () {// 事件响应print(index);},key: UniqueKey(),);},separatorBuilder: (BuildContext context, int index) {return const Padding(padding: EdgeInsets.only(left: 90),child: Divider(height: 1,color: Colors.blue,),);},);
}

效果如下:
增加分割线

二、实现ListView下拉刷新:

RefreshIndicator是Flutter用于实现下拉刷新的功能组件,RefreshIndicator可以包裹一个可以滚动的组件,如ListView、GridView,下拉到顶部时会触发刷新操作,调用onRefresh方法,这方法返回一个Future 的异步函数,用于执行刷新操作。RefreshIndicator常见属性如下:

  • onRefresh: 必须实现的回调函数,执行刷新时的操作。
  • child: 需要包裹的可滚动子组件。
  • color:刷新指示器的进度条颜色。
  • backgroundColor: 刷新指示器的背景色。
  • displacement:指示器开始显示时与顶部的距离。

示例如下:

class MyRefreshableList extends StatefulWidget {const MyRefreshableList({super.key});// ignore: library_private_types_in_public_api_MyRefreshableListState createState() => _MyRefreshableListState();
}class _MyRefreshableListState extends State<MyRefreshableList> {final List<String> items = List.generate(5, (i) => 'Item ${i + 1}');Future<void> _onRefresh() async {await Future.delayed(const Duration(seconds: 2)); // 模拟网络请求// 更新数据setState(() {items.addAll(List.generate(10, (i) => 'New item ${i + items.length + 1}'));});}Widget build(BuildContext context) {return RefreshIndicator(onRefresh: _onRefresh,child: ListView.builder(itemCount: items.length,itemBuilder: (context, index) {return ListTile(title: Text(items[index]));},),);}
}class MyHomeBody extends StatelessWidget {MyHomeBody({super.key}) {}Widget build(BuildContext context) {return MyRefreshableList();}
}
class MyApp extends StatelessWidget {final List<String> items;const MyApp({super.key, required this.items});// This widget is the root of your application.Widget build(BuildContext context) {const title = 'ListView的使用';return MaterialApp(debugShowCheckedModeBanner: false,title: title,theme: ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),useMaterial3: true,),home: Scaffold(appBar: AppBar(title: const Text(title),),body:MyHomeBody(),));}
}

这个例子是在下拉刷新onRefresh回调中,模拟了一个2s延时的网络请求,增加了10个新的item条目。
效果如下:
下拉刷新


三、实现上拉加载更多:

上拉加载更多功能可以利用ScrollController判断是否滚动到底部,执行loadmore实现上拉加载更多功能:

class _MyLoadMoreListState extends State<MyLoadMoreList> {final List<String> items = List.generate(20, (i) => 'Item ${i + 1}');final ScrollController _scrollController = ScrollController();bool isLoadingMore = false;void initState() {super.initState();_scrollController.addListener(() {// 滑动到底部时触发加载更多(gif加载动画)if (_scrollController.position.pixels == // scrollController.position.pixels:表示当前滚动的位置_scrollController.position.maxScrollExtent) { // scrollController.position.maxScrollExtent:表示可滚动区域的最大值_loadMore();}});}// 回调函数,执行刷新时的操作Future<void> _loadMore() async {if (!isLoadingMore) {setState(() => isLoadingMore = true);// 模拟网络请求结束后加载更多数据await Future.delayed(const Duration(seconds: 2)); // 模拟网络请求延迟setState(() {// 刷新操作:在底部增加10个itemitems.addAll(List.generate(10, (i) => 'New item ${items.length + i + 1}'));isLoadingMore = false;});}}// dispose字段主要用于在异步操作完成后,确保不会调用已经被销毁的State对象的setState方法void dispose() {_scrollController.dispose(); // 不要忘记在dispose方法中清理控制器super.dispose();}Widget build(BuildContext context) {return ListView.builder(controller: _scrollController,itemCount: items.length + 1, // 添加一个进度指示器作为最后一项itemBuilder: (context, index) {if (index == items.length) { // 最后一项作为进度指示器return Visibility(visible: isLoadingMore,child: const Center(child: CircularProgressIndicator(),),);}return ListTile(title: Text(items[index]));},);}
}

上述代码可以看到,我们在initState方法,增加ListView滚动监听,position.pixels == position.maxScrollExtent执行onLoadMore方法,增加一个isLoadingMore变量来控制重复刷新state,另外我们把loading条放在ListView最后一个条目加1,这样不会遮挡ListView条目,最后通过Visibility来控制loading条的显隐。最后需要注意的一点是,我们在dispose方法时,调用_scrollController.dispose()。
效果图如下:
上拉加载更多

四、实现下拉刷新、上拉加载更多:

我们把下拉刷新和上拉加载结合一起实现:

class PullToRefreshAndLoadMore extends StatefulWidget {const PullToRefreshAndLoadMore({super.key});// ignore: library_private_types_in_public_api_PullToRefreshAndLoadMoreState createState() =>_PullToRefreshAndLoadMoreState();
}class _PullToRefreshAndLoadMoreState extends State<PullToRefreshAndLoadMore> {final List<String> _items = List.generate(20, (i) => 'Item ${i + 1}');final ScrollController _scrollController = ScrollController();bool _isLoadingMore = false;bool _hasMore = true; // 表示是否还有更多数据可加载void initState() {super.initState();_scrollController.addListener(_onScroll);}Future<void> _onRefresh() async {await Future.delayed(const Duration(seconds: 2));setState(() {_items.clear();_items.addAll(List.generate(20, (i) => 'Refreshed item ${i + 1}'));});}void _onScroll() {// 检测是否滚动到底部if (_scrollController.position.pixels >= // scrollController.position.maxScrollExtent:表示可滚动区域的最大值_scrollController.position.maxScrollExtent && // scrollController.position.maxScrollExtent:表示可滚动区域的最大值!_isLoadingMore &&_hasMore) {_loadMore();}}Future<void> _loadMore() async {if (_isLoadingMore) return; // 如果已经在加载,则不执行后续操作setState(() {_isLoadingMore = true;});await Future.delayed(const Duration(seconds: 2));if (mounted) {setState(() {_items.addAll(List.generate(10, (i) => 'New item ${_items.length + i + 1}'));// 假设每次增加了10个数据,加载了5次后认为没有更多数据if (_items.length >= 70) {_hasMore = false;}_isLoadingMore = false;});}}// dispose字段主要用于在异步操作完成后,确保不会调用已经被销毁的State对象的setState方法void dispose() {_scrollController.removeListener(_onScroll); // 移除滚动监听_scrollController.dispose(); // 清理控制器资源super.dispose();}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Pull to Refresh & Load More'),),body: RefreshIndicator(onRefresh: _onRefresh,child: ListView.builder(controller: _scrollController,itemCount: _hasMore? _items.length + 1: _items.length, // 如果还有更多数据,添加额外一项来显示加载指示器itemBuilder: (context, index) {if (index == _items.length && _hasMore) { // 最后一项为加载进度指示器return const Center(child: Padding(padding: EdgeInsets.all(8.0),child: CircularProgressIndicator(),),);}return ListTile(title: Text(_items[index]));},),),);}
}

上述示例,_loadMore会在滚动到底部时才会触发,并用setState来管理状态变化,并且通过_isLoadingMore来防止重复加载操作,以及用_hasMore判断是否还有更多数据需要加载,需要注意的是mounted检查以确保不会在Widget树移除后调用setState方法。

五、ListView滚动方向和控制:

ListView有两种滚动方向,垂直(默认)和水平,我们可以通过修改scrollDirection属性来控制滚动方向:

ListView.builder(scrollDirection: Axis.horizontal,// ...
)

我们将scrollDirection属性设置为Axis.horizontal,创建一个水平滚动的ListView。
如何滚动指定position?看下面例子:

class ScrollToPositionPage extends StatefulWidget {const ScrollToPositionPage({super.key});// ignore: library_private_types_in_public_api_ScrollToPositionPageState createState() => _ScrollToPositionPageState();
}class _ScrollToPositionPageState extends State<ScrollToPositionPage> {final ScrollController _scrollController = ScrollController();final List<String> items = List.generate(100, (i) => 'Item $i');void dispose() {_scrollController.dispose();super.dispose();}void _scrollToIndex(int index) {// 滚动到指定索引的位置_scrollController.animateTo(_scrollController.positions.first.maxScrollExtent * (index / items.length),duration: const Duration(milliseconds: 300),curve: Curves.easeOut,);}Widget build(BuildContext context) {return Scaffold(body: ListView.builder(controller: _scrollController,itemCount: items.length,itemBuilder: (context, index) {return ListTile(title: Text(items[index]),);},),floatingActionButton: FloatingActionButton(onPressed: () => _scrollToIndex(15), // 假设我们想要滚动到第16个元素的位置child: const Icon(Icons.arrow_downward),),);}
}

我们可以看到,上述例子利用ScrollController执行animateTo动画,根据_scrollController.positions.first.maxScrollExtent * (index / items.length)计算,滚动指定position位置。
效果图如下:
滚动方向和控制

六、总结:

我们通过定义一个复杂的ListView布局和增加分割线,以及增加下拉刷新、上拉加载、修改ListView滚动方向,滚动到指定位置来介绍了一下ListView进阶使用,希望大家可以通过这些例子,更好的掌握ListView.

Thanks:
Flutter可滚动组件(3):ListView进阶使用


文章转载自:

http://bnIxwRIQ.qbjgw.cn
http://147qbOBY.qbjgw.cn
http://DEeTqRsm.qbjgw.cn
http://smL9U8JN.qbjgw.cn
http://e1RqdCYk.qbjgw.cn
http://zYpbsoGE.qbjgw.cn
http://e5NcrvZq.qbjgw.cn
http://q7plDvGz.qbjgw.cn
http://uRPhFkOD.qbjgw.cn
http://hZPah9ws.qbjgw.cn
http://ZxOkJMNF.qbjgw.cn
http://9No5Mvbu.qbjgw.cn
http://oarD2nXV.qbjgw.cn
http://ZCfxjako.qbjgw.cn
http://j0YIS3wW.qbjgw.cn
http://W3R2NOLO.qbjgw.cn
http://8sWfUBgf.qbjgw.cn
http://FTPjPTvV.qbjgw.cn
http://aDEUI2bV.qbjgw.cn
http://bzTOgSap.qbjgw.cn
http://V30ndQtN.qbjgw.cn
http://mAyXEkiH.qbjgw.cn
http://bttWE3zK.qbjgw.cn
http://6Ghrb6yv.qbjgw.cn
http://PFB77spt.qbjgw.cn
http://bFL4u6pf.qbjgw.cn
http://3wXA4ATO.qbjgw.cn
http://qWmxaRzT.qbjgw.cn
http://WvEbhBua.qbjgw.cn
http://alpfIcEm.qbjgw.cn
http://www.dtcms.com/wzjs/720952.html

相关文章:

  • 重庆夹夹虫网络公司网站建设贵州网站制作公司
  • 苏州网站建设公司鹅鹅鹅数字媒体艺术设计主要学什么
  • 如何建自己网站做淘宝客网站的建设费用预算
  • 网站建设与网页设计 视频教程厂家招商网
  • 网站文字规范鹰潭市网站建设公司
  • 男女做某事网站网页设计好的网站
  • 阿里云服务器上如何做网站做网站收款支付宝接口
  • 企业备案增加网站背景图在线制作
  • 兰州做网站价格百度网址安全中心怎么关闭
  • 网站服务器端口号是什么网络营销的模式有哪些
  • 毕业设计代做网站多少钱百度seo多久能优化关键词
  • 内部网站搭建网站运维是做什么的
  • 网站模糊效果咨询学校网站开发费用
  • 网站全屏图片怎么做电子商务网站设计与规划
  • 贸易网站设计丝绸之路网站平台建设
  • 招投标网站建设自己做的网站怎么上传到域名
  • 临沂做拼多多网站佛山搜索seo优化排名
  • 在什么网站可以自承包活来做设计方案表网站名称
  • 网站建设管理员工工资多少网站建设公司的名字
  • 备案不关闭网站的方法织梦网站系统删除
  • 企业建站公司哪里有一般网站尺寸
  • 网页制作基础教程图片合肥全网优化
  • 建设一个人才网站需要的人才林壑地板北京网站建设
  • 小蘑菇网站建设下载教育类网站前置审批系统 用户登录
  • 陕西省两学一做网站成立公司合作协议书范本
  • 免费网站seo优化数字营销seo
  • 微信的微网站模板下载不了安徽最新消息今天
  • 网站建设分金手指科捷11wordpress未收到验证码
  • 辽宁省城乡与住房建设厅网站软件开发工具的基本功能是什么
  • 德州网站建设哪家好网站建设人工智能