Flutter中構建佈局

你將學到什麼?html

  • Flutter的佈局機制如何工做。
  • 如何垂直和水平佈局小部件。
  • 如何構建一個Flutter佈局。

這是在Flutter中構建佈局的指南。 您將構建如下屏幕截圖的佈局:java

而後本指南迴過頭來解釋Flutter的佈局方法,並說明如何在屏幕上放置一個小部件。 在討論如何水平和垂直放置小部件以後,會介紹一些最多見的佈局小部件。git

創建佈局github

  • 第0步:設置
  • 第1步:繪製佈局圖
  • 第2步:實施標題行
  • 第3步:實現按鈕行
  • 第4步:實現文本部分
  • 第5步:實現圖像部分
  • 第6步:把它放在一塊兒

Flutter的佈局方法
佈置一個小部件
垂直和水平放置多個小部件web

  • 對齊小部件
  • 調整小部件
  • 包裝小部件
  • 嵌套行和列

常見的佈局小部件編程

  • 標準小部件
  • 材料組件

資源瀏覽器

創建佈局

若是您想要了解佈局機制的「全貌」,請從Flutter的佈局方法開始。網絡

第0步:設置

首先,獲取代碼:app

接下來,將圖像添加到示例中:框架

  • 在項目頂部建立一個images目錄。
  • 添加lake.jpg。 (請注意,wget沒法保存此二進制文件。)
  • 更新pubspec.yaml文件以包含assets標籤。 這會使圖像可用於您的代碼。

第1步:繪製佈局圖

第一步是將佈局打破成其基本要素:

  • 識別行和列。
  • 佈局是否包含網格?
  • 有重疊的元素嗎?
  • 用戶界面是否須要選項卡?
  • 注意須要對齊,填充或邊框的區域。

首先,肯定更大的元素。 在這個例子中,四個元素排列成一列:一個圖像,兩行和一個文本塊。

接下來,繪製每一行。 第一行稱爲標題部分,有三個孩子:一列文字,一個星形圖標和一個數字。 它的第一個孩子,列,包含2行文字。 第一列佔用大量空間,因此它必須包裝在擴展小部件中。

第二行稱爲按鈕部分,也有3個子項:每一個子項都是一個包含圖標和文本的列。

一旦佈局結束,最簡單的就是採起自下而上的方法來實現它。 爲了最大限度地減小深度嵌套佈局代碼的視覺混淆,將一些實現放置在變量和函數中。

第2步:實現標題行

首先,您將在標題部分構建左欄。 將列放入擴展窗口小部件中會拉伸該列以使用該行中的全部剩餘空閒空間。 將crossAxisAlignment屬性設置爲CrossAxisAlignment.start可將列置於行的開始位置。

將第一行文本放入Container中能夠添加填充。 列中的第二個子項(也是文本)顯示爲灰色。

標題行中的最後兩項是一個紅色的星形圖標和文字「41」。 將整行放在容器中,並沿着每一個邊緣填充32像素。

這是實現標題行的代碼。

注意:若是有什麼問題,對照GitHub上的lib/main.dart檢查代碼 

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'),
        ],
      ),
    );
  //...
}

提示:將代碼粘貼到應用程序中時,縮進可能會變形。 您能夠經過右鍵單擊Dart代碼並選擇使用Reformat with Dart Style來在IntelliJ中修復此問題。 或者,在命令行中,您可使用dartfmt

提示:爲了得到更快的開發體驗,請嘗試使用Flutter的熱從新加載功能。 熱從新加載容許您修改代碼並查看更改,而無需徹底從新啓動應用程序。 IntelliJ的Flutter插件支持熱重載,或者您能夠從命令行觸發。 有關更多信息,請參閱Hot Reloads與完整應用程序從新啓動

第3步:實現按鈕行

按鈕部分包含3列,它們使用相同的佈局 - 一行文本上的圖標。 此行中的列均勻分佈,文本和圖標用主顏色繪製,在應用程序的build()方法中將其設置爲藍色:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //...

    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),

    //...
}

因爲構建每一行的代碼幾乎是相同的,所以建立一個嵌套函數(如buildButtonColumn()(它接受一個Icon和Text)並返回一個列以其主要顏色繪製的小部件的效率最高。

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,
              ),
            ),
          ),
        ],
      );
    }
  //...
}

