Flutter的布局方法


重點是什么?

  • Widgets 是用於構建UI的類.
  • Widgets 用於布局和UI元素.
  • 通過簡單的widget來構建復雜的widget

Flutter布局機制的核心就是widget。在Flutter中,幾乎所有東西都是一個widget - 甚至布局模型都是widget。您在Flutter應用中看到的圖像、圖標和文本都是widget。 甚至你看不到的東西也是widget,例如行(row)、列(column)以及用來排列、約束和對齊這些可見widget的網格(grid)。

您可以通過構建widget來構建更復雜的widget。例如,下面左邊的屏幕截圖顯示了3個圖標,每個圖標下有一個標簽:

sample layout      sample sample layout with visual debugging turned on

第二個屏幕截圖顯示布局結構,顯示一個行包含3列,其中每列包含一個圖標和一個標簽。

注意: 本教程中的大多數屏幕截圖都是在debugPaintSizeEnabled為true時顯示的,因此您可以看到布局結構。 有關更多信息,請參閱可視化調試,這是調試 Flutter Apps中的一節。

 

以下是此UI的widget樹示意圖:

node tree representing the sample layout

大部分應該看起來應該像您所期望的,但你可能想了解一下Container(以粉紅色顯示)。 Container也是一個widget,允許您自定義其子widget。如果要添加填充,邊距,邊框或背景色,請使用Container來設置(譯者語:只有容器有這些屬性)。

在這個例子中,每個Text放置在Container中以添加邊距。整個行也被放置在容器中以在行的周圍添加填充。

本例UI中的其他部分也可以通過屬性來控制。使用其color屬性設置圖標的顏色。使用Text.style屬性來設置字體,顏色,粗細等。列和行的屬性允許您指定他們的子項如何垂直或水平對齊,以及應該占據多少空間。

布局一個 widget

重點是什么?

  • 即使應用程序本身也是一個 widget.
  • 創建一個widget並將其添加到布局widget中是很簡單的.
  • 要在設備上顯示widget,請將布局widget添加到 app widget中。
  • 使用Scaffold是最容易的,它是 Material Components庫中的一個widget,它提供了一個默認banner,背景顏色,並且具有添加drawer,snack bar和底部sheet的API。
  • 如果您願意,可以構建僅使用標准widget庫中的widget來構建您的應用程序

如何在Flutter中布局單個widget?本節介紹如何創建一個簡單的widget並將其顯示在屏幕上。它還展示了一個簡單的Hello World應用程序的完整代碼。

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

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

2.創建一個widget來容納可見對象

例如,創建一個Text widget:

Text('Hello World'),

或者

new Text(
  'Hello World', 
  style: new TextStyle(fontSize: 32.0,color: Colors.grey[500]),)
)

創建一個 Image widget:

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

或者

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

創建一個 Icon widget:

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

或者

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

3.將可見widget添加到布局widget.
所有布局widget都有一個child屬性(例如Center或Container),或者一個 children屬性,如果他們需要一個widget列表(例如Row,Column,ListView或Stack)。

將Text widget添加到Center widget:

Center(
  child: Text('Hello World'),
),

或者

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

4.將布局widget添加到頁面.
Flutter應用本身就是一個widget,大部分widget都有一個build()方法。在應用程序的build方法中創建會在設備上顯示的widget。

對於Material應用程序,您可以使用Scaffold widget; 它提供默認橫幅,背景顏色,and has API for adding drawers, snack bars, and bottom sheets。然后,您可以將Center widget直接添加到body主頁的屬性中。

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter layout demo',
      home: new Scaffold(
        appBar: AppBar(
          title: Text('Flutter layout demo'),
        ),
        body: Center(
          child: Text('Hello World'),
        ),
      ),
    );
  }
}

Note: 在設計用戶界面時,您可以使用標准widget庫中的widget,也可以使用Material Components中的widget。 您可以混合使用兩個庫中的widget,可以自定義現有的widget,也可以構建一組自定義的widget。

對於非Material應用程序,您可以將Center widget添加到應用程序的build()方法中:

