• 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(
                 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( 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,
     

    资源

    编写布局代码时以下资源可能会有所帮助。

  • 相关阅读:
    ArrayList用法
    Delegate比较全面的例子(原创)
    一个登陆页面,包含了初始化用户,输入检测,错误处理等
    C#线程 在某一时间内,只有N个线程在并发执行,其余都在队列中的实现
    ASP.Net防止刷新自动触发事件的解决方案
    存储过程编写经验和优化措施 (转)
    [转]数据库开发21条军规
    [转]Ajax简单客户登陆验证
    用SqlBulkCopy进行大批量数据迁移
    什么时候使用哪个数据绑定控件(asp.net)
  • 原文地址:https://www.cnblogs.com/joe235/p/11130893.html
Copyright © 2020-2023  润新知