構建函數將圖標直接添加到列中。 將文本放入容器以在文本上方添加填充,將其與圖標分開。

經過調用函數並傳遞特定於該列的圖標和文原本構建包含這些列的行。 使用MainAxisAlignment.spaceEvenly沿着主軸對齊列,以在每列以前,之間和以後均勻排列空閒空間。

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屬性指示文本是否應在軟換行符(如句點或逗號)上斷開。

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步:實現圖像部分

四列元素中的三個如今完成,只留下圖像。 該圖片能夠在Creative Commons許可下在線得到,可是它大並且緩慢。 在步驟0中,您將該圖像包含在項目中並更新了pubspec文件,以便如今能夠從代碼中引用它:

body: new ListView(
  children: [
    new Image.asset(
      'images/lake.jpg',
      height: 240.0,
      fit: BoxFit.cover,
    ),
    // ...
  ],
)

BoxFit.cover告訴框架,圖像應儘量小,但覆蓋整個渲染框。

第6步:把它放在一塊兒

在最後一步,你將這些碎片組裝在一塊兒。 這些小部件安排在ListView中,而不是列中,由於在小設備上運行應用程序時,ListView會自動滾動。

//...
body: new ListView(
  children: [
    new Image.asset(
      'images/lake.jpg',
      width: 600.0,
      height: 240.0,
      fit: BoxFit.cover,
    ),
    titleSection,
    buttonSection,
    textSection,
  ],
),
//...

Dart代碼main.dart
Imageimages
Pubspecpubspec.yaml

而已! 當您從新加載應用程序時,應該會看到截圖中顯示的相同佈局。 您能夠經過將交互添加到您的Flutter應用中來爲此佈局添加交互功能。

Flutter的佈局方法

重點是什麼?

  • 小部件是用於構建UI的類。
  • 小部件用於佈局和UI元素。
  • 撰寫簡單的小部件來構建複雜的小部件。

Flutter的佈局機制的核心是小部件。 在Flutter中,幾乎全部東西都是一個小部件 - 甚至佈局模型都是小部件。 您在Flutter應用中看到的圖像,圖標和文本都是小部件。 可是你看不到的東西也是小部件,例如排列,約束和對齊可見小部件的行,列和網格。

您能夠經過構建小部件來建立佈局來構建更復雜的小部件。 例如,左邊的屏幕截圖顯示了3個圖標,每一個圖標下有一個標籤:

第二個屏幕截圖顯示可視佈局,顯示一列3列,其中每列包含一個圖標和一個標籤。

注意:本教程中的大多數屏幕截圖均以debugPaintSizeEnabled設置爲true顯示,以便您能夠看到可視佈局。 有關更多信息,請參閱可視化調試,這是調試Flutter應用程序中的一部分

如下是此UI的部件樹圖:

大部分應該看起來像你所指望的,但你可能想知道容器(以粉紅色顯示)。 容器是一個小部件,容許您自定義其子部件。 若是要添加填充,邊距,邊框或背景色,請使用容器來命名其某些功能。

在這個例子中,每一個文本小部件放置在容器中以添加邊距。 整個行也被放置在容器中以在行的周圍添加填充。

本例中的其他UI由屬性控制。 使用其color屬性設置圖標的顏色。 使用文本的style屬性來設置字體,顏色,重量等等。 列和行的屬性容許您指定他們的孩子如何垂直或水平對齊,以及兒童應該佔據多少空間。

佈置一個小部件

重點是什麼?

  • 即便應用程序自己也是一個小部件。
  • 建立一個小部件並將其添加到佈局小部件很容易。
  • 要在設備上顯示小部件,請將佈局小部件添加到應用小部件。
  • 使用Scaffold是最容易的,它是Material Components庫中的一個小部件,它提供了一個默認橫幅,背景顏色,而且具備添加抽屜,小吃店和底部表單的API。
  • 若是您願意,能夠構建僅使用小部件庫中的標準小部件的應用程序。

如何在Flutter中佈置單個小部件? 本節介紹如何建立一個簡單的小部件並將其顯示在屏幕上。 它還顯示了一個簡單的Hello World應用程序的完整代碼。