// 這個App沒有使用Material組件,  如Scaffold.
// 一般來說, app沒有使用Scaffold的話,會有一個黑色的背景和一個默認為黑色的文本顏色。
// 這個app,將背景色改為了白色,並且將文本顏色改為了黑色以模仿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',
            textDirection: TextDirection.ltr,
            style: new TextStyle(
                fontSize: 40.0, 
                color: Colors.black87
            )
         ),
      ),
    );
  }
}                 

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

好了! 當你運行這個應用時,你會看到:

screenshot of a white background with grey 'Hello World' text.

Dart 代碼 (Material app): main.dart
Dart 代碼 (僅使用標准Widget的app): main.dart

垂直和水平放置多個widget

最常見的布局模式之一是垂直或水平排列widget。您可以使用行(Row)水平排列widget,並使用列(Column)垂直排列widget。

重點是什么?

  • 行和列是兩種最常用的布局模式。
  • 行和列都需要一個子widget列表。
  • 子widget本身可以是行、列或其他復雜widget。
  • 您可以指定行或列如何在垂直或水平方向上對齊其子項
  • 您可以拉伸或限制特定的子widget.
  • 您可以指定子widget如何使用行或列的可用空間.

Contents

要在Flutter中創建行或列,可以將一個widget列表添加到Row 或Column 中。 同時,每個孩子本身可以是一個Row或一個Column,依此類推。以下示例顯示如何在行或列內嵌套行或列。

此布局按行組織。該行包含兩個孩子:左側的一列和右側的圖片:screenshot with callouts showing the row containing two children: a column and an image.

 

左側的Column widget樹嵌套行和列。diagram showing a left column broken down to its sub-rows and sub-columns

 

您將在嵌套行和列中實現一些Pavlova(圖片中的奶油水果蛋白餅)的布局代碼 

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

對齊 widgets

您可以控制行或列如何使用mainAxisAlignmentcrossAxisAlignment屬性來對齊其子項。 對於行(Row)來說,主軸是水平方向,橫軸垂直方向。對於列(Column)來說,主軸垂直方向,橫軸水平方向。

diagram showing the main axis and cross axis for a row                                    diagram showing the main axis and cross axis for a column

MainAxisAlignment 和CrossAxisAlignment 類提供了很多控制對齊的常量.

注意: 將圖片添加到項目時,需要更新pubspec文件才能訪問它們 - 此示例使用Image.asset顯示圖像。 有關更多信息,請參閱此示例的pubspec.yaml文件, 或在Flutter中添加資源和圖像。如果您使用的是網上的圖片,則不需要執行此操作,使用Image.network即可。

在以下示例中,3個圖像中的每一個都是100像素寬。渲染盒(在這種情況下,整個屏幕)寬度超過300個像素, 因此設置主軸對齊方式為spaceEvenly,它會在每個圖像之間,之前和之后均勻分配空閑的水平空間。

Row(
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  children: [
    Image.asset('images/pic1.jpg'),
    Image.asset('images/pic2.jpg'),
    Image.asset('images/pic3.jpg'),
  ],
);

a row showing 3 images spaced evenly in the rowDart code: main.dart  Images: images  Pubspec: pubspec.yaml

 

列的工作方式與行相同。以下示例顯示了一列,包含3個圖片,每個圖片高100個像素。 渲染盒(在這種情況下,整個屏幕)的高度大於300像素,因此設置主軸對齊方式為spaceEvenly,它會在每個圖像之間,上方和下方均勻分配空閑的垂直空間。

Column(
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  children: [
    Image.asset('images/pic1.jpg'),
    Image.asset('images/pic2.jpg'),
    Image.asset('images/pic3.jpg'),
  ],
);

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

調整 widget大小

當布局太大而無法容納設備時,受影響的邊緣會出現黃色和黑色條紋圖案。這是一個太寬的行示例

排過寬

可以使用Expanded widget調整widget的大小以適合行或列要修復前一個示例,其中圖像行對於其渲染框來說太寬,請使用Expanded widget包裝每個圖像

默認情況下,每個widget的彈性系數為1,將行的三分之一分配給每個小部件。

child: Row(
  crossAxisAlignment: CrossAxisAlignment.center,
  children: [
    Expanded(
      child: Image.asset('images/pic1.jpg'),
    ),
    Expanded(
      child: Image.asset('images/pic2.jpg'),
    ),
    Expanded(
      child: Image.asset('images/pic3.jpg'),
    ),
  ],
);

