個人中心頁面
為什麼要挑這個頁面來講解下佈局呢,因為它比較具有代表意義,塊狀的佈局,包含Row,Column,Stack。最主要的是角標的處理方式。在一般的頁面中,我們都採用上下佈局,左右佈局,列表等來做,很巧合的是這裡基本都有,同時有一個要注意的點是角標,屬於絕對位置的佈局。
首先我們來解析一下這個個人中心頁面;
- 頂部導航欄;
- 頭部個人資訊;
- 訂單和其他中的Item項(角標要注意下);
這個頁面由三部分組成,我們分別來說下三部分怎麼實現:
- 頂部導航欄
appBar: AppBar(
backgroundColor: Color.fromRGBO(73, 129, 245, 1),
title: Text(
"我的",
style: TextStyle(
color: Colors.white, fontSize: 16, fontWeight: FontWeight.bold),
),
///導航欄下的那條黑線
elevation: 0,
///右側按鈕,可設定多個
actions: <Widget>[
FlatButton(
child: Text(
"設定",
style: TextStyle(
color: Colors.white,
fontSize: 15,
fontWeight: FontWeight.bold),
),
onPressed: () {
},
),
],
),
複製程式碼
此模組比較簡單和常規,一目瞭然,不再過多複述。
頭部個人資訊
return Container(
///設定背景漸變色
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Color.fromRGBO(73, 129, 245, 1),
Color.fromRGBO(115, 172, 248, 1),
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
)),
child: Container(
margin: EdgeInsets.only(top: 16, bottom: 16),
child: Row(
children: <Widget>[
Container(
margin: EdgeInsets.only(left: 16),
///切成圓形
child: ClipOval(
child: Image(
image: AssetImage('images/codingfire.png'),
width: 48),
),
),
Expanded(
flex: 100,
child: Container(
margin: EdgeInsets.only(left: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start, //元素左對齊
children: <Widget>[
Container(
child: Text(
Glb().userName,///可加長,會顯示點點點
style: TextStyle(
fontSize: 19,
fontWeight: FontWeight.bold,
color: Colors.white),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
Container(
child: Text(
"黃河之水天上來,奔流到海不復回",///可加長,會顯示點點點
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 12,
color: Colors.white,
),
),
),
],
),
),
),
// Spacer(),
Container(
height: 24,
padding: EdgeInsets.only(right: 16, left: 6),
child: OutlineButton(
color: Colors.white,
child: Baseline(
baseline: 12,
baselineType: TextBaseline.alphabetic,
child: Text("編輯資訊",
style: TextStyle(color: Colors.white, fontSize: 12),
textAlign: TextAlign.center),
),
///設定圓角
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0)),
borderSide: new BorderSide(color: Colors.white),
onPressed: () {
},
),
),
],
),
),
);
複製程式碼
這裡有一張簡單的佈局圖可以說明佈局的關係,外層是Row,暱稱和副考標題所在的區域可以用Column來進行佈局。這裡說下為什麼要用Expanded,是為了讓文字自動撐開的同時,在超出右邊區域的時候不至於報錯,並自己顯示點點點,設定點點點要設定:
overflow: TextOverflow.ellipsis,
複製程式碼
訂單和其他中的Item項(角標要注意下)
接下來要寫的是塊狀區域,塊狀區域每行有四塊,每塊中有最多三個元素,分別是icon,標題和角標;我們可以參照個人資訊部分用Row很容易的實現這樣的效果,但是角標加入的時候會導致icon或者標題位置變化,因為角標是需要蓋在icon右上角的,按照盒子佈局的方式,會擠到其他元素導致變形,這時要用到Stack佈局,前端中也存在這樣的佈局方式。下面看下具體實現:
return Container(
color: Colors.white,
height: 92,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
itemCell(
Icon(
Icons.access_time,
color: Color(0xFF3479FD),
),
'全部訂單',
"https://blog.csdn.net/CodingFire",
10),
itemCell(
Icon(
Icons.access_time,
color: Color(0xFF3479FD),
),
'待發貨',
"https://blog.csdn.net/CodingFire",
100),
itemCell(
Icon(
Icons.access_time,
color: Color(0xFF3479FD),
),
'待收貨',
'https://blog.csdn.net/CodingFire',
0),
itemCell(
Icon(
Icons.access_time,
color: Color(0xFF3479FD),
),
'確認收貨',
'https://blog.csdn.net/CodingFire',
1),
],
),
);
複製程式碼
這裡你看到的很簡單,是塊狀的處理方式,單獨對塊做了封裝,並傳入需要的icon,標題,跳轉連結和訂單數量。下面我們來看看對塊的封裝:
Widget itemCell(Icon itemIcon, String itemTitle, String url, int count) {
double c_width;
if (count < 10) {
c_width = 20;
} else if (count > 100) {
c_width = 35;
} else
c_width = 30;
return GestureDetector(
onTap: () {
},
child: Container(
color: Colors.white,
child: Stack(
children: <Widget>[
Stack(
children: <Widget>[
Container(
height: 27,
margin: EdgeInsets.only(top: 0),
child: IconButton(
icon: itemIcon,
tooltip: 'item',
iconSize: 23,
),
),
Container(
///Offstage表示按條件可隱藏的包裝
child: Offstage(
///這裡隱藏的條件是count=0的時候,Offstage包含的模組(角標)會隱藏,考慮的是下面沒有角標的item
offstage: count == 0,
child: Container(
margin: EdgeInsets.only(left: 30),
width: c_width,
height: 14,
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(7),
bottomRight: Radius.circular(7),
topRight: Radius.circular(7)),
color: Color(0xFFFF491C),
),
child: Text(
count >= 100 ? '99+' : count.toString(),
style: TextStyle(
color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.w500),
),
),
),
)
],
),
Container(
width: 50,
margin: EdgeInsets.only(top: 35),
child: Text(
itemTitle,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
color: Colors.black,
fontWeight: FontWeight.w500),
),
),
],
),
),
);
}
複製程式碼
其實也不復雜吧,只是要用到Stack的佈局方式,讓角標可以蓋在icon右上角而不至於擠到佈局變形。
以上就是個人中心頁面佈局的全部,如需程式碼可單獨找博主要下,暫時先不放上去,因為還有一篇關於單例靈活使用的部落格,程式碼會放在一起,後續會更新上地址。
備註:以上佈局並非最佳方案,大家可自行嘗試。
如果你細心的話會發現這裡已經用到了單例中的資料:
Glb().userName
複製程式碼
補充
今天,博主發現了一個問題,在適配iPad和安卓iPad時發現下面的文字換行了,因為設定了width:50,這是不合理的,應該去掉寬度設定。但同時發現icon下的文字不會自動居中,因為使用的是Stack,所以沒有辦法設定讓文字整體豎直居中,所以要調整佈局為Column,角標通過Positioned來處理,完美解決,下面看下修改後的程式碼:
Widget itemCell(Icon itemIcon, String itemTitle, String url, int count) {
double c_width;
if (count < 10) {
c_width = 20;
} else if (count > 100) {
c_width = 35;
} else
c_width = 30;
return GestureDetector(
onTap: () {
},
child: Container(
color: Colors.white,
child: Column(
children: <Widget>[
Stack(
children: <Widget>[
Container(
height: 23,
///這裡左右一定要撐開20的區域,要不然紅色角標會顯示不全(我覺得這裡的佈局還可以再優化)
margin: EdgeInsets.only(top: 28, left: 20, right: 20),
child: IconButton(
padding: EdgeInsets.all(0),
icon: itemIcon,
tooltip: 'item',
iconSize: 23,
),
),
Positioned(
left: 17,
top: 20,
child: Offstage(
offstage: count == 0,
child: Container(
margin: EdgeInsets.only(left: 30),
width: c_width,
height: 14,
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(7),
bottomRight: Radius.circular(7),
topRight: Radius.circular(7)),
color: Color(0xFFFF491C),
),
child: Text(
count >= 100 ? '99+' : count.toString(),
style: TextStyle(
color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.w500),
),
),
),
)
],
),
Container(
color: Colors.white,
margin: EdgeInsets.only(top: 4),
child: Text(
itemTitle,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
color: Colors.black,
fontWeight: FontWeight.w500),
),
),
],
),
),
);
}
複製程式碼