在Flutter中,只需幾個步驟便可在屏幕上放置文本,圖標或圖像。

1.選擇一個佈局小部件來保存該對象。
根據您想要對齊或約束可見窗口小部件的方式,從各類佈局窗口小部件中進行選擇,由於這些特性一般會傳遞到包含的窗口小部件。 這個例子使用Center,它將內容水平和垂直居中。

2.建立一個小部件來容納可見對象。

注意:Flutter應用程序是用Dart語言編寫的。 若是您瞭解Java或相似的面向對象編程語言,Dart會感到很是熟悉。 若是不是的話,你能夠試試DartPad,一個能夠在任何瀏覽器上使用的交互式Dart練習。 語言遊覽提供了Dart語言功能的概述。

例如,建立一個文本小部件:

new Text('Hello World', style: new TextStyle(fontSize: 32.0))

建立一個圖像小部件:

new Image.asset('images/myPic.jpg', fit: BoxFit.cover)

建立一個圖標小部件:

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

3.將可見小部件添加到佈局小部件。
若是全部佈局小部件帶有一個子元素(例如Center或Container),則它們具備一個child屬性,若是它們帶有小部件列表(例如Row,Column,ListView或Stack),則它們具備children屬性。

將文本小部件添加到中心小部件:

new Center(
  child: new Text('Hello World', style: new TextStyle(fontSize: 32.0))

4.將佈局小部件添加到頁面。
Flutter應用自己就是一個小部件,大部分小部件都有一個build()方法。 在應用程序的構建方法中聲明小部件會在設備上顯示小部件。

對於Material應用程序,您能夠將Center小部件直接添加到主頁的body屬性。

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new Center(
        child: new Text('Hello World', style: new TextStyle(fontSize: 32.0)),
      ),
    );
  }
}

注意:Material Components庫實現了遵循Material Design原則的小部件。 在設計用戶界面時,您能夠專門使用標準小部件庫中的小部件,也可使用材質部件中的小部件。 您能夠混合使用兩個庫中的小部件,您能夠自定義現有的小部件,也能夠構建本身的一組定製小部件。

對於非Material應用程序,您能夠將Center小部件添加到應用程序的build()方法中:

// This app doesn't use any Material Components, such as Scaffold.
// Normally, an app that doesn't use Scaffold has a black background
// and the default text color is black. This app changes its background
// to white and its text color to dark grey to mimic a Material app.
import 'package:flutter/material.dart';

void main() {
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Container(
      decoration: new BoxDecoration(color: Colors.white),
      child: new Center(
        child: new Text('Hello World',
            style: new TextStyle(fontSize: 40.0, color: Colors.black87)),
      ),
    );
  }
}

請注意,默認狀況下,非Material應用程序不包含AppBar,標題或背景顏色。 若是您想在非Material應用程序中使用這些功能,您必須本身構建它們。 此應用程序將背景顏色更改成白色,將文本更改成深灰色以模仿Material應用程序。

而已! 當你運行這個應用時,你應該看到:

Dart code (Material app): main.dart
Dart code (widgets-only app): main.dart

垂直和水平放置多個小部件

最多見的佈局模式之一是垂直或水平排列小部件。 您可使用「行」小部件水平排列小部件,並使用「列」小部件垂直排列小部件。

重點是什麼?

  • 行和列是兩種最經常使用的佈局模式。
  • 行和列分別獲取子窗口小部件的列表。
  • 子小部件自己能夠是行,列或其餘複雜小部件。
  • 您能夠指定行或列如何在垂直和水平方向上對齊其子項。
  • 您能夠拉伸或限制特定的子部件。
  • 您能夠指定子窗口小部件如何使用行或列的可用空間。

內容

  • 對齊小部件
  • 調整小部件
  • 包裝小部件
  • 嵌套行和列

要在Flutter中建立行或列,能夠將一個子窗口小部件列表添加到RowColumn窗口小部件中。 反過來,每一個孩子自己能夠是一排或一列,依此類推。 如下示例顯示如何在行或列內嵌套行或列。

此佈局按行組織。 該行包含兩個孩子:左側的一列和右側的圖片:

左列的小部件樹嵌套行和列。

您將在嵌套行和列中實現一些Pavlova的佈局代碼。

注意:行和列是水平和垂直佈局的基本原始小部件 - 這些低級小部件容許最大化的自定義。 Flutter還提供專門的,更高級別的小部件,可能足以知足您的需求。 例如,您可能更喜歡ListTile,而不是Row,而ListTile是一個易於使用的小部件,具備前導和尾隨圖標屬性以及最多3行文本。 您可能更喜歡ListView,而不是列,您可能更喜歡ListView,這是一種列狀佈局,若是其內容太長而沒法適應可用空間,則會自動滾動。 有關更多信息,請參閱通用佈局小部件

對齊小部件

您可使用mainAxisAlignmentcrossAxisAlignment屬性控制行或列的排列方式。 對於一排,主軸水平延伸,橫軸垂直延伸。 對於一列,主軸垂直運行,橫軸水平運行。

MainAxisAlignmentCrossAxisAlignment類提供了用於控制對齊的各類常量。

注意:將圖像添加到項目中時,須要更新pubspec文件才能訪問它們 - 此示例使用Image.asset來顯示圖像。 有關更多信息,請參閱此示例的pubspec.yaml文件,或在Flutter中添加資源和圖像。 若是您使用Image.network來引用聯機圖像,則不須要執行此操做。

在如下示例中,3個圖像中的每個都是100像素寬。 渲染框(在這種狀況下,整個屏幕)寬度超過300像素,所以將主軸對齊設置爲spaceEvenly在每一個圖像之間,以前和以後均勻分配自由水平空間。

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.dart
Images: images
Pubspec: pubspec.yaml

列的工做方式與行相同。 如下示例顯示了一列3個圖像,每一個圖像高100個像素。 渲染盒(在這種狀況下,整個屏幕)的高度大於300像素,所以將主軸對齊設置爲spaceEvenly將自由垂直空間均勻分配在每一個圖像之間,之上和之下。

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.dart
Images: images
Pubspec: pubspec.yaml

注意:若是佈局太大而不適合設備,則會在受影響的邊緣出現紅色條紋。 例如,如下截圖中的行對於設備的屏幕來講太寬:

經過使用「擴展」窗口小部件,能夠將窗口小部件的大小設置爲適合行或列,這在下面的「調整窗口小部件」部分進行了描述。

調整小部件

也許你想要一個小部件佔據其兄弟姐妹兩倍的空間。 您能夠將行或列的子項放置在擴展小部件中,以控制沿着主軸的小部件大小。 擴展小部件具備flex屬性,它是一個整數,用於肯定小部件的彈性因子。 擴展小部件的默認彈性因子是1。

例如,要建立一個由三個小部件組成的行,其中中間小部件的寬度是其餘兩個小部件的兩倍,請將中間小部件的彈性係數設置爲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(

Dart code: main.dart
Images: images
Pubspec: pubspec.yaml

要修復上一節中的示例,其中3行圖像的行對於其渲染框太寬,而且致使紅色條帶,請使用擴展小部件包裝每一個小部件。 默認狀況下,每一個小部件的彈性因子爲1,將行的三分之一分配給每一個小部件。

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(

Dart code: main.dart
Images: images
Pubspec: pubspec.yaml

包裝小部件

默認狀況下,行或列沿着其主軸佔據儘量多的空間,但若是要將子項緊密包裝在一塊兒,請將mainAxisSize設置爲MainAxisSize.min。 如下示例使用此屬性將星形圖標打包在一塊兒。

class _MyHomePageState extends State<MyHomePage> {
  @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),
      ],
    );

  // ...
}

Dart code: main.dart
Icons: Icons class
Pubspec: pubspec.yaml

嵌套行和列

佈局框架容許您根據須要在行和列內部嵌套行和列。 讓咱們看下面佈局的概述部分的代碼:

概述部分實現爲兩行。 評級行包含五顆星和評論數量。 圖標行包含三列圖標和文本。

評級行的小部件樹:

ratings變量建立一行,其中包含一行較小的5星形圖標和文本:

class _MyHomePageState extends State<MyHomePage> {
  @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,
            ),
          ),
        ],
      ),
    );
    //...
  }
}

提示:爲了最大限度地減小由嵌套嚴重的佈局代碼致使的視覺混淆,能夠在變量和函數中實現UI的各個部分。

評級行下方的圖標行包含3列; 每一個列都包含一個圖標和兩行文本,您能夠在其小部件樹中看到:

iconList變量定義圖標行:

class _MyHomePageState extends State<MyHomePage> {
  @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 allows you to create a default text
    // style that is inherited by its child and all subsequent children.
    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變量包含評分和圖標行,以及描述Pavlova的標題和文本:

class _MyHomePageState extends State<MyHomePage> {
  @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,
        ],
      ),
    );
    //...
  }
}

左列放置在容器中以約束其寬度。 最後,用Card的整個行(包含左列和圖像)構建UI。

Pavlova圖片來自Pixabay,能夠在Creative Commons許可下使用。 您可使用Image.network從網絡中嵌入圖像,但對於此示例,圖像將保存到項目中的圖像目錄中,添加到pubspec文件並使用Images.asset訪問。 有關更多信息,請參閱在Flutter中添加資產和圖像

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.dart
Images: images
Pubspec: pubspec.yaml

提示:Pavlova示例在普遍的設備(如平板電腦)上水平運行效果最佳。 若是您在iOS模擬器中運行此示例,則可使用Hardware > Device菜單選擇其餘設備。 對於這個例子,咱們推薦iPad Pro。 您可使用Hardware > Rotate將其方向更改成橫向模式。 您還可使用Window > Scale更改模擬器窗口的大小(不更改邏輯像素的數量)。

常見的佈局小部件

Flutter擁有豐富的佈局小部件庫,但這裏有一些最經常使用的佈局部件。 其目的是儘量快地啓動並運行,而不是讓您完整列出。 有關其餘可用小部件的信息,請參閱小部件概述,或使用API參考文檔中的搜索框。 此外,API文檔中的小部件頁面常常會提供有關可能更適合您需求的相似小部件的建議。

如下小部件分爲兩類:小部件庫中的標準小部件和材質組件庫中的專用小部件。 任何應用程序均可以使用小部件庫,但只有Material應用程序可使用Material Components庫。

標準小部件

  • Container: 向邊框添加填充,邊距,邊框,背景顏色或其餘裝飾。
  • GridView: 放置小部件做爲可滾動的網格。
  • ListView: 將小部件列爲可滾動列表。
  • Stack: 將小部件重疊在另外一個小部件之上。

Material Components

  • Card: 將相關信息組織成帶有圓角和投影的盒子。
  • ListTile: 將最多3行文本,以及可選的前導和訓練圖標組合成一行。

Container

許多佈局會自由使用Container來使用填充分隔小部件,或者添加邊框或邊距。 您能夠經過將整個佈局放入Container並更改其背景顏色或圖像來更改設備的背景。

容器概要:

  • 添加填充,邊距,邊框
  • 更改背景顏色或圖像
  • 包含單個子部件,但該子部件能夠是Row,Column,甚至是部件樹的根部

容器示例:
除了下面的例子以外,本教程中的許多示例都使用Container。 您還能夠在Flutter Gallery中找到更多容器示例。

該佈局由兩列組成,每列包含2個圖像。 每一個圖像使用一個Container來添加一個圓形的灰色邊框和邊距。 包含圖像行的列使用容器將背景顏色更改成淺灰色。

Dart code: main.dart,下面的代碼段
Images: images
Pubspec: pubspec.yaml

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {

    var container = new Container(
      decoration: new BoxDecoration(
        color: Colors.black26,
      ),
      child: new Column(
        children: [
          new Row(
            children: [
              new Expanded(
                child: new Container(
                  decoration: new BoxDecoration(
                    border: new Border.all(width: 10.0, color: Colors.black38),
                    borderRadius:
                        const BorderRadius.all(const Radius.circular(8.0)),
                  ),
                  margin: const EdgeInsets.all(4.0),
                  child: new Image.asset('images/pic1.jpg'),
                ),
              ),
              new Expanded(
                child: new Container(
                  decoration: new BoxDecoration(
                    border: new Border.all(width: 10.0, color: Colors.black38),
                    borderRadius:
                        const BorderRadius.all(const Radius.circular(8.0)),
                  ),
                  margin: const EdgeInsets.all(4.0),
                  child: new Image.asset('images/pic2.jpg'),
                ),
              ),
            ],
          ),
          // ...
          // See the definition for the second row on GitHub:
          // https://raw.githubusercontent.com/flutter/website/master/_includes/code/layout/container/main.dart
        ],
      ),
    );
    //...
  }
}

