做自(zì)由與創造的先行者

Flutter 構建布局

Flutter開(kāi)發手冊

第0步: 設置

首先, 獲取代碼:

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

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

接下(xià)來(lái),将圖像添加到(dào)示例中:

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

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

更新 pubspec.yaml 文(wén)件以包含 assets 标簽. 這(zhè)樣才會(huì)使您的圖片在代碼中可用(yòng)。

第一步: 繪制布局圖

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

找出行和(hé)列.

布局包含網格嗎?

有重疊的元素嗎?

是否需要選項卡?

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

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

接下(xià)來(lái),繪制每一行。第一行稱其爲标題部分,有三個子項:一列文(wén)字,一個星形圖标和(hé)一個數字。它的第一個子項,列,包含2行文(wén)字。 第一列占用(yòng)大(dà)量空(kōng)間,所以它必須包裝在Expanded widget中。

第二行稱其爲按鈕部分,也(yě)有3個子項:每個子項都是一個包含圖标和(hé)文(wén)本的列。

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

Step 2: 實現(xiàn)标題行

首先,構建标題部分左邊欄。将Column(列)放(fàng)入Expanded中會(huì)拉伸該列以使用(yòng)該行中的所有剩餘空(kōng)閑空(kōng)間。 設置crossAxisAlignment屬性值爲CrossAxisAlignment.start,這(zhè)會(huì)将該列中的子項左對(duì)齊。

将第一行文(wén)本放(fàng)入Container中,然後底部添加8像素填充。列中的第二個子項(也(yě)是文(wén)本)顯示爲灰色。

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

這(zhè)是實現(xiàn)标題行的代碼。

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'),

],

),

);

//...

}

提示: 将代碼粘貼到(dào)應用(yòng)程序中時(shí),縮進可能(néng)會(huì)變形。您可以通過右鍵單擊,選擇 Reformat with dartfmt 來(lái)在IntelliJ中修複此問題。或者,在命令行中,您可以使用(yòng) dartfmt。

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

第3步: 實現(xiàn)按鈕行

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

class MyApp extends StatelessWidget {

@override

Widget build(BuildContext context) {

//...

return new MaterialApp(

title: 'Flutter Demo',

theme: new ThemeData(

primarySwatch: Colors.blue,

),

//...

}

由于構建每個列的代碼幾乎是相同的,因此使用(yòng)一個嵌套函數,如buildButtonColumn,它會(huì)創建一個顔色爲primary color,包含一個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,

),

),

),

],

);

}

//...

}

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

通過調用(yòng)函數并傳遞icon和(hé)文(wén)本來(lái)構建這(zhè)些(xiē)列。然後在行的主軸方向通過 MainAxisAlignment.spaceEvenly 平均的分配每個列占據的行空(kōng)間。

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步:實現(xiàn)文(wén)本部分

将文(wén)本放(fàng)入容器中,以便沿每條邊添加32像素的填充。softwrap屬性表示文(wé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àn)圖像部分

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

body: new ListView(

children: [

new Image.asset(

'images/lake.jpg',

height: 240.0,

fit: BoxFit.cover,

),

// ...

],

)

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

Step 6: 整合

在最後一步,你(nǐ)将上(shàng)面這(zhè)些(xiē)組裝在一起。這(zhè)些(xiē)widget放(fàng)置到(dào)ListView中,而不是列中,因爲在小(xiǎo)設備上(shàng)運行應用(yòng)程序時(shí),ListView會(huì)自(zì)動滾動。

//...

body: new ListView(

children: [

new Image.asset(

'images/lake.jpg',

width: 600.0,

height: 240.0,

fit: BoxFit.cover,

),

titleSection,

buttonSection,

textSection,

],

),

//...

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