上期实现了一个网络轮播图的效果,自定义了一个轮播图组件,继承自StatefulWidget,我们知道Flutter中并没有像Android中activity的概念。页面见的跳转是通过路由从一个全屏组件跳转到另外的一个全屏组件,那如果我想在A组件中更新B组件的数据应该怎么实现呢?

今天我们来实现一个支持筛选的列表页面。前面我们已经实现来一个支持下拉刷新和上拉加载更多的列表组件,这里就不在做更多介绍来,效果图如下:



通过点击左滑菜单筛选列表的数据。由于列表在之前的一篇文章已经说明过Flutter学习四之实现一个支持刷新加载的列表,所以这里就直接上列表的代码:我们将列表定义程一个组件,方便,页面引用,列表的请求也放在组件内部。

class ArticleListBaseWidget extends StatefulWidget {
int cid = 0; //文章分类的id
@override
State<StatefulWidget> createState() {
return ArticleListBaseState();
} ArticleListBaseWidget({this.cid});
} class ArticleListBaseState extends State<ArticleListBaseWidget> {
RefreshController refreshController =
RefreshController(initialRefresh: true);
int pageNum = 0;
List<TopArticleBeanData> _articles = []; void onRefresh() {
pageNum = 0;
getArticle(true, getApiName());
} void loadMore() {
pageNum++;
getArticle(false, getApiName());
} //根据cid参数来处理apiName,如果没有传cid参数进来表示不支持分类筛选。
String getApiName() {
String apiName = "";
if (widget.cid > 0) {
apiName = "article/list/$pageNum/json?cid=${widget.cid}";
} else {
apiName = "article/list/$pageNum/json";
}
print("apiName=$apiName");
return apiName;
} ///置顶文章
void getArticle(bool isRefresh, String apiName) async {
///文章接口请求
dio.get(apiName).then((value) {
///文章实体解析
ArticleListEntityEntity articleBeanEntity =
ArticleListEntityEntity().fromJson(jsonDecode(value.toString()));
if (isRefresh) {
_articles = articleBeanEntity.data.datas;
} else {
_articles.addAll(articleBeanEntity.data.datas);
} ///接口调用成功后更新数据需要调用setState()方法
setState(() { }); if (articleBeanEntity.data.datas.length ==0) {
//如果接口没有数据返回
if (isRefresh) {
//如果是下拉刷新的时候并且接口没有返回数据,隐藏列表控件,展示空页面
refreshController.refreshFailed();
} else {
//如果是上啦加载更多并且没有返回数据,就展示列表控件,但是下拉提示没有更多数据了
refreshController.loadNoData();
}
} else {
//如果有数据返回,展示列表控件
if (isRefresh) {
//如果是下拉刷新,并且有数据返回正常展示页面数据
refreshController.refreshCompleted();
} else {
//如果是上啦加载,并且有数据返回正常展示页面数据
refreshController.loadComplete();
}
}
}).catchError((onError) {
if (isRefresh) {
//如果下拉刷新,并且接口出错,展示错误页面
refreshController.refreshFailed();
} else {
//如果上拉加载更多,并且接口出错,展示列表控件,底部下拉位置展示加载失败
refreshController.loadFailed();
}
});
} @override
Widget build(BuildContext context) {
return
SmartRefresher(
controller: refreshController,
enablePullUp: true,
onRefresh: onRefresh,
onLoading: loadMore,
header: WaterDropHeader(),
footer: ClassicFooter(),
child:
ListView.builder(
itemBuilder: (context, index) => ItemPage(_articles[index]),
itemCount: _articles.length)
);
}
}

因为要实现的列表支持筛选项,所以我们这里要在构造方法中接收一个cid参数,用来进行列表筛选的,代码很简单,主要是定义来一个下拉刷新和上拉加载更多要执行的方法,然后在接口返回中针对返回的数据处理来对应的刷新状态,以及对异常的处理,注释已经写的很清楚来。

接下来我们新建一个页面,

 @override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("文章列表")),
endDrawer: drawerSystem(),
body:ArticleListBaseWidget(key:key,cid: cid));
}

这里endDrawer方法是用来添加一个左滑菜单栏的,这里我们用来显示需要筛选的分类数据组件drawerSystem,该组件是由两个联动的列表组成的,同时在构造方法中,传人两个列表的点击时间,方便调用该组件的页面进行数据更新。这里要注意的是获取状态栏的高度和appbar的高度,还有我们要在endDrawer中自定义一个标题栏,但是endDrawer页面默认会有一个距离顶部的空白高度,我们要利用MediaQuery.removePadding方法来去掉顶部留白的部分,然后设置自己定义的标题栏。这里的appbar高度用常量kToolbarHeight来获取,MediaQuery.of(context).padding.top就是状态栏的高度,看到往上很多是直接写死,这样在不同的机型上面展示的效果会不一样的。