GridView

使用GridView將小部件放置爲二維列表。 GridView提供了兩個預製列表,或者您能夠構建本身的自定義網格。 當GridView檢測到其內容太長而不適合渲染框時,它會自動滾動。

GridView摘要:

  • 在網格中放置小部件
  • 檢測列內容什麼時候超過渲染框並自動提供滾動
  • 構建您本身的自定義網格,或使用提供的網格之一:
  •     GridView.count容許你指定列數
  •     GridView.extent容許你指定一個tile的最大像素寬度

注意:顯示二維列表時,重要的是單元格佔用哪一行和一列(例如,它是「avocado」行的「calorie」列中的條目),請使用TableDataTable

GridView示例:

使用GridView.extent建立一個最大寬度爲150像素的網格。

Dart code: main.dart
Images: images
Pubspec: pubspec.yaml

// The images are saved with names pic1.jpg, pic2.jpg...pic30.jpg.
// The List.generate constructor allows an easy way to create
// a list when objects have a predictable naming pattern.
List<Container> _buildGridTileList(int count) {

  return new List<Container>.generate(
      count,
      (int index) =>
          new Container(child: new Image.asset('images/pic${index+1}.jpg')));
}

Widget buildGrid() {
  return new GridView.extent(
      maxCrossAxisExtent: 150.0,
      padding: const EdgeInsets.all(4.0),
      mainAxisSpacing: 4.0,
      crossAxisSpacing: 4.0,
      children: _buildGridTileList(30));
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new Center(
        child: buildGrid(),
      ),
    );
  }
}

使用GridView.count在縱向模式下建立2個寬度的網格,在橫向模式下建立3個寬度的網格。 標題是經過設置每一個GridTile的頁腳屬性建立的。

Dart code:來自Flutter Gallerygrid_list_demo.dart

ListView

ListView是一個相似列的小部件,它的內容對於其渲染框太長時會自動提供滾動。

ListView摘要:

  • 專門用於組織框列表的列
  • 能夠水平或垂直放置
  • 檢測它的內容什麼時候不適合並提供滾動
  • 比Column更少配置,但更易於使用並支持滾動

ListView示例:

使用ListView顯示使用ListTiles的業務列表。 分隔線將餐廳與餐廳分開。

Dart code: main.dart,
Icons: Icons class
Pubspec: pubspec.yaml

List<Widget> list = <Widget>[
  new ListTile(
    title: new Text('CineArts at the Empire',
        style: new TextStyle(fontWeight: FontWeight.w500, fontSize: 20.0)),
    subtitle: new Text('85 W Portal Ave'),
    leading: new Icon(
      Icons.theaters,
      color: Colors.blue[500],
    ),
  ),
  new ListTile(
    title: new Text('The Castro Theater',
        style: new TextStyle(fontWeight: FontWeight.w500, fontSize: 20.0)),
    subtitle: new Text('429 Castro St'),
    leading: new Icon(
      Icons.theaters,
      color: Colors.blue[500],
    ),
  ),
  // ...
  // See the rest of the column defined on GitHub:
  // https://raw.githubusercontent.com/flutter/website/master/_includes/code/layout/listview/main.dart
];

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      // ...
      body: new Center(
        child: new ListView(
          children: list,
        ),
      ),
    );
  }
}

使用ListView顯示特定ColorsMaterial Design面板中的顏色。
Dart代碼:來自Flutter Gallerycolors_demo.dart

Stack

使用Stack來安排基礎小部件頂部的小部件 - 一般是圖像。 小部件能夠徹底或部分重疊基礎小部件。