a row of 3 images that are too wide, but each is constrained to take only 1/3 of the row's available spaceDart code: main.dart  

也許你想要一個widget占據其兄弟widget兩倍的空間。您可以將行或列的子項放置在Expandedwidget中, 以控制沿着主軸方向的widget大小。Expanded widget具有一個flex屬性,它是一個整數,用於確定widget的彈性系數,默認彈性系數是1。

例如,要創建一個由三個widget組成的行,其中中間widget的寬度是其他兩個widget的兩倍,將中間widget的彈性系數設置為2:

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(
    child: new Image.asset('images/pic3.jpg'),
      ),
    ],
);

a row of 3 images with the middle image twice as wide as the othersDart code: main.dart  

聚集 widgets

默認情況下,行或列沿着其主軸會盡可能占用盡可能多的空間,但如果要將孩子緊密聚集在一起,可以將mainAxisSize設置為MainAxisSize.min。 以下示例使用此屬性將星形圖標聚集在一起(如果不聚集,五張星形圖標會分散開)。

child: Row(
  mainAxisSize: MainAxisSize.min,
  children: [
    Icon(Icons.star, color: Colors.green[500]),
    Icon(Icons.star, color: Colors.green[500]),
    Icon(Icons.star, color: Colors.green[500]),
    Icon(Icons.star, color: Colors.black),
    Icon(Icons.star, color: Colors.black),
  ],
)

或者

var stars = Row(
    mainAxisSize: MainAxisSize.min,
    children: [
        Icon(Icons.star, color: Colors.green[500]),
        Icon(Icons.star, color: Colors.green[500]),
        Icon(Icons.star, color: Colors.green[500]),
        Icon(Icons.star, color: Colors.black),
        Icon(Icons.star, color: Colors.black),
    ],
);

a row of 5 stars, packed together in the middle of the rowDart code: main.dart  Icons: Icons class  Pubspec: pubspec.yaml

嵌套行和列

布局框架允許您根據需要在行和列內部再嵌套行和列。讓我們看下面紅色邊框圈起來部分的布局代碼:

a screenshot of the pavlova app, with the ratings and icon rows outlined in red

紅色邊框部分的布局通過兩個行來實現。評級行包含五顆星和評論數量。圖標行包含三列圖標和文本。

評級行的widget樹:

a node tree showing the widgets in the ratings row

ratings變量創建一個包含5個星形圖標和一個文本的行:

final ratings = Container(
  padding: EdgeInsets.all(20),
  child: Row(
    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
    children: [
      Row(
      mainAxisSize: MainAxisSize.min,
      children: [
          Icon(Icons.star, color: Colors.green[500]),
          Icon(Icons.star, color: Colors.green[500]),
          Icon(Icons.star, color: Colors.green[500]),
          Icon(Icons.star, color: Colors.black),
          Icon(Icons.star, color: Colors.black),
      ],
      ),
      Text(
        '170 Reviews',
        style: TextStyle(
          color: Colors.black,
          fontWeight: FontWeight.w800,
          fontFamily: 'Roboto',
          letterSpacing: 0.5,
          fontSize: 20,
        ),
      ),
    ],
  ),
);

或者

var stars = Row(
  mainAxisSize: MainAxisSize.min,
  children: [
    Icon(Icons.star, color: Colors.green[500]),
    Icon(Icons.star, color: Colors.green[500]),
    Icon(Icons.star, color: Colors.green[500]),
    Icon(Icons.star, color: Colors.black),
    Icon(Icons.star, color: Colors.black),
  ],
);

final ratings = Container(
  padding: EdgeInsets.all(20),
  child: Row(
    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
    children: [
      stars,
      Text(
        '170 Reviews',
        style: TextStyle(
          color: Colors.black,
          fontWeight: FontWeight.w800,
          fontFamily: 'Roboto',
          letterSpacing: 0.5,
          fontSize: 20,
        ),
      ),
    ],
  ),
);

提示: 為了最大限度地減少由嵌套嚴重的布局代碼導致的視覺混淆,可以在變量和函數中實現UI的各個部分。

