- 原文地址:Flutter Layout Cheat Sheet
- 原文做者:Tomek Polański
- 譯文出自:掘金翻譯計劃
- 本文永久連接:github.com/xitu/gold-m…
- 譯者:EmilyQiRabbit
- 校對者:smilemuffie,suhanyujie
你須要瞭解 Flutter 的簡單佈局模版嗎? 如今我將展現給你我總結的一系列 Flutter 佈局代碼片斷。我會盡可能保證代碼簡短易懂,而且會給出效果圖。 可是咱們仍舊須要按部就班 —— 模版目錄將會隨之逐步深刻。我將會將更多的篇幅集中於 Flutter 部件的應用,而不是單純陳列組件(Flutter Gallery 在這一點作的很好!) 若是你對於 Flutter 佈局還有其餘疑問,或者想要分享你的代碼,請留言給我!css
List<BoxShadow>
Row /*或 Column*/(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Icon(Icons.star, size: 50),
Icon(Icons.star, size: 50),
Icon(Icons.star, size: 50),
],
),
複製代碼
Row /*或 Column*/(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.star, size: 50),
Icon(Icons.star, size: 50),
Icon(Icons.star, size: 50),
],
),
複製代碼
Row /*或 Column*/(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Icon(Icons.star, size: 50),
Icon(Icons.star, size: 50),
Icon(Icons.star, size: 50),
],
),
複製代碼
Row /*或 Column*/(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Icon(Icons.star, size: 50),
Icon(Icons.star, size: 50),
Icon(Icons.star, size: 50),
],
),
複製代碼
Row /*或 Column*/(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Icon(Icons.star, size: 50),
Icon(Icons.star, size: 50),
Icon(Icons.star, size: 50),
],
),
複製代碼
Row /*或 Column*/(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Icon(Icons.star, size: 50),
Icon(Icons.star, size: 50),
Icon(Icons.star, size: 50),
],
),
複製代碼
若是你想要不一樣字符的基線對齊,你應該使用 CrossAxisAlignment.baseline
。前端
Row(
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: <Widget>[
Text(
'Baseline',
style: Theme.of(context).textTheme.display3,
),
Text(
'Baseline',
style: Theme.of(context).textTheme.body1,
),
],
),
複製代碼
Row /*或 Column*/(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Icon(Icons.star, size: 50),
Icon(Icons.star, size: 200),
Icon(Icons.star, size: 50),
],
),
複製代碼
Row /*或 Column*/(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Icon(Icons.star, size: 50),
Icon(Icons.star, size: 200),
Icon(Icons.star, size: 50),
],
),
複製代碼
Row /*或 Column*/(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Icon(Icons.star, size: 50),
Icon(Icons.star, size: 200),
Icon(Icons.star, size: 50),
],
),
複製代碼
Row /*或 Column*/(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Icon(Icons.star, size: 50),
Icon(Icons.star, size: 200),
Icon(Icons.star, size: 50),
],
),
複製代碼
Row /*或 Column*/(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Icon(Icons.star, size: 50),
Icon(Icons.star, size: 50),
Icon(Icons.star, size: 50),
],
),
複製代碼
Row /*或 Column*/(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Icon(Icons.star, size: 50),
Icon(Icons.star, size: 50),
Icon(Icons.star, size: 50),
],
),
複製代碼
想要某行或列中全部部件和最高/最寬的部件同樣高/寬?不要亂找了,答案在這裏!android
當你有這種樣式的佈局:ios
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('IntrinsicWidth')),
body: Center(
child: Column(
children: <Widget>[
RaisedButton(
onPressed: () {},
child: Text('Short'),
),
RaisedButton(
onPressed: () {},
child: Text('A bit Longer'),
),
RaisedButton(
onPressed: () {},
child: Text('The Longest text button'),
),
],
),
),
);
}
複製代碼
可是你但願全部的按鈕都和最寬的按鈕等寬,只須要使用 IntrinsicWidth
:git
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('IntrinsicWidth')),
body: Center(
child: IntrinsicWidth(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
RaisedButton(
onPressed: () {},
child: Text('Short'),
),
RaisedButton(
onPressed: () {},
child: Text('A bit Longer'),
),
RaisedButton(
onPressed: () {},
child: Text('The Longest text button'),
),
],
),
),
),
);
}
複製代碼
若是你須要的是讓全部部件和最高的部件等高,能夠結合使用 IntrinsicHeight
和 Row
部件。github
很是適用於將部件疊加在一塊兒算法
@override
Widget build(BuildContext context) {
Widget main = Scaffold(
appBar: AppBar(title: Text('Stack')),
);
return Stack(
fit: StackFit.expand,
children: <Widget>[
main,
Banner(
message: "Top Start",
location: BannerLocation.topStart,
),
Banner(
message: "Top End",
location: BannerLocation.topEnd,
),
Banner(
message: "Bottom Start",
location: BannerLocation.bottomStart,
),
Banner(
message: "Bottom End",
location: BannerLocation.bottomEnd,
),
],
);
}
複製代碼
若是想使用本身的部件,須要將它們放置在 Positioned
裏面後端
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Stack')),
body: Stack(
fit: StackFit.expand,
children: <Widget>[
Material(color: Colors.yellowAccent),
Positioned(
top: 0,
left: 0,
child: Icon(Icons.star, size: 50),
),
Positioned(
top: 340,
left: 250,
child: Icon(Icons.call, size: 50),
),
],
),
);
}
複製代碼
若是你不想去猜想 top 或 bottom 的值,你可使用 LayoutBuilder
來檢索它們數組
Widget build(BuildContext context) {
const iconSize = 50;
return Scaffold(
appBar: AppBar(title: Text('Stack with LayoutBuilder')),
body: LayoutBuilder(
builder: (context, constraints) =>
Stack(
fit: StackFit.expand,
children: <Widget>[
Material(color: Colors.yellowAccent),
Positioned(
top: 0,
child: Icon(Icons.star, size: iconSize),
),
Positioned(
top: constraints.maxHeight - iconSize,
left: constraints.maxWidth - iconSize,
child: Icon(Icons.call, size: iconSize),
),
],
),
),
);
}
複製代碼
Expanded
能夠和 Flex\Flexbox 佈局一塊兒應用,而且很是適用於分配多元素的空間。app
Row(
children: <Widget>[
Expanded(
child: Container(
decoration: const BoxDecoration(color: Colors.red),
),
flex: 3,
),
Expanded(
child: Container(
decoration: const BoxDecoration(color: Colors.green),
),
flex: 2,
),
Expanded(
child: Container(
decoration: const BoxDecoration(color: Colors.blue),
),
flex: 1,
),
],
),
複製代碼
默認狀況下,大多數組件都會使用盡量小的空間:
Card(child: const Text('Hello World!'), color: Colors.yellow)
複製代碼
ConstrainedBox
讓部件可使用指望的剩餘空間。
ConstrainedBox(
constraints: BoxConstraints.expand(),
child: const Card(
child: const Text('Hello World!'),
color: Colors.yellow,
),
),
複製代碼
你可使用 BoxConstraints
指定部件可使用多大的空間 —— 經過指定 height
/width
的 min
/max
屬性。
BoxConstraints.expand
將會讓組件使用無限制(全部可用)的空間,除非另有指定:
ConstrainedBox(
constraints: BoxConstraints.expand(height: 300),
child: const Card(
child: const Text('Hello World!'),
color: Colors.yellow,
),
),
複製代碼
上面代碼和以下代碼等效:
ConstrainedBox(
constraints: BoxConstraints(
minWidth: double.infinity,
maxWidth: double.infinity,
minHeight: 300,
maxHeight: 300,
),
child: const Card(
child: const Text('Hello World!'),
color: Colors.yellow,
),
),
複製代碼
最經常使用的部件之一 —— 而且它之因此這麼經常使用是有緣由的:
若是你沒有指定 Container
的 height
和 width
,它將和 child
的大小相同
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Container as a layout')),
body: Container(
color: Colors.yellowAccent,
child: Text("Hi"),
),
);
}
複製代碼
若是你想要 Container
擴大到和它的父級元素相等,對 height
和 width
屬性使用 double.infinity
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Container as a layout')),
body: Container(
height: double.infinity,
width: double.infinity,
color: Colors.yellowAccent,
child: Text("Hi"),
),
);
}
複製代碼
你可使用 color 屬性來改變 Container
的背景色,可是 decoration
和 foregroundDecoration
則能夠作更多。(使用這兩個屬性,你能夠完全改變 Container
的外觀,這部分我將在後續討論,由於這部份內容不少) decoration
總會放置在 child 後面,而 foregroundDecoration
則在 child
的上面。
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Container.decoration')),
body: Container(
height: double.infinity,
width: double.infinity,
decoration: BoxDecoration(color: Colors.yellowAccent),
child: Text("Hi"),
),
);
}
複製代碼
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Container.foregroundDecoration')),
body: Container(
height: double.infinity,
width: double.infinity,
decoration: BoxDecoration(color: Colors.yellowAccent),
foregroundDecoration: BoxDecoration(color: Colors.red.withOpacity(0.5)),
child: Text("Hi"),
),
);
}
複製代碼
若是你不想使用 Transform
部件來改變你的佈局,你可使用 Container
的 transform
屬性
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Container.transform')),
body: Container(
height: 300,
width: 300,
transform: Matrix4.rotationZ(pi / 4),
decoration: BoxDecoration(color: Colors.yellowAccent),
child: Text(
"Hi",
textAlign: TextAlign.center,
),
),
);
}
複製代碼
裝飾效果一般用於容器組件,來改變組件的外觀。
將圖片做爲背景:
Scaffold(
appBar: AppBar(title: Text('image: DecorationImage')),
body: Center(
child: Container(
height: 200,
width: 200,
decoration: BoxDecoration(
color: Colors.yellow,
image: DecorationImage(
fit: BoxFit.fitWidth,
image: NetworkImage(
'https://flutter.io/images/catalog-widget-placeholder.png',
),
),
),
),
),
);
複製代碼
指定容器的邊框樣式。
Scaffold(
appBar: AppBar(title: Text('border: Border')),
body: Center(
child: Container(
height: 200,
width: 200,
decoration: BoxDecoration(
color: Colors.yellow,
border: Border.all(color: Colors.black, width: 3),
),
),
),
);
複製代碼
讓邊框能夠是圓角。
若是裝飾的 shape
是 BoxShape.circle
,那麼 borderRadius
將無效
Scaffold(
appBar: AppBar(title: Text('borderRadius: BorderRadius')),
body: Center(
child: Container(
height: 200,
width: 200,
decoration: BoxDecoration(
color: Colors.yellow,
border: Border.all(color: Colors.black, width: 3),
borderRadius: BorderRadius.all(Radius.circular(18))),
),
),
);
複製代碼
盒子的形狀能夠是長方形、正方形、橢圓或者圓形。
對於其餘任意形狀,你應該使用 ShapeDecoration
而不是 BoxDecoration
Scaffold(
appBar: AppBar(title: Text('shape: BoxShape')),
body: Center(
child: Container(
height: 200,
width: 200,
decoration: BoxDecoration(
color: Colors.yellow,
shape: BoxShape.circle,
),
),
),
);
複製代碼
List<BoxShadow>
能夠給容器添加陰影。
這個參數是一個列表,這樣你就能夠定義多種不一樣的陰影,而後將它們組合在一塊兒。
Scaffold(
appBar: AppBar(title: Text('boxShadow: List<BoxShadow>')),
body: Center(
child: Container(
height: 200,
width: 200,
decoration: BoxDecoration(
color: Colors.yellow,
boxShadow: const [
BoxShadow(blurRadius: 10),
],
),
),
),
);
複製代碼
有三種類型的漸變:LinearGradient
、RadialGradient
和 SweepGradient
。
Scaffold(
appBar: AppBar(title: Text('gradient: LinearGradient')),
body: Center(
child: Container(
height: 200,
width: 200,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: const [
Colors.red,
Colors.blue,
],
),
),
),
),
);
複製代碼
Scaffold(
appBar: AppBar(title: Text('gradient: RadialGradient')),
body: Center(
child: Container(
height: 200,
width: 200,
decoration: BoxDecoration(
gradient: RadialGradient(
colors: const [Colors.yellow, Colors.blue],
stops: const [0.4, 1.0],
),
),
),
),
);
複製代碼
Scaffold(
appBar: AppBar(title: Text('gradient: SweepGradient')),
body: Center(
child: Container(
height: 200,
width: 200,
decoration: BoxDecoration(
gradient: SweepGradient(
colors: const [
Colors.blue,
Colors.green,
Colors.yellow,
Colors.red,
Colors.blue,
],
stops: const [0.0, 0.25, 0.5, 0.75, 1.0],
),
),
),
),
);
複製代碼
backgroundBlendMode
是 BoxDecoration
中最複雜的屬性。 它能夠混合 BoxDecoration
的顏色和漸變,而且不管 BoxDecoration
在何種元素之上。
有了 backgroundBlendMode
,你可使用 BlendMode
枚舉類型中的一長串算法。
首先,配置 BoxDecoration
爲 foregroundDecoration
,它被渲染於 Container
子元素的上方(而 decoration
被渲染於子元素的後面)。
Scaffold(
appBar: AppBar(title: Text('backgroundBlendMode')),
body: Center(
child: Container(
height: 200,
width: 200,
foregroundDecoration: BoxDecoration(
backgroundBlendMode: BlendMode.exclusion,
gradient: LinearGradient(
colors: const [
Colors.red,
Colors.blue,
],
),
),
child: Image.network(
'https://flutter.io/images/catalog-widget-placeholder.png',
),
),
),
);
複製代碼
backgroundBlendMode
不只影響它所在的 Container
。
backgroundBlendMode
能改變從 Container
的部件樹中任意部件的顏色。 下面這段代碼中,有一個做爲父級元素的 Container
,它渲染了一張圖片 image
和一個使用了 backgroundBlendMode
的子元素 Container
。你仍舊會獲得和前一段代碼相同的效果。
Scaffold(
appBar: AppBar(title: Text('backgroundBlendMode')),
body: Center(
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(
'https://flutter.io/images/catalog-widget-placeholder.png',
),
),
),
child: Container(
height: 200,
width: 200,
foregroundDecoration: BoxDecoration(
backgroundBlendMode: BlendMode.exclusion,
gradient: LinearGradient(
colors: const [
Colors.red,
Colors.blue,
],
),
),
),
),
),
);
複製代碼
這是最簡單可是最有用的部件
SizedBox
能夠實現和 ConstrainedBox
類似的效果
SizedBox.expand(
child: Card(
child: Text('Hello World!'),
color: Colors.yellowAccent,
),
),
複製代碼
若是你須要添加內邊距或者外邊距,你能夠選擇 Padding
或者 Container
部件。可是它們都不如添加 Sizedbox
簡單易讀
Column(
children: <Widget>[
Icon(Icons.star, size: 50),
const SizedBox(height: 100),
Icon(Icons.star, size: 50),
Icon(Icons.star, size: 50),
],
),
複製代碼
不少時候你但願經過一個布爾值(bool
)來控制組件的顯示和隱藏
Widget build(BuildContext context) {
bool isVisible = ...
return Scaffold(
appBar: AppBar(
title: Text('isVisible = $isVisible'),
),
body: isVisible
? Icon(Icons.star, size: 150)
: const SizedBox(),
);
}
複製代碼
因爲 SizedBox
有一個 const
構造函數,使用 const SizedBox()
就變得很是簡單。
更簡單的解決方案是使用 Opacity
部件,而後將 opacity
的值改爲 0.0
。這個方案的缺點是雖然組件不可見,可是它依舊佔據空間。
在不一樣的平臺上,有不少特殊的位置,好比 Android 系統的狀態欄,或者 iPhone X 的「齊劉海」,咱們應該避免在這些位置放置元素。
解決方案就是使用 SafeArea
部件(下面的例子分別是使用和沒使用 SafeArea
的效果)
Widget build(BuildContext context) {
return Material(
color: Colors.blue,
child: SafeArea(
child: SizedBox.expand(
child: Card(color: Colors.yellowAccent),
),
),
);
}
複製代碼
更多內容敬請期待
若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。