Stack摘要:

  • 用於與另外一個小部件重疊的小部件
  • 子列表中的第一個小部件是基礎小部件; 隨後的子被覆蓋在基礎小部件的頂部
  • 堆棧的內容不能滾動
  • 您能夠選擇剪切超過渲染框的子項

Stack示例:

使用Stack疊加容器(在半透明的黑色背景上顯示其文本),放置在Circle Avatar的頂部。Stack使用alignment屬性和Alignments偏移文本。

Dart code: main.dart
Image: images
Pubspec: pubspec.yaml

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    var stack = new Stack(
      alignment: const Alignment(0.6, 0.6),
      children: [
        new CircleAvatar(
          backgroundImage: new AssetImage('images/pic.jpg'),
          radius: 100.0,
        ),
        new Container(
          decoration: new BoxDecoration(
            color: Colors.black45,
          ),
          child: new Text(
            'Mia B',
            style: new TextStyle(
              fontSize: 20.0,
              fontWeight: FontWeight.bold,
              color: Colors.white,
            ),
          ),
        ),
      ],
    );
    // ...
  }
}

使用Stack將漸變疊加到圖像的頂部。 漸變確保工具欄的圖標與圖像不一樣。
Dart代碼:Flutter Gallery中的contacts_demo.dart

Card

材料組件庫中的卡片包含相關的信息塊,能夠由大多數任何小部件構成,但一般與ListTile一塊兒使用。 卡片有一個孩子,但其孩子能夠是支持多個孩子的列,行,列表,網格或其餘小部件。 默認狀況下,卡片將其大小縮小爲0像素0。 您可使用SizedBox來限制卡的大小。

在Flutter中,一張卡片具備稍微圓潤的角落和陰影,使其具備3D效果。 更改卡片的elevation屬性可以讓您控制投影效果。 例如,將標高設置爲24.0,將卡片從視覺上擡離表面並使陰影變得更加分散。 有關支持的高程值的列表,請參見材料準則中的高程和陰影。 指定不支持的值將徹底禁用投影。

Card摘要:

  • 實現材料設計卡片
  • 用於呈現相關信息的塊
  • 接受單個孩子,但該孩子能夠是Row,Column或其餘包含子級列表的小部件
  • 顯示圓角和陰影
  • 卡片的內容不能滾動
  • 來自材料組件庫

卡片示例:

包含3個ListTiles並經過用SizedBox包裝進行大小調整的卡片。 分隔符分隔第一個和第二個ListTiles。

Dart code: main.dart
Icons: Icons class
Pubspec: pubspec.yaml

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    var card = new SizedBox(
      height: 210.0,
      child: new Card(
        child: new Column(
          children: [
            new ListTile(
              title: new Text('1625 Main Street',
                  style: new TextStyle(fontWeight: FontWeight.w500)),
              subtitle: new Text('My City, CA 99984'),
              leading: new Icon(
                Icons.restaurant_menu,
                color: Colors.blue[500],
              ),
            ),
            new Divider(),
            new ListTile(
              title: new Text('(408) 555-1212',
                  style: new TextStyle(fontWeight: FontWeight.w500)),
              leading: new Icon(
                Icons.contact_phone,
                color: Colors.blue[500],
              ),
            ),
            new ListTile(
              title: new Text('costa@example.com'),
              leading: new Icon(
                Icons.contact_mail,
                color: Colors.blue[500],
              ),
            ),
          ],
        ),
      ),
    );
  //...
}

包含圖像和文字的卡片。
Flutter代碼:來自Flutter Gallerycards_demo.dart

ListTile

使用ListTile是Material Components庫中的一個專門的行小部件,用於建立包含最多3行文本和可選的前導和尾隨圖標的行。 ListTile在Card或ListView中最經常使用,但能夠在別處使用。

ListTile摘要:

  • 包含最多3行文本和可選圖標的專用行
  • 比Row更不易配置,但更易於使用
  • 來自材料組件庫

ListTile示例:

包含3個ListTiles的卡片。
Dart代碼:查看卡片示例

使用ListTile列出3個下拉按鈕類型。
飛鏢代碼:來自Flutter Gallerybuttons_demo.dart

資源

編寫佈局代碼時如下資源可能會有所幫助。

相關文章
相關標籤/搜索