評級行下方的圖標行包含3列; 每個列都包含一個圖標和兩行文本,您可以在其widget樹中看到:

a node tree for the widets in the icons row

iconList變量定義了圖標行:

final descTextStyle = TextStyle(
  color: Colors.black,
  fontWeight: FontWeight.w800,
  fontFamily: 'Roboto',
  letterSpacing: 0.5,
  fontSize: 18,
  height: 2,
);

// DefaultTextStyle.merge可以允許您創建一個默認的文本樣式,該樣式會被其
// 所有的子節點繼承
final iconList = DefaultTextStyle.merge(
  style: descTextStyle,
  child: Container(
    padding: EdgeInsets.all(20),
    child: Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: [
        Column(
          children: [
            Icon(Icons.kitchen, color: Colors.green[500]),
            Text('PREP:'),
            Text('25 min'),
          ],
        ),
        Column(
          children: [
            Icon(Icons.timer, color: Colors.green[500]),
            Text('COOK:'),
            Text('1 hr'),
          ],
        ),
        Column(
          children: [
            Icon(Icons.restaurant, color: Colors.green[500]),
            Text('FEEDS:'),
            Text('4-6'),
          ],
        ),
      ],
    ),
  ),
);

leftColumn變量包含評分和圖標行,以及描述Pavlova的標題和文字:

final leftColumn = Container(
  padding: EdgeInsets.fromLTRB(20, 30, 20, 20),
  child: Column(
    children: [
      titleText,
      subTitle,
      ratings,
      iconList,
    ],
  ),
);

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

Pavlova圖片來自 Pixabay ,可以在Creative Commons許可下使用。 您可以使用Image.network直接從網上下載顯示圖片,但對於此示例,圖像保存到項目中的圖像目錄中,添加到pubspec文件, 並使用Images.asset。 有關更多信息,請參閱在Flutter中添加Asserts和圖片

body: Center(
  child: Container(
    margin: EdgeInsets.fromLTRB(0, 40, 0, 30),
    height: 600,
    child: Card(
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Container(
            width: 440,
            child: leftColumn,
          ),
          mainImage,
        ],
      ),
    ),
  ),
),

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

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

常用布局widgets

Flutter擁有豐富的布局widget,但這里有一些最常用的布局widget。其目的是盡可能快地讓您構建應用並運行,而不是讓您淹沒在整個完整的widget列表中。 有關其他可用widget的信息,請參閱widget概述,或使用API 參考 docs文檔中的搜索框。 此外,API文檔中的widget頁面經常會推薦一些可能更適合您需求的類似widget。

以下widget分為兩類:widgets library中的標准widget和Material Components library中的專用widget 。 任何應用程序都可以使用widgets library中的widget,但只有Material應用程序可以使用Material Components庫。

標准 widgets

Container: 添加 padding, margins, borders, background color, 或將其他裝飾添加到widget.
GridView: 將 widgets 排列為可滾動的網格.
ListView: 將 widget排列為可滾動列表
Stack: 將 widget重疊在另一個widget之上.

Material Components

Card: 將相關內容放到帶圓角和投影的盒子中。
ListTile: 將最多3行文字,以及可選的行前和和行尾的圖標排成一行

Container

許多布局會自由使用容器來使用padding分隔widget,或者添加邊框(border)或邊距(margin)。您可以通過將整個布局放入容器並更改其背景顏色或圖片來更改設備的背景。

Container 概要 :

  • 添加padding, margins, borders
  • 改變背景顏色或圖片
  • 包含單個子widget,但該子widget可以是Row,Column,甚至是widget樹的根

a diagram showing that margins, borders, and padding, that surround content in a container

Container 示例:

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

該布局中每個圖像使用一個Container來添加一個圓形的灰色邊框和邊距。然后使用容器將列背景顏色更改為淺灰色。

Widget _buildImageColumn() => Container(
      decoration: BoxDecoration(
        color: Colors.black26,
      ),
      child: Column(
        children: [
          _buildImageRow(1),
          _buildImageRow(3),
        ],
      ),
    );

Container還用於為每個圖像添加圓角邊框和邊距:

