版權(quán)聲明:本文為本人原創(chuàng)文章,未經(jīng)本人允許不得轉(zhuǎn)載。
不知不覺已經(jīng)到第五篇了,本篇結(jié)束,這個項目目前要展現(xiàn)的UI界面布局就差不多了,下一篇開始就會開始講數(shù)據(jù)庫本地存儲和業(yè)務(wù)邏輯了。剩下查詢、統(tǒng)計等頁面等我學(xué)習(xí)做完再寫,現(xiàn)在我自己也不會 哈哈哈!
廢話少說,直接開始今天的內(nèi)容,先看兩個圖:
以上就是今天要說的內(nèi)容:
1.首頁添加tabbar,用于分別展示所有項目和未結(jié)款項目
2.完成首頁項目卡片點擊后的詳細信息查看
1、先講首頁tabbar的實現(xiàn)
之前我的文章也有介紹這部分實現(xiàn),相對不難,我們正好再復(fù)習(xí)下。
要實現(xiàn)頂部tabbar效果,那么他不是某個單獨控件就可以展現(xiàn)的,是由一些控件組合起來才能正常運行,包括:TabController、TabBar、TabBarView。
首先找到home_page.dart
文件,修改其內(nèi)容:
@override
Widget build(BuildContext context) {
//使用默認的tab控制器來實現(xiàn)tab標簽和展示內(nèi)容的聯(lián)動
return new DefaultTabController(
//length代表一共有幾個tabbar
length: 2,
child: new Scaffold(
//標題欄,包含一個標題和一個圖標按鈕
appBar: new AppBar(
title: new Text(_title),
actions: <Widget>[
new IconButton(icon: new Icon(Icons.palette), onPressed: () {})
],
//TabBar是屬于appbar的底部屬性控件
bottom: new TabBar(
indicatorColor: Colors.white,
indicatorSize: TabBarIndicatorSize.label,
tabs: <Widget>[
new Text('全部(${_diyProjects.length})'),
new Text('未結(jié)(${_diyProjects.length})'),
],
),
),
//TabBarView用于展示對應(yīng)tab標簽下的內(nèi)容,通過默認的tab控制器來實現(xiàn)對應(yīng)
body: new TabBarView(
children: <Widget>[
new ListView.builder(
itemCount: _diyProjects.length,
itemBuilder: (context, index) {
return new DiyListShow(
diyItem: _diyProjects[index],
);
},
),
new Center(
child: new Text('這是未結(jié)頁面'),
)
],
),
以上代碼再原有基礎(chǔ)上進行了三處改動
1、在AppBar的bottom屬性里增加TabBar控件,并添加兩個標簽
2、body屬性原來的ListView.build控件外面套上TabBarView,用于存放標簽頁對應(yīng)的視圖內(nèi)容
3、在整個Scaffold外增加DefaultTabController,通過這個默認的控制器實現(xiàn)標簽和視圖的聯(lián)動
標簽可以包含名字和圖標,我這里就沒有放圖標,我在后面添加了一個數(shù)字,代表這個標簽下的數(shù)據(jù)量。大家可以試試添加圖標看看效果。
2、實現(xiàn)首頁項目卡片點擊進入相信相信查看頁面
開始做之前先分析頁面結(jié)構(gòu),觀察上圖發(fā)現(xiàn)這個頁面基本包含以下控件:
1、可以跟隨滑動的sliverAppbar
2、floatingActionButton
3、用于項目信息展示的ListTile
首先我們在pages下新建diy_item_info.dart
,在ui下新建diy_info_show.dart
兩個文件,我們將在這兩個文件里實現(xiàn)點擊卡片查看詳細信息。
首先編輯diy_info_show.dart
:
import 'package:activity_record/model/diy_project.dart';
import 'package:flutter/material.dart';
class DiyInfoShow extends StatelessWidget {
DiyInfoShow({Key key, this.diyItem}) : super(key: key);
DiyProject diyItem;
@override
Widget build(BuildContext context) {
//使用stack,將滑動視圖和浮動按鈕組合起來,實現(xiàn)按鈕附加在FlexibleSpaceBar效果
return new Stack(children: <Widget>[
//SliverAppBar需要配合CustomScrollView來實現(xiàn)
new CustomScrollView(
slivers: <Widget>[
new SliverAppBar(
//展開的高度
expandedHeight: 218.0,
//是否隨著滑動消失
pinned: true,
actions: <Widget>[
new IconButton(
icon: new Icon(Icons.content_paste),
onPressed: () {},
)
],
//展開的空間區(qū)域
flexibleSpace: new FlexibleSpaceBar(
//設(shè)置區(qū)域背景圖片
background: new Image.asset(
diyItem.imagePath,
fit: BoxFit.cover,
),
title: new Text(
'利潤:${diyItem.profit.toString()}',
style: new TextStyle(fontSize: 16.0),
),
centerTitle: true,
),
),
//sliverAppBar下面的內(nèi)容區(qū)域
new SliverList(
delegate: new SliverChildListDelegate([
//名稱和聯(lián)系人
new ListTile(
leading: new Icon(
Icons.toys,
color: Theme.of(context).primaryColor,
),
title: new Text(diyItem.name,
style: new TextStyle(
fontWeight: FontWeight.bold, fontSize: 22.0)),
subtitle: new Text(diyItem.contact),
),
new Divider(
indent: 16.0,
),
//活動地點時間
new ListTile(
leading: new Icon(
Icons.open_with,
color: Theme.of(context).primaryColor,
),
title: new Text(diyItem.place,
style: new TextStyle(fontWeight: FontWeight.w500)),
subtitle: new Text(diyItem.date),
),
new Divider(
indent: 16.0,
),
//活動單價和份數(shù)
new ListTile(
leading: new Icon(
Icons.repeat,
color: Theme.of(context).primaryColor,
),
title: new Text('單價: ${diyItem.singlePrcie}元'),
subtitle: new Text('份數(shù): ${diyItem.nums}'),
),
//活動總價、物料人員成本
new ListTile(
leading: new Icon(
Icons.attach_money,
color: Theme.of(context).primaryColor,
),
title: new Text('總價: ${diyItem.totalAmount}元'),
subtitle: new Row(children: <Widget>[
new Text('物料: ${diyItem.itemCost}元'),
new SizedBox(
width: 10.0,
),
new Text('人員: ${diyItem.laborCost}元'),
]),
),
]),
)
],
),
//位置控件,用于擺放浮動按鈕
new Positioned(
top: 218.0,
right: 26.0,
child: new FloatingActionButton(
backgroundColor: diyItem.isCheckOut ? Colors.green : Colors.redAccent,
onPressed: () {},
child: new Text(
diyItem.isCheckOut ? '已結(jié)清' : '未結(jié)清',
style: new TextStyle(fontSize: 12.0),
),
),
)
]);
}
}
以上代碼整體實現(xiàn)思路如下:
1、通過SliverAppBar和CustomScrollView結(jié)合實現(xiàn)可擴展收縮的滑動標題欄
2、通過ListTile完成項目信息的展示,中間通過Divider添加分割線。
3、通過Stack疊加控件和Positioned位置控件將FloatingActionButton放在SliverAppBar上。
由于我底下展示區(qū)域內(nèi)容不多,所以無法看到標題欄的收縮效果,如果多放幾個內(nèi)容滾動的時候就會有收縮效果。
當然了埋了一個坑在里面,不知道你是不是看出來了呢,可以試試如何解決這個問題,這個坑就下次再填吧 。
寫完UI布局,我們還需要編輯diy_item_info.dart文件,來展示以上的UI代碼:
diy_item_info.dart
import 'package:activity_record/model/diy_project.dart';
import 'package:activity_record/ui/diy_info_show.dart';
import 'package:flutter/material.dart';
class DiyItemInfo extends StatelessWidget {
DiyItemInfo({Key key, this.diyItem}) : super(key: key);
DiyProject diyItem;
@override
Widget build(BuildContext context) {
return new Scaffold(
body: new DiyInfoShow(diyItem: diyItem,),
);
}
}
現(xiàn)在為止真是萬事俱備,只欠路由咯,因為我們還要去首頁card的點擊事件去配置導(dǎo)航路由到這個項目信息頁面
diy_list_show.dart
@override
Widget build(BuildContext context) {
//將整個項目展示內(nèi)容包裹在card里
return new Card(
margin: const EdgeInsets.fromLTRB(18.0, 18.0, 18.0, 9.0), //設(shè)置外邊距18
//card形狀設(shè)置頂部圓形弧度12,底部沒有
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(12.0))),
//inkwell是一個帶水波紋觸摸效果的控件,預(yù)留點擊回調(diào)作為以后點擊響應(yīng)事件
child: new InkWell(
onTap: () {
Navigator.of(context)
.push(new MaterialPageRoute(builder: (BuildContext context) {
return new DiyItemInfo(
diyItem: widget.diyItem,
);
}));
},
child: _diyContentShow(),
),
);
}
這樣我們就可以通過點擊首頁項目卡片查看項目信息咯。
最后
今天結(jié)束后,這個項目的UI布局除了查詢和統(tǒng)計頁面外基本就完成了。細心的你可能發(fā)現(xiàn)了目前的數(shù)據(jù)都是預(yù)設(shè)的,如何通過用戶添加,如果進行數(shù)據(jù)保存是必不可少的,所以下篇開始我將介紹Flutter本地數(shù)據(jù)庫sqflite的用法以及業(yè)務(wù)交互邏輯。
最后附上項目源碼地址:https://gitee.com/xusujun33/activity_record_jia.git
項目持續(xù)更新中.......