Padding元件
在HTML中,常見的布局标簽都有padding屬性,但是在Flutter中,很多的widget是沒有padding屬性的。這時我們就可以使用padding元件來處理容器與子元素之間的間距。
Padding元件有兩個屬性:
- padding,EdgeInsets 設定填充的值
- child,子元件
先來看下面一段代碼:
class HomeContent extends StatelessWidget {
List<Widget> _getChildren(){
var children = listData.map((value){
return Image.network(value["imgUrl", fit: BoxFit.cover,);
});
return children.toList();
}
@override
Widget build(BuildContext context) {
return GridView.count(
crossAxisCount: 3,
children: this._getChildren(),
);
}
}
複制
這段代碼的運作效果如下:

可以看到,GridView的子元素是Image。現在我們想給圖檔元件加一些内邊距,但是Image元件是沒有padding屬性的,這個時候該怎麼辦呢?我們可以使用Padding元件。代碼如下:
class HomeContent extends StatelessWidget {
List<Widget> _getChildren() {
var children = listData.map((value) {
return Padding(//Padding元件
child: Image.network(
value["imgUrl"],
fit: BoxFit.cover,
),
padding: EdgeInsets.fromLTRB(10, 10, 0, 0),
);
});
return children.toList();
}
@override
Widget build(BuildContext context) {
return Padding(//Padding元件
padding: EdgeInsets.fromLTRB(0, 0, 10, 10),
child: GridView.count(
crossAxisCount: 3,
children: this._getChildren(),
),
);
}
}
複制
效果如下:
對于一些沒有padding屬性的元件,比如Image,我們可以在其外部包一個Padding元件,來實作内邊距padding的效果。
如何自定義一個元件
自定義一個元件無非就是三步:
- 實作build方法來定義元件的樣式和布局;
- 聲明需要傳入的相關屬性;
- 實作構造方法
下面是自定義一個名為IconContainer的元件:
class IconContainer extends StatelessWidget {
//聲明屬性
Color bgColor = Colors.yellow;
double iconSize = 16;
IconData iconname = Icons.home;
//構造方法(使用大括号包起來的都是可選命名參數)
IconContainer({this.bgColor, this.iconname, this.iconSize});
//build方法
@override
Widget build(BuildContext context) {
return Container(
height: 100,
width: 100,
color: this.bgColor,
child: Center(
child: Icon(this.iconname, size: this.iconSize, color: Colors.white,),
),
);
}
}
複制
Row 水準布局元件
Row元件有如下三個屬性:
- mainAxisAlignment,主軸的排列方式
- crossAxisAlignment,交叉軸的排列方式
- children,元件子元素
class HomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: 300,
height: 500,
color: Colors.pink,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, //調整主軸的排列方式(常用)
crossAxisAlignment: CrossAxisAlignment.center, //調整交叉軸的排列方式(用的比較少)
children: <Widget>[
IconContainer(Colors.green, Icons.date_range, 30),
IconContainer(Colors.red, Icons.edit_location, 35),
IconContainer(Colors.yellow, Icons.fast_rewind, 40),
],
),
);
}
}
複制
效果如下:
Column 垂直布局元件
Colume元件與Row元件的使用方式一模一樣:
class HomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: 300,
height: 500,
color: Colors.pink,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, //調整主軸的排列方式(常用)
crossAxisAlignment: CrossAxisAlignment.end, //調整交叉軸的排列方式(用的比較少)
children: <Widget>[
IconContainer(Colors.green, Icons.date_range, 30),
IconContainer(Colors.red, Icons.edit_location, 35),
IconContainer(Colors.yellow, Icons.fast_rewind, 40),
],
),
);
}
}
複制
效果如下:
Expanded 元件
Expanden元件可以用在Row和Column布局中,有如下兩個屬性:
- flex,元素占整個父 Row/Column 的比例
- child,子元素
Row(
children: <Widget>[
Expanded(
flex: 1,
child: IconContainer(Colors.pink, Icons.fast_rewind, 30),
),
Expanded(
flex: 2,
child: IconContainer(Colors.orange, Icons.hdr_strong, 40),
),
Expanded(
flex: 1,
child: IconContainer(Colors.blue, Icons.screen_lock_rotation, 50),
),
],
);
複制
效果如下:
此外,我們也可以使用Expanded元件實作寬度或者高度的自适應。如下所示:
Row(
children: <Widget>[
Expanded(
flex: 1,
child: IconContainer(Colors.pink, Icons.fast_rewind, 30),
),
IconContainer(Colors.orange, Icons.hdr_strong, 40),
],
);
複制
效果如下:
其他
可以使用SizedBox元件來定義元件的間隔。
Stack
Stack是堆的意思,有如下兩個參數:
- alignment,配置所有子元素的顯示位置
- children,子元件
Stack元件可以單獨使用。當其子元素隻有一個,或者隻有少數個元素并且這些子元素的布局是統一的,此時就可以 單獨使用Stack進行布局。如下所示:
Container(
height: 400,
width: 300,
color: Colors.yellow,
child: Stack(
alignment: Alignment(0, 0),//這裡的效果是,使children裡面d額所有元素都居中展示
children: <Widget>[
Image.network(
"http://pic27.nipic.com/20130325/11918471_071536564166_2.jpg"),
Text(
"666888",
style: TextStyle(color: Colors.white, fontSize: 20),
),
],
),
);
複制
效果如下:
但一個容器中有多個元素,而這些元素各有各自不同的布局的時候,可以使用Stack結合Align或者Stack結合Positioned來實作。
Stack & Align
Container(
height: 400,
width: 300,
color: Colors.yellow,
child: Stack(
alignment: Alignment(0, 0),
children: <Widget>[
Align(
alignment: Alignment.topLeft,
child: IconContainer(Colors.red, Icons.aspect_ratio, 30),
),
Align(
alignment: Alignment.topRight,
child: IconContainer(Colors.blue, Icons.sd_card, 40),
),
Align(
child: IconContainer(Colors.green, Icons.data_usage, 50),
),
],
),
);
複制
通過Stack結合ALign可以控制Stack元件内部的每個元素的具體位置。Stack的alignment可以控制所有子元素的布局,Align的alignment屬性可以控制某個具體子元素的布局,如果兩者同時存在,則以Align的alignment屬性為準。上述代碼的效果如下:
Stack & Positioned
Container(
height: 200,
width: 300,
color: Colors.yellow,
child: Stack(
children: <Widget>[
Align(
alignment: Alignment.center,
child: Container(
child: Image.network(
"http://pic27.nipic.com/20130325/11918471_071536564166_2.jpg",
fit: BoxFit.cover,
),
),
),
Positioned(
left: 10,
bottom: 10,
right: 10,
child: Text(
"http://pic27.nipic.com/20130325/11918471_071536564166_2.jpg",
style: TextStyle(color: Colors.white, fontSize: 18),
),
)
],
),
);
複制
效果圖如下:
AspectRatio
AspectRatio的作用是根據設定調整子元素child的寬高比。
AspectRatio首先會在布局限制條件允許的範圍内盡可能地擴充,Widget的寬度(高度)由高度(寬度)和比率決定,類似于BoxFit中的contain,按照固定比率去盡量占滿區域。
AspectRatio有如下兩個屬性:
- aspectRatio,寬高比
- child,子元件
如下代碼:
Container(
width: 300,
child: AspectRatio(
aspectRatio: 2,
child: Container(
color: Colors.red,
),
),
);
複制
展示效果為:
Card
Card是卡片元件塊,内容可以由大多數類型的Widget構成。Card具有圓角和陰影,這讓它看起來具有立體感。
Card有如下三個屬性:
- margin,外邊距
- child,子元件
- shape,Card的陰影效果,預設的陰影效果為圓角的長方形邊
如下面代碼:
ListView(
children: <Widget>[
Card(
margin: EdgeInsets.all(10),
child: Column(
children: <Widget>[
ListTile(
title: Text(
"張三",
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
subtitle: Text("進階軟體工程師"),
),
ListTile(
title: Text("電話:13241668866"),
),
ListTile(
title: Text("位址:北京市海澱區"),
)
],
),
),
Card(
margin: EdgeInsets.all(10),
child: Column(
children: <Widget>[
ListTile(
title: Text(
"李四",
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
subtitle: Text("進階軟體工程師"),
),
ListTile(
title: Text("電話:13241668866"),
),
ListTile(
title: Text("位址:北京市海澱區"),
)
],
),
),
Card(
margin: EdgeInsets.all(10),
child: Column(
children: <Widget>[
ListTile(
title: Text(
"王武",
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
subtitle: Text("進階軟體工程師"),
),
ListTile(
title: Text("電話:13241668866"),
),
ListTile(
title: Text("位址:北京市海澱區"),
)
],
),
)
],
);
複制
效果如下:
下面再來看一個例子,代碼如下:
class HomeContent extends StatelessWidget {
Widget _getItem(context, index) {
Map itemdata = listData[index];
return Card(
margin: EdgeInsets.all(10),
child: Column(
children: <Widget>[
AspectRatio(
aspectRatio: 2,
child: Image.network(
itemdata["imgUrl"],
fit: BoxFit.cover,
),
),
ListTile(
leading: CircleAvatar(
backgroundImage: NetworkImage(itemdata["imgUrl"]),
),
title: Text(itemdata["title"]),
subtitle: Text(itemdata["detail"]),
)
],
),
);
}
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: listData.length,
itemBuilder: this._getItem,
);
}
}
複制
效果如下:
關于上面這個例子,有如下幾點說明。
圖檔的圓角,我們可以使用ClipOval元件,也可以使用該例中的CircleAvator元件。
可以使用AspectRatio元件來實作元件固定的寬高比。
Wrap
Wrap可以實作流布局,單行的Wrap跟Row表現幾乎一緻,單列的Wrap跟Column表現幾乎一緻。但是Row與Column都是單行單列的,Wrap則突破了這個限制,mainAxis上空間不足時,則向crossAxis上去擴充展示。
Wrap有如下常用屬性:
- direction,主軸的方向,預設是水準
- alignment,主軸的對齊方式
- spacing,主軸方向上的間距
- runSpacing,交叉軸方向上的間距
class HomeContent extends StatelessWidget {
List<Widget> _getChildren() {
var children = listData.map((value) {
return MyButton(value["title"]);
});
return children.toList();
}
@override
Widget build(BuildContext context) {
return Wrap(
children: this._getChildren(),
alignment: WrapAlignment.start, //主軸方向上的對齊方式
spacing: 30, //主軸方向上的間距
runSpacing: 10, //交叉軸方向上的間距
);
}
}
class MyButton extends StatelessWidget {
final String titleStr;
MyButton(this.titleStr);
@override
Widget build(BuildContext context) {
return RaisedButton(
child: Text(this.titleStr),
onPressed: () {
print(Text(this.titleStr));
},
);
}
}
複制
顯示效果如下:
以上。