Flutter 開發從 0 到 1(三)布局與 ListView
上周日出去玩了,因此沒時間寫文章。我司加班到 11 點,第二天可以晚上班一個小時,加班到 12 點,可以晚上班兩個小時,以此類推,為什麼說這個,對的,加班第二天我沒有多睡覺,而是起來抓緊時間寫文章,好了,廢話不多說,進入今天的主題。
布局
說到 Android 布局,不是很難,會在對應的 xml 裡布局,Flutter 里沒有 xml,都在代碼里寫,給人感覺就很難,看下我們要實現的布局:
打開 PhotoShop,看下背景色 #ededed,日期字體顏色 #a6a6a6,標題字體顏色 #1b1b1b,摘要字體顏色 #808080。
公眾號這是列表,我先將 item 搞定。看這布局都是線性布局,這要在之前,分分鐘搞定,但 Flutter……好吧,Flutter 布局可沒那麼簡單,我花了好幾個小時才做好,期間遇到了不少困難。
Flutter 也有橫向 Row 布局和豎向 Column 布局,我本想分 1 和 2 兩個部分,最外層豎向 Column 包含 1 和 2,2 本身是 Column,包含一個 image 和兩個 text,直接使用 Column 可以完成,當我需要設置 2 裏面白色的背景色,發現 Column 根本沒有背景色屬性,於是把 2 最外層改造成 Container。
使用 Container 沒有問題,布局也很快實現了,接下來是實現四角的圓角效果。
Container 有 decoration,可以實現圓角,我遇到了兩個問題:
1、當 shape: BoxShape.circle 時不能設置 borderRadius ,會異常
異常信息:’shape != BoxShape.circle ||borderRadius == null’: is not true.
2、使用 BoxDecoration
Container 不能使用 color,會報錯:
Cannot provide both a color and a decoration
To provide both, use “decoration: BoxDecoration(color: color)”.
以為這樣就實現了圓角,不,不會那麼順利的,發現圖片根本沒有圓角效果,這和之前 Java 實現方式不一樣,最外層都實現了圓角,對裏面的布局(圖片)居然沒有生效,最後只好把布局實現如下:
分成 1、2、3 部分,3 還是 Container,2 和 3 圓角效果只對上下部分分別實現,完整代碼如下:
blogItem() {
var date = new Padding(
padding: const EdgeInsets.only(
top: 20.0,
left: 10.0,
right: 10.0,
),
child: new Text(
'2020年6月28日 22:49',
textAlign: TextAlign.center,
style: TextStyle(color: ColorCommon.dateColor, fontSize: 18),
));
var cover = new Padding(
padding: const EdgeInsets.only(
top: 10.0,
left: 10.0,
right: 10.0,
),
child: new ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10.0),
topRight: Radius.circular(10.0)),
child: new Image.network(
'//pic1.win4000.com/wallpaper/2020-04-21/5e9e676001e20.jpg',
)));
var title = new Text(
'APP 開發從 0 到 1(一)需求與準備',
style: TextStyle(color: ColorCommon.titleColor, fontSize: 22),
);
var summary = new Padding(
padding: const EdgeInsets.only(
top: 5.0,
),
child: new Text('一個人做一個項目,你也可以。',
textAlign: TextAlign.left,
style: TextStyle(color: ColorCommon.summaryColor, fontSize: 18)));
var titleSummary = new Container(
padding: const EdgeInsets.all(10.0),
alignment: Alignment.topLeft,
decoration: new BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(10.0),
bottomRight: Radius.circular(10.0)),
shape: BoxShape.rectangle,
),
margin: const EdgeInsets.only(left: 10, right: 10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[title, summary],
),
);
var blogItem = new Column(
children: <Widget>[date, cover, titleSummary, date, cover, titleSummary],
);
return blogItem;
}
實際效果如下:
好了,關於 Flutter 布局就講到這裡,我只是針對這個項目所需要的去實現,Flutter 布局的東西還有很多,其屬性讓人眼花撩亂,可以去官網一個個去仔細學習和實踐。
ListView
blogItem 寫好了,完成了大頭,接下來就要填充真實的數據,在《APP 開發從 0 到 1(二)框架與網絡》,有說到網絡請求,其中有提到 setstate(){} 方法,調用這個方法會回調 build 方法,這樣我們可以在 build 方法加個判斷,先加載 Progress,待網絡數據請求完,再顯示 ListView,代碼如下:
@override
Widget build(BuildContext context) {
var content;
if (blogList.isEmpty) {
content = new Center(
// 可選參數 child:
child: new CircularProgressIndicator(),
);
} else {
content = new ListView(children: blogItem());
}
return Scaffold(
backgroundColor: ColorCommon.backgroundColor,
appBar: AppBar(
title: Text('AndBlog'),
),
body: content,
floatingActionButton: FloatingActionButton(
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
blogItem() {
List<Widget> widgets = [];
for (int i = 0; i < blogList.length; i++) {
Blog blog = blogList[i];
var date = new Padding(
padding: const EdgeInsets.only(
top: 20.0,
left: 10.0,
right: 10.0,
),
child: new Text(
// 填充真實數據
blog.date,
textAlign: TextAlign.center,
style: TextStyle(color: ColorCommon.dateColor, fontSize: 18),
));
//……
var blogItem = new Column(
children: <Widget>[
date,
cover,
titleSummary,
],
);
widgets.add(blogItem);
}
return widgets;
}
這樣 ListView 也完成了,接下來需要完成的是 ListView 加載更多。