Widget _buildDecoratedImage(int imageIndex) => Expanded(
      child: Container(
        decoration: BoxDecoration(
          border: Border.all(width: 10, color: Colors.black38),
          borderRadius: const BorderRadius.all(const Radius.circular(8)),
        ),
        margin: const EdgeInsets.all(4),
        child: Image.asset('images/pic$imageIndex.jpg'),
      ),
    );

Widget _buildImageRow(int imageIndex) => Row(
      children: [
        _buildDecoratedImage(imageIndex),
        _buildDecoratedImage(imageIndex + 1),
      ],
    );

您可以Container教程Flutter Gallery中找到更多示例

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

GridView

使用GridView將widget放置為二維列表。 GridView提供了兩個預制list,或者您可以構建自定義網格。當GridView檢測到其內容太長而不適合渲染框時,它會自動滾動。

GridView 概覽:

  • 在網格中放置widget
  • 檢測列內容超過渲染框時自動提供滾動
  • 構建您自己的自定義grid,或使用一下提供的grid之一:
    1. ·GridView.count 允許您指定列數
      ·GridView.extent 允許您指定項的最大像素寬度
注意: 在顯示二維列表時,重要的是單元格占用哪一行和哪一列時, 應該使用Table或 DataTable

GridView 示例:


用於GridView.extent創建一個網格,最大寬度為150像素。
Dart code:  main.dart,

使用GridView.count 在縱向模式下創建兩個行的grid,並在橫向模式下創建3個行的網格。通過為每個GridTile設置footer屬性來創建標題。
Dart code:  grid_list_demo.dart,
 
//圖像以名稱pic0.jpg,pic1.jpg ... pic29.jpg保存。
// List.generate()構造函數允許一種簡單的方法來創建       
//對象具有可預測命名模式的列表。
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(),
      ),
    );
  }
}

或者

Widget _buildGrid() => GridView.extent(
    maxCrossAxisExtent: 150,
    padding: const EdgeInsets.all(4),
    mainAxisSpacing: 4,
    crossAxisSpacing: 4,
    children: _buildGridTileList(30)
);

//圖像以名稱pic0.jpg,pic1.jpg ... pic29.jpg保存。
// List.generate()構造函數允許一種簡單的方法來創建       
//對象具有可預測命名模式的列表。

List<Container> _buildGridTileList(int count) => List.generate(
    count, (i) => Container(
    child:Image.asset('images/pic$i.jpg')
    )
);

ListView

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

ListView 摘要:

  • 用於組織盒子中列表的特殊Column
  • 可以水平或垂直放置
  • 檢測它的內容超過顯示框時提供滾動
  • 比Column配置少,但更易於使用並支持滾動

ListView 示例:


使用ListView顯示多個ListTile的業務列表。分隔線將劇院與餐廳分開
Dart code:  grid_and_list,

使用ListView控件來顯示Material Design palette中的Colors
Dart code:  colors_demo.dart,
 
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],
    ),
  ),
  // ...
  // 查看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,
        ),
      ),
    );
  }
}

或者

Widget _buildList() => ListView(
      children: [
        _tile('CineArts at the Empire', '85 W Portal Ave', Icons.theaters),
        _tile('The Castro Theater', '429 Castro St', Icons.theaters),
        _tile('Alamo Drafthouse Cinema', '2550 Mission St', Icons.theaters),
        _tile('Roxie Theater', '3117 16th St', Icons.theaters),
        _tile('United Artists Stonestown Twin', '501 Buckingham Way',
            Icons.theaters),
        _tile('AMC Metreon 16', '135 4th St #3000', Icons.theaters),
        Divider(),
        _tile('Kescaped_code#39;s Kitchen', '757 Monterey Blvd', Icons.restaurant),
        _tile('Emmyescaped_code#39;s Restaurant', '1923 Ocean Ave', Icons.restaurant),
        _tile(
            'Chaiya Thai Restaurant', '272 Claremont Blvd', Icons.restaurant),
        _tile('La Ciccia', '291 30th St', Icons.restaurant),
      ],
    );

