做(zuò)自(zì)由與創造的先行(xíng)者

Flutter 布局多個widgets

Flutter開(kāi)發手冊

垂直和(hé)水平放置多個widget

最常見(jiàn)的布局模式之一(yī)是垂直或水平排列widget。您可(kě)以使用行(xíng)(Row)水平排列widget,并使用列(Column)垂直排列widget。

重點是什麽?

行(xíng)和(hé)列是兩種最常用的布局模式。

行(xíng)和(hé)列都(dōu)需要(yào)一(yī)個子widget列表。

子widget本身可(kě)以是行(xíng)、列或其他(tā)複雜(zá)widget。

您可(kě)以指定行(xíng)或列如(rú)何在垂直或水平方向上(shàng)對齊其子項

您可(kě)以拉伸或限制特定的子widget.

您可(kě)以指定子widget如(rú)何使用行(xíng)或列的可(kě)用空間(jiān).

要(yào)在Flutter中創建行(xíng)或列,可(kě)以将一(yī)個widget列表添加到Row 或Column 中。 同時(shí),每個孩子本身可(kě)以是一(yī)個Row或一(yī)個Column,依此類推。以下(xià)示例顯示如(rú)何在行(xíng)或列內(nèi)嵌套行(xíng)或列。

注意:行(xíng)和(hé)列是水平和(hé)垂直布局的基本、低(dī)級widget - 這(zhè)些低(dī)級widget允許最大化的自(zì)定義。Flutter還提供專門的,更高級别的widget,可(kě)能(néng)足以滿足您的需求。 例如(rú),您可(kě)能(néng)更喜歡ListTile而不是Row,ListTile是一(yī)個易于使用的小部件,具有前後圖标屬性以及最多3行(xíng)文本。您可(kě)能(néng)更喜歡ListView而不是列,ListView是一(yī)種列狀布局,如(rú)果其內(nèi)容太長(cháng)而無法适應可(kě)用空間(jiān),則會自(zì)動滾動。 有關更多信息,請(qǐng)參閱通(tōng)用布局widget。

對齊 widgets

您可(kě)以控制行(xíng)或列如(rú)何使用mainAxisAlignment和(hé)crossAxisAlignment屬性來對齊其子項。 對于行(xíng)(Row)來說,主軸是水平方向,橫軸垂直方向。對于列(Column)來說,主軸垂直方向,橫軸水平方向。

MainAxisAlignment 和(hé)CrossAxisAlignment 類提供了(le)很(hěn)多控制對齊的常量.

注意: 将圖片添加到項目時(shí),需要(yào)更新pubspec文件才能(néng)訪問(wèn)它們 - 此示例使用Image.asset顯示圖像。 有關更多信息,請(qǐng)參閱此示例的pubspec.yaml文件, 或在Flutter中添加資源和(hé)圖像。如(rú)果您使用的是網上(shàng)的圖片,則不需要(yào)執行(xíng)此操作(zuò),使用Image.network即可(kě)。

在以下(xià)示例中,3個圖像中的每一(yī)個都(dōu)是100像素寬。渲染盒(在這(zhè)種情況下(xià),整個屏幕)寬度超過300個像素, 因此設置主軸對齊方式為(wèi)spaceEvenly,它會在每個圖像之間(jiān),之前和(hé)之後均勻分配空閑的水平空間(jiān)。

appBar: new AppBar(

title: new Text(widget.title),

),