具体代码:

 Widget drawerSystem() {
return MediaQuery.removePadding(
context: context,
removeTop: true,
child: Container(
color: Colors.blue,
width: 320,
child: Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Container(
child: Text("体系数据"),
height: kToolbarHeight + MediaQuery.of(context).padding.top,
//appbar高度+状态栏高度
padding: EdgeInsets.only(
top: MediaQuery.of(context).padding.top),
alignment: Alignment.center,
color: Colors.grey[200]),
Expanded(
child: Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
child: Container(
child: ListView.separated(
separatorBuilder: (context, index) {
return Divider(
height: 1, color: Colors.grey[50]);
},
itemBuilder: (context, index) => ItemPageSystem(
screenList[index],
null,
index,
(index) => {onItemClick(index)}),
itemCount: screenList.length),
color: Colors.white)),
Expanded(
child: Container(
child: ListView.separated(
separatorBuilder: (context, index) {
return Divider(
height: 1, color: Colors.white);
},
itemBuilder: (context, index) => ItemPageSystem(
null,
screenChildList[index],
index,
(index) => onItemClickChild(index)),
itemCount: screenChildList.length),
color: Colors.grey[50]))
],
))
],
)));
}

ItemPageSystem是listView每该item的样式,可以自己定义,这里要注意的一下,就是listview item的点击事件,这里为来方便在父组件进行数据的处理,所以是从item组件的构造方法将方法传进去的,

 ItemPageSystem(
this.screenDataBean, this.screenChild, this.index, this.function);

然后就可以在点击事件处理筛选的联动效果了,

 //一级筛选点击事件处理
onItemClick(int index) {
setState(() {
//全局记住点击位置
this.index = index;
//设置二级菜单数据集合
screenChildList = screenList[index].children;
//遍历一级数据设置一级菜单标示,是否选中
updateListSelect(index, screenList);
});
} //二级筛选事件处理
onItemClickChild(int index) {
setState(() {
//全局记住二级菜单点击位置
indexChild = index;
//双层循环遍历清空二级菜单为非选中状态
for (int i = 0; i < screenList.length; i++) {
updateListSelect(-1, screenList[i].children);
}
//设置当前点击数据为选中状态
updateListSelect(index, screenChildList);
cid = screenChildList[index].id;
Navigator.pop(context);//关闭侧边菜单栏
key.currentState.refreshController.requestRefresh();
});
}

到这一步基本已经完成了,我们看下效果发现,点击了筛选后并不能更新列表数据,这是为什么呢,查找了半天不知道问题处在哪里,通过查阅文档发现,如果想在父组件里面更新继承自StatefulWidget的组件的数据,光设置setStat还是不行,因为组件的Key是相同的没有改变,所以要想在父组件更新StatefulWidget组件的数据,需要用到GlobalKey,GlobalKey 能够跨 Widget 访问状态,简单来说就是可以通过GlobalKey来调用子组件的方法或者属性。

具体用法:

//在子组件的构造方法中添加一个Key参数。并且调用super方法返回
ArticleListBaseWidget({Key key,this.cid}):super(key:key); //在父组件中初始化组件,ArticleListBaseState为你要更改状态的子组件
final GlobalKey<ArticleListBaseState> key = GlobalKey<ArticleListBaseState>(); //在父组件中初始化子组件的位置,将GlobalKey对象传回到子组件
ArticleListBaseWidget(key:key,cid: cid)); //父组件中,在你需要更新子组件的位置利用GlobalKey对象调用子组件的方法
key.currentState.refreshController.requestRefresh();

在此运行发现,可以通过筛选条件来更新列表了。

Flutter学习六之实现一个带筛选的列表页面的更多相关文章

  1. Flutter学习四之实现一个支持刷新加载的列表

    上一篇文章用Scaffold widget搭建了一个带底部导航栏的的项目架构,这篇文章就来介绍一下在flutter中怎么实现一个带下拉刷新和上拉加载更多的一个列表,这里用到了pull_to_refre ...

  2. Unity3D学习笔记2——绘制一个带纹理的面

    目录 1. 概述 2. 详论 2.1. 网格(Mesh) 2.1.1. 顶点 2.1.2. 顶点索引 2.2. 材质(Material) 2.2.1. 创建材质 2.2.2. 使用材质 2.3. 光照 ...

  3. 「六」创建一个带 weblogic 服务的基础镜像

    Weblogic Weblogic 简单介绍以及其在 Docker 环境下的特殊应用 WebLogic是美国Oracle公司出品的一个application server确切的说是一个基于JAVAEE ...

  4. Flutter学习三之搭建一个简单的项目框架

    上一篇文章介绍了Dart的语法的基本使用,从这篇文章开始,开发一个基于玩Android网站的app.使用的他们开放的api来获取网站数据. 根据网站的结构,我们app最外层框架需要添加一个底部导航栏, ...

  5. 学习ASP.NET Core Blazor编程系列五——列表页面

    学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 学习ASP.NET Core Blazor编程系 ...

  6. Flutter学习之路---------第一个Flutter项目

    Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面. Flutter可以与现有的代码一起工作.在全世界,Flutter正在被越来越多的开发者和组织使用,并且 ...

  7. 学习ASP.NET MVC(七)——我的第一个ASP.NET MVC 查询页面

    在本篇文章中,我将添加一个新的查询页面(SearchIndex),可以按书籍的种类或名称来进行查询.这个新页面的网址是http://localhost:36878/Book/ SearchIndex. ...

  8. 【Flutter学习】页面布局之基础布局组件

    一,概述 Flutter中拥有30多种预定义的布局widget,常用的有Container.Padding.Center.Flex.Row.Colum.ListView.GridView.按照< ...

  9. 【Flutter学习】基本组件之图片组件Image

    一,概述 Image(图片组件)是显示图像的组件,一个显示图片的widget,支持图像格式:JPEG,PNG,GIF,动画GIF,WebP,动画WebP,BMP和WBMP. Image组件有多种构造函 ...

随机推荐

  1. eclipse项目文件夹整理

    1.点击倒三角 2.系统默认为Projects,选择第二个working sets 3.点击Configure Working Sets,点new 4.点击后,选中点Add 5.添加一个名字,Fins ...

  2. 经典的 Fork 炸弹解析

    原文出处: saymagic Jaromil 在 2002 年设计了最为精简的一个Linux Fork炸弹,整个代码只有13个字符,在 shell 中运行后几秒后系统就会宕机: ::(){:|:&am ...

  3. SpringMVC+Spring+mybatis+maven+搭建多模块框架前后端分离开发框架的完整demo,拿走不谢。——猿实战02

            猿实战是一个原创系列文章,通过实战的方式,采用前后端分离的技术结合SpringMVC Spring Mybatis,手把手教你撸一个完整的电商系统,跟着教程走下来,变身猿人找到工作不是 ...

  4. JavaScript学习系列博客_28_JavaScript 数组去重

    数组去重 var arr = [1,2,3,2,2,1,3,4,2,5]; //去除数组中重复的数字 //获取数组中的每一个元素 for(var i=0 ; i<arr.length ; i++ ...

  5. goalng包和命令工具

    1. 包简介 任何包系统设计的目的都是为了简化大型程序的设计和维护工作,通过将一组相关的特性放进一个独立的单元以便于理解和更新,在每个单元更新的同时保持和程序中其它单元的相对独立性.这种模块化的特性允 ...

  6. 重学c#系列——盛派自定义异常源码分析(八)

    前言 接着异常七后,因为以前看过盛派这块代码,正好重新整理一下. 正文 BaseException 首先看下BaseException 类: 继承:public class BaseException ...

  7. 树链剖分详解&题解 P6098 【[USACO19FEB]Cow Land G】

    看到各位大佬们已经把其他的东西讲的很明白了,我这个 juruo 就讲一讲最基本的树链剖分吧. 0.树剖是什么?能吃吗? 不能吃 树剖是树链剖分的简称,我们一般说的树剖其实指重链剖分.当然,还有一种长链 ...

  8. 小程序 使用Promise封装request 接口请求

    //httpService.jsconst host = 'https://baidu.com/ceshi' // 接口请求的域名 // get请求使用 json对象转字符串 (formatParam ...

  9. Mysql常用的一些命令

    1.登录Mysql数据库, 打开终端命令输入窗口,输入命令:mysql -u <账户名,一般是root> -p <密码>. 2.显示所有的数据库: show databases ...

  10. mac 下配置连接Linux服务器方法,上传下载文件操作

    1.先按照文档在本地生成SSHkey 2.mac输入 sudo -i 进入超级管理员#模式下,然后 创建用户 #useradd XXXadmin #passwd XXXadmin XXXadmin用户 ...