本项目借用 逛丢 网站的部分数据,仅作为 flutter 开发学习之用。 逛丢官方网址:https://guangdiu.com/
flutter 项目实战三 json数据解析以及Gson格式化flutter 项目实战二 网络请求
flutter 项目实战五 item 点击跳转,webview加载
flutter 项目实战七 bottomNavigationBar
先放上 本人 使用 kotlin 开发的逛丢的页面,kotlin开发的源码以及相关说明将在其他部分给出。
我们会按照此列表展示,但是UI会略有修改。
appBar部分为一个 Image 与 title ,不用详细的分解。
列表的Item 分解示意图如下
说名一下,row是横向排列的控件,column是竖向排列的控件。container 可设置边框边距等属性。
开始代码实现步骤。
新建一个 home_index.dart文件
class HomeIndex extends StatefulWidget{
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return IndexWidget();
}
}
class IndexWidget extends State<HomeIndex>{
@override
Widget build(BuildContext context) {
// TODO: implement build
return null;
}
}
flutter 页面新建的时候可以选择继承 StatefulWidget 以及 StatelessWidget,StatelessWidget是无状态值得,即不可使用setState更新变量,我们需要在获取数据之后来刷新页面加载数据,所以我们使用 StatefulWidget .然后修改 main() 中的代码加载HomeIndex.
此时 IndexWidget 的 build方法返回的还是空值,先完成appBar 部分,修改代码
class IndexWidget extends State<HomeIndex>{
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text("首页",style: TextStyle(color: Colors.white),),
leading: Icon(Icons.menu,color: Colors.white,),
backgroundColor: Colors.green[500],
),
body: Text("列表数据等待设计"),
);
}
}
运行代码
flutter中的所有的控件都是基于 Widget 所有可以使用 各widget 组合出各种效果。上面的appBar 中控件排列方式如下图(actions未展示),大概的位置如下图所示(请忽略图的美丑,示意即可)
下面按照之前的 item 分析设计列表数据。flutter中列表数据使用 ListView.builder 创建。
首先item用container包裹,里面是一个横向排列的Row控件,Row有两个子widget ,左边一个 image,右边一个 column ,column又分为两部分,上面一个Text,下面又是一个Row,而此Row又包含一个靠左显示的Text,以及靠右的有两个子Text的Row.分析完了,开始代码。
根据梳理好的结构关系,编写代码如下
class IndexWidget extends State<HomeIndex>{
List<RstData> _listData;//设置列表数据
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text("首页",style: TextStyle(color: Colors.white),),
leading: Icon(Icons.menu,color: Colors.white,),
backgroundColor: Colors.green[500],
),
body: _listInfos(),
);
}
//list列表
Widget _listInfos(){
return ListView.builder(
itemCount: 3,//此处展示需要写成此形式,实际适用时 _listData==null?0:_listData.length
itemBuilder: (content,index){
return _listItem(null);
}
);
}
//list列表的item
Widget _listItem(RstData rstdata){
return Container(
height: 110,//设置item的高度
padding: EdgeInsets.all(5),//设置item的边距
child: Row(
children: <Widget>[
Container(
height: 100,
margin: EdgeInsets.all(5),//设置图片的边距
child: Image.network("https://l.guangdiu.com/29ddbc1dc1e151a2311604744f54510b.jpg?imageView2/2/w/224/h/224/format/jpg"),
),//涉及到widget的大小或者边框的时候,使用container包裹
Container(
width: MediaQuery.of(context).size.width-120,
child: Column(
children: <Widget>[
Text("拼多多 Apple 苹果 新iPad Air 10.5 英寸平板电脑 WLAN版 64GB 3749元包邮(直降250元)"),
Expanded( //此处使用expanded 填充,然后设置container 的对其方式确保 在底部显示
child: Row(
children: <Widget>[
Container(
alignment: Alignment.bottomLeft,//设置container的对其方式
child: Text("天猫",style: TextStyle(color: Colors.green[500]),),
),
Expanded(
child: Container(
alignment: Alignment.bottomRight,//设置container的对其方式
child: Row(
mainAxisAlignment: MainAxisAlignment.end,//设置ROW的对其显示方式
children: <Widget>[
Text("3分钟前-",style: TextStyle(color: Colors.green[500]),),
Text("今日值得买",style: TextStyle(color: Colors.green[500]),),
],
),
),
),
],
),
),//expanded类似于Android View的layout_weight属性按照比例填充,flex: 为1 时可以不填写此属性
],
),
),
],
),
);
}
}
因为边界问题所以当widget需要设置宽高,对其方式等属性是,我们用container进行包裹,当控件需要占用一个不固定的空间时,我们用expanded 包裹,达到类似于 Android View的layout_weight的使用效果。
运行示例,app截图
基本样式已完成,下面的步骤是使用网络数据填充,并且给item添加一个框框
修改后的代码为
class IndexWidget extends State<HomeIndex>{
List<RstData> _listData;//设置列表数据
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text("首页",style: TextStyle(color: Colors.white),),
leading: Icon(Icons.menu,color: Colors.white,),
backgroundColor: Colors.green[500],
),
body: _listInfos(),
);
}
//list列表
Widget _listInfos(){
return ListView.builder(
itemCount: _listData==null?0:_listData.length,//此处展示需要写成 3,实际适用时 _listData==null?0:_listData.length
itemBuilder: (content,index){
return _listItem(_listData[index]);
}
);
}
//list列表的item
Widget _listItem(RstData rstdata){
return Container(
height: 110,//设置item的高度
margin: EdgeInsets.only(left: 5,right: 5,top: 5),//设置item的边距
decoration: BoxDecoration(
border: Border.all(color: Colors.black54,width: 1),//设置边框的宽度 以及 颜色
borderRadius: BorderRadius.all(Radius.circular(5)),//设置圆角
),
child: Row(
children: <Widget>[
Container(
height: 100,
margin: EdgeInsets.all(5),//设置图片的边距
child: Image.network(rstdata.image),
),//涉及到widget的大小或者边框的时候,使用container包裹
Expanded(
child: Container(
margin: EdgeInsets.only(right: 5),
child: Column(
children: <Widget>[
Text(rstdata.title),
Expanded( //此处使用expanded 填充,然后设置container 的对其方式确保 在底部显示
child: Row(
children: <Widget>[
Container(
alignment: Alignment.bottomLeft,//设置container的对其方式
child: Text(rstdata.mall,style: TextStyle(color: Colors.green[500]),),
),
Expanded(
child: Container(
alignment: Alignment.bottomRight,//设置container的对其方式
child: Row(
mainAxisAlignment: MainAxisAlignment.end,//设置ROW的对其显示方式
children: <Widget>[
Text("${rstdata.pubtime}-",style: TextStyle(color: Colors.green[500],fontSize: 10),),
Text(rstdata.fromsite,style: TextStyle(color: Colors.green[500],fontSize: 10),),
],
),
),
),
],
),
),//expanded类似于Android View的layout_weight属性按照比例填充,flex: 为1 时可以不填写此属性
],
),
),
),
],
),
);
}
@override
void initState() {
// TODO: implement initState
super.initState();
//项目加载时去获取数据
_getGuangdiuIndexData();
}
void _getGuangdiuIndexData() async{
String url="getlist.php";
FormData formData=FormData();
formData.add("markid", "5685521");
Response resp=await HttpUtil().post(url,data: formData).then((resp){
RespResult respResult=RespResult.fromJson(resp.data);
setState(() {
_listData=respResult.data;
});
});
}
}
此处在 initState 中获取数据,所有不用热加载更新,否则看不到数据。重新运行项目等到数据列表
此为数据的展示样式