body: new Center(

child: new Row(

mainAxisAlignment: MainAxisAlignment.spaceEvenly,

children: [

new Image.asset('images/pic1.jpg'),

Dart code: main.dartImages: imagesPubspec: pubspec.yaml

列的工(gōng)作(zuò)方式與行(xíng)相同。以下(xià)示例顯示了(le)一(yī)列,包含3個圖片,每個圖片高100個像素。 渲染盒(在這(zhè)種情況下(xià),整個屏幕)的高度大于300像素,因此設置主軸對齊方式為(wèi)spaceEvenly,它會在每個圖像之間(jiān),上(shàng)方和(hé)下(xià)方均勻分配空閑的垂直空間(jiān)。

appBar: new AppBar(

title: new Text(widget.title),

),

body: new Center(

child: new Column(

mainAxisAlignment: MainAxisAlignment.spaceEvenly,

children: [

new Image.asset('images/pic1.jpg'),

Dart code: main.dartImages: imagesPubspec: pubspec.yaml

調整 widget

也許你想要(yào)一(yī)個widget占據其兄弟widget兩倍的空間(jiān)。您可(kě)以将行(xíng)或列的子項放置在Expandedwidget中, 以控制沿着主軸方向的widget大小。Expanded widget具有一(yī)個flex屬性,它是一(yī)個整數(shù),用于确定widget的彈性系數(shù),默認彈性系數(shù)是1。

例如(rú),要(yào)創建一(yī)個由三個widget組成的行(xíng),其中中間(jiān)widget的寬度是其他(tā)兩個widget的兩倍,将中間(jiān)widget的彈性系數(shù)設置為(wèi)2:

appBar: new AppBar(

title: new Text(widget.title),

),

body: new Center(

child: new Row(

crossAxisAlignment: CrossAxisAlignment.center,

children: [

new Expanded(

child: new Image.asset('images/pic1.jpg'),

),

new Expanded(

flex: 2,

child: new Image.asset('images/pic2.jpg'),

),

new Expanded(

a row of 3 images with the middle image twice as wide as the others

Dart code: main.dartImages: imagesPubspec: pubspec.yaml

要(yào)修複上(shàng)一(yī)節中的示例:其中一(yī)行(xíng)有3張圖片,行(xíng)對于其渲染框太寬,并且導緻右邊出現紅(hóng)色條中的問(wèn)題,可(kě)以使用Expanded widget來包裝每個widget。 默認情況下(xià),每個widget的彈性系數(shù)為(wèi)1,将行(xíng)的三分之一(yī)分配給每個小部件。

appBar: new AppBar(

title: new Text(widget.title),

),

body: new Center(

child: new Row(

crossAxisAlignment: CrossAxisAlignment.center,

children: [

new Expanded(

child: new Image.asset('images/pic1.jpg'),

),

new Expanded(

child: new Image.asset('images/pic2.jpg'),

),

new Expanded(

聚集 widgets

默認情況下(xià),行(xíng)或列沿着其主軸會盡可(kě)能(néng)占用盡可(kě)能(néng)多的空間(jiān),但(dàn)如(rú)果要(yào)将孩子緊密聚集在一(yī)起,可(kě)以将mainAxisSize設置為(wèi)MainAxisSize.min。 以下(xià)示例使用此屬性将星形圖标聚集在一(yī)起(如(rú)果不聚集,五張星形圖标會分散開(kāi))。

class _MyHomePageState extends State {

@override

Widget build(BuildContext context) {

var packedRow = new Row(

mainAxisSize: MainAxisSize.min,

children: [

new Icon(Icons.star, color: Colors.green[500]),

new Icon(Icons.star, color: Colors.green[500]),

new Icon(Icons.star, color: Colors.green[500]),

new Icon(Icons.star, color: Colors.black),

new Icon(Icons.star, color: Colors.black),

],

);

// ...

}

嵌套行(xíng)和(hé)列

布局框架允許您根據需要(yào)在行(xíng)和(hé)列內(nèi)部再嵌套行(xíng)和(hé)列。

該ratings變量創建一(yī)個包含5個星形圖标和(hé)一(yī)個文本的行(xíng):

class _MyHomePageState extends State {

@override

Widget build(BuildContext context) {

//...

var ratings = new Container(

padding: new EdgeInsets.all(20.0),

child: new Row(

mainAxisAlignment: MainAxisAlignment.spaceEvenly,

children: [

new Row(

mainAxisSize: MainAxisSize.min,

children: [

new Icon(Icons.star, color: Colors.black),

new Icon(Icons.star, color: Colors.black),

new Icon(Icons.star, color: Colors.black),

new Icon(Icons.star, color: Colors.black),

new Icon(Icons.star, color: Colors.black),

],

),

new Text(

'170 Reviews',

style: new TextStyle(

color: Colors.black,

fontWeight: FontWeight.w800,

fontFamily: 'Roboto',

letterSpacing: 0.5,

fontSize: 20.0,

),

),

],

),

);

//...

}

}

提示: 為(wèi)了(le)最大限度地(dì)減少(shǎo)由嵌套嚴重的布局代碼導緻的視(shì)覺混淆,可(kě)以在變量和(hé)函數(shù)中實現UI的各個部分。

該iconList變量定義了(le)圖标行(xíng):

class _MyHomePageState extends State {

@override

Widget build(BuildContext context) {

// ...

var descTextStyle = new TextStyle(

color: Colors.black,

fontWeight: FontWeight.w800,

fontFamily: 'Roboto',

letterSpacing: 0.5,

fontSize: 18.0,

height: 2.0,

);

// DefaultTextStyle.merge可(kě)以允許您創建一(yī)個默認的文本樣式,該樣式會被其

// 所有的子節點繼承

var iconList = DefaultTextStyle.merge(

style: descTextStyle,

child: new Container(

padding: new EdgeInsets.all(20.0),

child: new Row(

mainAxisAlignment: MainAxisAlignment.spaceEvenly,

children: [

new Column(

children: [

new Icon(Icons.kitchen, color: Colors.green[500]),

new Text('PREP:'),

new Text('25 min'),

],

),

new Column(

children: [

new Icon(Icons.timer, color: Colors.green[500]),

new Text('COOK:'),

new Text('1 hr'),

],

),

new Column(

children: [

new Icon(Icons.restaurant, color: Colors.green[500]),

new Text('FEEDS:'),

new Text('4-6'),

],

),

],

),

),

);

// ...

}

}

該leftColumn變量包含評分和(hé)圖标行(xíng),以及描述Pavlova的标題和(hé)文字:

class _MyHomePageState extends State {

@override

Widget build(BuildContext context) {

//...

var leftColumn = new Container(

padding: new EdgeInsets.fromLTRB(20.0, 30.0, 20.0, 20.0),

child: new Column(

children: [

titleText,

subTitle,

ratings,

iconList,

],

),

);

//...

}

}

左列放置在容器中以約束其寬度。最後,用整個行(xíng)(包含左列和(hé)圖像)放置在一(yī)個Card內(nèi)構建UI:

Pavlova圖片來自(zì) Pixabay ,可(kě)以在Creative Commons許可(kě)下(xià)使用。 您可(kě)以使用Image.network直接從(cóng)網上(shàng)下(xià)載顯示圖片,但(dàn)對于此示例,圖像保存到項目中的圖像目錄中,添加到pubspec文件, 并使用Images.asset。 有關更多信息,請(qǐng)參閱在Flutter中添加Asserts和(hé)圖片。

body: new Center(

child: new Container(

margin: new EdgeInsets.fromLTRB(0.0, 40.0, 0.0, 30.0),

height: 600.0,

child: new Card(

child: new Row(

crossAxisAlignment: CrossAxisAlignment.start,

children: [

new Container(

width: 440.0,

child: leftColumn,

),

mainImage,

],

),

),

),

),

Dart code: main.dartImages: imagesPubspec: pubspec.yaml

提示: Pavlova示例在廣泛的橫屏設備(如(rú)平闆電腦)上(shàng)運行(xíng)最佳。如(rú)果您在iOS模拟器中運行(xíng)此示例, 則可(kě)以使用Hardware > Device菜單選擇其他(tā)設備。對于這(zhè)個例子,我們推薦iPad Pro。 您可(kě)以使用Hardware > Rotate将其方向更改為(wèi)橫向模式 。您還可(kě)以使用Window > Scale更改模拟器窗口的大小(不更改邏輯像素的數(shù)量)

網站建設開(kāi)發|APP設計開(kāi)發|小程序建設開(kāi)發
下(xià)一(yī)篇:Flutter 常用布局widgets
上(shàng)一(yī)篇:Flutter 布局方法