ListTile _tile(String title, String subtitle, IconData icon) => ListTile(
      title: Text(title,
          style: TextStyle(
            fontWeight: FontWeight.w500,
            fontSize: 20,
          )),
      subtitle: Text(subtitle),
      leading: Icon(
        icon,
        color: Colors.blue[500],
      ),
    );

Stack

使用Stack來組織需要重疊的widget。widget可以完全或部分重疊底部widget。

Stack 摘要:

  • 用於與另一個widget重疊的widget
  • 子列表中的第一個widget是base widget; 隨后的子widget被覆蓋在基礎widget的頂部
  • Stack的內容不能滾動
  • 您可以選擇剪切超過渲染框的子項

Stack 示例:


使用Stack疊加Container(在半透明的黑色背景上顯示其文本),放置在Circle Avatar的頂部。Stack使用alignment屬性和調整文本偏移。
Dart code:  card_and_stack,

使用Stack將gradient疊加到圖像的頂部。gradient確保工具欄的圖標與圖片不同。
Dart code:  contacts_demo.dart,
 
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,
            ),
          ),
        ),
      ],
    );

或者

Widget _buildStack() => Stack(
    alignment: const Alignment(0.6, 0.6),
    children: [
      CircleAvatar(
        backgroundImage: AssetImage('images/pic.jpg'),
        radius: 100,
      ),
      Container(
        decoration: BoxDecoration(
          color: Colors.black45,
        ),
        child: Text(
          'Mia B',
          style: TextStyle(
            fontSize: 20,
            fontWeight: FontWeight.bold,
            color: Colors.white,
          ),
        ),
      ),
    ],
  );

Card

Material Components 庫中的Card包含相關內容塊,可以由大多數類型的widget構成,但通常與ListTile一起使用。Card有一個子項, 但它可以是支持多個子項的列,行,列表,網格或其他小部件。默認情況下,Card將其大小縮小為0像素。您可以使用SizedBox來限制Card的大小。

在Flutter中,Card具有圓角和陰影,這使它有一個3D效果。更改Card的eelevation屬性允許您控制投影效果。 例如,將elevation設置為24.0,將會使Card從視覺上抬離表面並使陰影變得更加分散。 有關支持的elevation值的列表,請參見Material guidelines中的Elevation and Shadows。 如果指定不支持的值將會完全禁用投影 。

Card 摘要:

  • 實現了一個 Material Design card
  • 接受單個子項,但該子項可以是Row,Column或其他包含子級列表的widget
  • 顯示圓角和陰影
  • Card內容不能滾動
  • Material Components 庫的一個widget

Card 示例:



一個Card包含3個ListTiles並通過包裝它來調整大小SizedBox。A Divider分隔第一個和第二個ListTiles。
Dart code:  card_and_stack,

包含圖像和文字的Card。
Dart code:  cards_demo.dart,
 
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],
              ),
            ),
          ],
        ),
      ),
    );

或者

Widget _buildCard() => SizedBox(
    height: 210,
    child: Card(
      child: Column(
        children: [
          ListTile(
            title: Text('1625 Main Street',
                style: TextStyle(fontWeight: FontWeight.w500)),
            subtitle: Text('My City, CA 99984'),
            leading: Icon(
              Icons.restaurant_menu,
              color: Colors.blue[500],
            ),
          ),
          Divider(),
          ListTile(
            title: Text('(408) 555-1212',
                style: TextStyle(fontWeight: FontWeight.w500)),
            leading: Icon(
              Icons.contact_phone,
              color: Colors.blue[500],
            ),
          ),
          ListTile(
            title: Text('costa@example.com'),
            leading: Icon(
              Icons.contact_mail,
              color: Colors.blue[500],
            ),
          ),
        ],
      ),
    ),
  );

ListTile

ListTile是Material Components庫中的一個專門的行級widget,用於創建包含最多3行文本和可選的行前和行尾圖標的行。ListTile在Card或ListView中最常用,但也可以在別處使用。

ListTile 摘要:

  • 包含最多3行文本和可選圖標的專用行
  • 比起Row不易配置,但更易於使用
  • Material Components 庫里的widget

ListTile 示例:



一個Card包含3 ListTiles。
Dart code:  card_and_stack,

用於ListTile列出3個下拉按鈕類型。
Dart code:  buttons_demo.dart,
 

資源

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM