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

Flutter 構建布局

Flutter開(kāi)發手冊

第0步: 設置

首先, 獲取代碼:

确保您已經安裝好了(le) set up 您的Flutter環境.

創建一(yī)個基本的Flutter應用程序.

接下(xià)來,将圖像添加到示例中:

在工(gōng)程根目錄創建一(yī)個 images 文件夾.

添加一(yī)張圖片. (請(qǐng)注意,wget不能(néng)保存此二進制文件。)

更新 pubspec.yaml 文件以包含 assets 标簽. 這(zhè)樣才會使您的圖片在代碼中可(kě)用。

第一(yī)步: 繪制布局圖

第一(yī)步是将布局拆分成基本的元素:

找出行(xíng)和(hé)列.

布局包含網格嗎?

有重疊的元素嗎?

是否需要(yào)選項卡?

注意需要(yào)對齊、填充和(hé)邊框的區(qū)域.

首先,确定更大的元素。在這(zhè)個例子中,四個元素排列成一(yī)列:一(yī)個圖像,兩個行(xíng)和(hé)一(yī)個文本塊

接下(xià)來,繪制每一(yī)行(xíng)。第一(yī)行(xíng)稱其為(wèi)标題部分,有三個子項:一(yī)列文字,一(yī)個星形圖标和(hé)一(yī)個數(shù)字。它的第一(yī)個子項,列,包含2行(xíng)文字。 第一(yī)列占用大量空間(jiān),所以它必須包裝在Expanded widget中。

第二行(xíng)稱其為(wèi)按鈕部分,也有3個子項:每個子項都(dōu)是一(yī)個包含圖标和(hé)文本的列。

一(yī)旦拆分好布局,最簡單的就是采取自(zì)下(xià)而上(shàng)的方法來實現它。為(wèi)了(le)最大限度地(dì)減少(shǎo)深度嵌套布局代碼的視(shì)覺混淆,将一(yī)些實現放置在變量和(hé)函數(shù)中。

Step 2: 實現标題行(xíng)

首先,構建标題部分左邊欄。将Column(列)放入Expanded中會拉伸該列以使用該行(xíng)中的所有剩餘空閑空間(jiān)。 設置crossAxisAlignment屬性值為(wèi)CrossAxisAlignment.start,這(zhè)會将該列中的子項左對齊。

将第一(yī)行(xíng)文本放入Container中,然後底部添加8像素填充。列中的第二個子項(也是文本)顯示為(wèi)灰色。

标題行(xíng)中的最後兩項是一(yī)個紅(hóng)色的星形圖标和(hé)文字“41”。将整行(xíng)放在容器中,并沿着每個邊緣填充32像素

這(zhè)是實現标題行(xíng)的代碼。

Note: If you have problems, you can check your code against lib/main.dart on GitHub.

class MyApp extends StatelessWidget {

@override

Widget build(BuildContext context) {

Widget titleSection = new Container(

padding: const EdgeInsets.all(32.0),

child: new Row(

children: [

new Expanded(

child: new Column(

crossAxisAlignment: CrossAxisAlignment.start,

children: [

new Container(

padding: const EdgeInsets.only(bottom: 8.0),

child: new Text(

'Oeschinen Lake Campground',

style: new TextStyle(

fontWeight: FontWeight.bold,

),

),

),

new Text(

'Kandersteg, Switzerland',

style: new TextStyle(

color: Colors.grey[500],

),

),

],

),

),

new Icon(

Icons.star,

color: Colors.red[500],

),

new Text('41'),

],

),

);

//...

}

提示: 将代碼粘貼到應用程序中時(shí),縮進可(kě)能(néng)會變形。您可(kě)以通(tōng)過右鍵單擊,選擇 Reformat with dartfmt 來在IntelliJ中修複此問(wèn)題。或者,在命令行(xíng)中,您可(kě)以使用 dartfmt。

提示: 為(wèi)了(le)獲得更快(kuài)的開(kāi)發體驗,請(qǐng)嘗試使用Flutter的熱(rè)重載功能(néng)。 熱(rè)重載允許您修改代碼并查看(kàn)更改,而無需完全重新啓動應用程序。 IntelliJ的Flutter插件支持熱(rè)重載,或者您可(kě)以從(cóng)命令行(xíng)觸發。 有關更多信息,請(qǐng)參閱Hot Reloads vs 應用程序重新啓動。

第3步: 實現按鈕行(xíng)

按鈕部分包含3個使用相同布局的列 - 上(shàng)面一(yī)個圖标,下(xià)面一(yī)行(xíng)文本。該行(xíng)中的列平均分布行(xíng)空間(jiān), 文本和(hé)圖标顔色為(wèi)主題中的primary color,它在應用程序的build()方法中設置為(wèi)藍(lán)色:

class MyApp extends StatelessWidget {

@override

Widget build(BuildContext context) {

//...

return new MaterialApp(

title: 'Flutter Demo',

theme: new ThemeData(

primarySwatch: Colors.blue,

),

//...

}

由于構建每個列的代碼幾乎是相同的,因此使用一(yī)個嵌套函數(shù),如(rú)buildButtonColumn,它會創建一(yī)個顔色為(wèi)primary color,包含一(yī)個Icon和(hé)Text的 Widget 列。

class MyApp extends StatelessWidget {

@override

Widget build(BuildContext context) {

//...

Column buildButtonColumn(IconData icon, String label) {

Color color = Theme.of(context).primaryColor;

return new Column(

mainAxisSize: MainAxisSize.min,

mainAxisAlignment: MainAxisAlignment.center,

children: [

new Icon(icon, color: color),

new Container(

margin: const EdgeInsets.only(top: 8.0),

child: new Text(

label,

style: new TextStyle(

fontSize: 12.0,

fontWeight: FontWeight.w400,

color: color,

),

),

),

],

);

}

//...

}

構建函數(shù)将圖标直接添加到列(Column)中。将文本放入容器以在文本上(shàng)方添加填充,将其與圖标分開(kāi)。

通(tōng)過調用函數(shù)并傳遞icon和(hé)文本來構建這(zhè)些列。然後在行(xíng)的主軸方向通(tōng)過 MainAxisAlignment.spaceEvenly 平均的分配每個列占據的行(xíng)空間(jiān)。

class MyApp extends StatelessWidget {

@override

Widget build(BuildContext context) {

//...

Widget buttonSection = new Container(

child: new Row(

mainAxisAlignment: MainAxisAlignment.spaceEvenly,

children: [

buildButtonColumn(Icons.call, 'CALL'),

buildButtonColumn(Icons.near_me, 'ROUTE'),

buildButtonColumn(Icons.share, 'SHARE'),

],

),

);

//...

}

第4步:實現文本部分

将文本放入容器中,以便沿每條邊添加32像素的填充。softwrap屬性表示文本是否應在軟換行(xíng)符(例如(rú)句點或逗号)之間(jiān)斷開(kāi)。

class MyApp extends StatelessWidget {

@override

Widget build(BuildContext context) {

//...

Widget textSection = new Container(

padding: const EdgeInsets.all(32.0),

child: new Text(

'''

Lake Oeschinen lies at the foot of the Blüemlisalp in the Bernese Alps. Situated 1,578 meters above sea level, it is one of the larger Alpine Lakes. A gondola ride from Kandersteg, followed by a half-hour walk through pastures and pine forest, leads you to the lake, which warms to 20 degrees Celsius in the summer. Activities enjoyed here include rowing, and riding the summer toboggan run.

''',

softWrap: true,

),

);

//...

}

第5步:實現圖像部分

四列元素中的三個現在已經完成,隻剩下(xià)圖像部分。該圖片可(kě)以在Creative Commons許可(kě)下(xià)在線獲得, 但(dàn)是它非常大,且下(xià)載緩慢(màn)。在步驟0中,您已經将該圖像包含在項目中并更新了(le)pubspec文件,所以現在可(kě)以從(cóng)代碼中直接引用它:

body: new ListView(

children: [

new Image.asset(

'images/lake.jpg',

height: 240.0,

fit: BoxFit.cover,

),

// ...

],

)

BoxFit.cover 告訴框架,圖像應該盡可(kě)能(néng)小,但(dàn)覆蓋整個渲染框

Step 6: 整合

在最後一(yī)步,你将上(shàng)面這(zhè)些組裝在一(yī)起。這(zhè)些widget放置到ListView中,而不是列中,因為(wèi)在小設備上(shàng)運行(xíng)應用程序時(shí),ListView會自(zì)動滾動。

//...

body: new ListView(

children: [

new Image.asset(

'images/lake.jpg',

width: 600.0,

height: 240.0,

fit: BoxFit.cover,

),

titleSection,

buttonSection,

textSection,

],

),

//...

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