Skip to main content

面向 Web 开发人员的 Flutter

本页面面向熟悉 HTML 和 CSS 语法以排列应用程序 UI 组件的用户。它将 HTML/CSS 代码片段映射到等效的 Flutter/Dart 代码。

Flutter 是一个使用 Dart 编程语言构建跨平台应用程序的框架。要了解使用 Dart 编程和使用 Javascript 编程之间的一些区别,请参阅作为 JavaScript 开发人员学习 Dart

设计 Web 布局和 Flutter 布局之间的一个根本区别是了解约束的工作方式以及小部件的大小和位置。要了解更多信息,请参阅了解约束

示例假设:

  • HTML 文档以 <!DOCTYPE html> 开头,所有 HTML 元素的 CSS 盒子模型都设置为 border-box,以与 Flutter 模型保持一致。

    css
    {
        box-sizing: border-box;
    }
  • 在 Flutter 中,'Lorem ipsum' 文本的默认样式由 bold24Roboto 变量定义如下,以保持语法的简单性:

    dart
    TextStyle bold24Roboto = const TextStyle(
      color: Colors.white,
      fontSize: 24,
      fontWeight: FontWeight.bold,
    );

执行基本的布局操作

#

以下示例显示如何执行最常见的 UI 布局任务。

样式和对齐文本

#

CSS 使用 font 和 color 属性处理的字体样式、大小和其他文本属性是 Text 小部件的 TextStyle 子项的各个属性。

对于 CSS 中用于对齐文本的 text-align 属性,Text 小部件具有 textAlign 属性。

在 HTML 和 Flutter 中,默认情况下,子元素或小部件都锚定在左上角。

css
<div class="grey-box">
  Lorem ipsum
</div>

.grey-box {
    background-color: #e0e0e0; /* grey 300 */
    width: 320px;
    height: 240px;
    font: 900 24px Georgia;
}
dart
final container = Container(
  // 灰色盒子
  width: 320,
  height: 240,
  color: Colors.grey[300],
  child: const Text(
    'Lorem ipsum',
    style: TextStyle(
      fontFamily: 'Georgia',
      fontSize: 24,
      fontWeight: FontWeight.bold,
    ),
    textAlign: TextAlign.center,
  ),
);

设置背景颜色

#

在 Flutter 中,您可以使用 Containercolor 属性或 decoration 属性设置背景颜色。但是,您不能同时提供两者,因为这可能会导致装饰覆盖背景颜色。当背景是简单的颜色时,应优先使用 color 属性。对于其他情况,例如渐变或图像,请使用 decoration 属性。

CSS 示例使用十六进制颜色等效于 Material 颜色调色板。

css
<div class="grey-box">
  Lorem ipsum
</div>

.grey-box {
    background-color: #e0e0e0; /* grey 300 */
    width: 320px;
    height: 240px;
    font: 900 24px Roboto;
}
dart
final container = Container(
  // 灰色盒子
  width: 320,
  height: 240,
  color: Colors.grey[300],
  child: Text(
    'Lorem ipsum',
    style: bold24Roboto,
  ),
);
dart
final container = Container(
  // 灰色盒子
  width: 320,
  height: 240,
  decoration: BoxDecoration(
    color: Colors.grey[300],
  ),
  child: Text(
    'Lorem ipsum',
    style: bold24Roboto,
  ),
);

居中组件

#

Center 小部件在其子项水平和垂直方向上居中。

要在 CSS 中实现类似的效果,父元素使用 flex 或 table-cell 显示行为。本页面的示例显示 flex 行为。

css
<div class="grey-box">
  Lorem ipsum
</div>

.grey-box {
    background-color: #e0e0e0; /* grey 300 */
    width: 320px;
    height: 240px;
    font: 900 24px Roboto;
    display: flex;
    align-items: center;
    justify-content: center;
}
dart
final container = Container(
  // 灰色盒子
  width: 320,
  height: 240,
  color: Colors.grey[300],
  child: Center(
    child: Text(
      'Lorem ipsum',
      style: bold24Roboto,
    ),
  ),
);

设置容器宽度

#

要指定 Container 小部件的宽度,请使用其 width 属性。这是一个固定宽度,与 CSS max-width 属性不同,后者会将容器宽度调整到最大值。要在 Flutter 中模拟该效果,请使用 Container 的 constraints 属性。使用 minWidthmaxWidth 创建一个新的 BoxConstraints 小部件。

对于嵌套的容器,如果父容器的宽度小于子容器的宽度,则子容器会调整自身大小以匹配父容器。

css
<div class="grey-box">
  <div class="red-box">
    Lorem ipsum
  </div>
</div>

.grey-box {
    background-color: #e0e0e0; /* grey 300 */
    width: 320px;
    height: 240px;
    font: 900 24px Roboto;
    display: flex;
    align-items: center;
    justify-content: center;
}
.red-box {
    background-color: #ef5350; /* red 400 */
    padding: 16px;
    color: #ffffff;
    width: 100%;
    max-width: 240px;
}
dart
final container = Container(
  // 灰色盒子
  width: 320,
  height: 240,
  color: Colors.grey[300],
  child: Center(
    child: Container(
      // 红色盒子
      width: 240, // max-width 为 240
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: Colors.red[400],
      ),
      child: Text(
        'Lorem ipsum',
        style: bold24Roboto,
      ),
    ),
  ),
);

操作位置和大小

#

以下示例显示如何对小部件位置、大小和背景执行更复杂的操作。

设置绝对位置

#

默认情况下,小部件相对于其父级定位。

要将小部件指定为 x-y 坐标的绝对位置,请将其嵌套在 Positioned 小部件中,该小部件又嵌套在 Stack 小部件中。

css
<div class="grey-box">
  <div class="red-box">
    Lorem ipsum
  </div>
</div>

.grey-box {
    position: relative;
    background-color: #e0e0e0; /* grey 300 */
    width: 320px;
    height: 240px;
    font: 900 24px Roboto;
}
.red-box {
    background-color: #ef5350; /* red 400 */
    padding: 16px;
    color: #ffffff;
    position: absolute;
    top: 24px;
    left: 24px;
}
dart
final container = Container(
  // 灰色盒子
  width: 320,
  height: 240,
  color: Colors.grey[300],
  child: Stack(
    children: [
      Positioned(
        // 红色盒子
        left: 24,
        top: 24,
        child: Container(
          padding: const EdgeInsets.all(16),
          decoration: BoxDecoration(
            color: Colors.red[400],
          ),
          child: Text(
            'Lorem ipsum',
            style: bold24Roboto,
          ),
        ),
      ),
    ],
  ),
);

旋转组件

#

要旋转小部件,请将其嵌套在 Transform 小部件中。使用 Transform 小部件的 alignmentorigin 属性分别以相对和绝对术语指定变换原点(支点)。

对于简单的二维旋转(其中小部件在 Z 轴上旋转),创建一个新的 Matrix4 身份对象,并使用其 rotateZ() 方法使用弧度(度 × π / 180)指定旋转因子。

css
<div class="grey-box">
  <div class="red-box">
    Lorem ipsum
  </div>
</div>

.grey-box {
    background-color: #e0e0e0; /* grey 300 */
    width: 320px;
    height: 240px;
    font: 900 24px Roboto;
    display: flex;
    align-items: center;
    justify-content: center;
}
.red-box {
    background-color: #ef5350; /* red 400 */
    padding: 16px;
    color: #ffffff;
    transform: rotate(15deg);
}
dart
final container = Container(
  // 灰色盒子
  width: 320,
  height: 240,
  color: Colors.grey[300],
  child: Center(
    child: Transform(
      alignment: Alignment.center,
      transform: Matrix4.identity()..rotateZ(15 * 3.1415927 / 180),
      child: Container(
        // 红色盒子
        padding: const EdgeInsets.all(16),
        decoration: BoxDecoration(
          color: Colors.red[400],
        ),
        child: Text(
          'Lorem ipsum',
          style: bold24Roboto,
          textAlign: TextAlign.center,
        ),
      ),
    ),
  ),
);

缩放组件

#

要放大或缩小小部件,请将其嵌套在 Transform 小部件中。使用 Transform 小部件的 alignmentorigin 属性分别以相对或绝对术语指定变换原点(支点)。

对于沿 x 轴的简单缩放操作,创建一个新的 Matrix4 身份对象,并使用其 scale() 方法指定缩放因子。

缩放父小部件时,其子小部件也会相应缩放。

css
<div class="grey-box">
  <div class="red-box">
    Lorem ipsum
  </div>
</div>

.grey-box {
    background-color: #e0e0e0; /* grey 300 */
    width: 320px;
    height: 240px;
    font: 900 24px Roboto;
    display: flex;
    align-items: center;
    justify-content: center;
}
.red-box {
    background-color: #ef5350; /* red 400 */
    padding: 16px;
    color: #ffffff;
    transform: scale(1.5);
}
dart
final container = Container(
  // 灰色盒子
  width: 320,
  height: 240,
  color: Colors.grey[300],
  child: Center(
    child: Transform(
      alignment: Alignment.center,
      transform: Matrix4.identity()..scale(1.5),
      child: Container(
        // 红色盒子
        padding: const EdgeInsets.all(16),
        decoration: BoxDecoration(
          color: Colors.red[400],
        ),
        child: Text(
          'Lorem ipsum',
          style: bold24Roboto,
          textAlign: TextAlign.center,
        ),
      ),
    ),
  ),
);

应用线性渐变

#

要将线性渐变应用于小部件的背景,请将其嵌套在 Container 小部件中。然后使用 Container 小部件的 decoration 属性创建一个 BoxDecoration 对象,并使用 BoxDecorationgradient 属性来转换背景填充。

渐变“角度”基于 Alignment (x, y) 值:

  • 如果开始和结束 x 值相等,则渐变为垂直方向 (0° | 180°)。
  • 如果开始和结束 y 值相等,则渐变为水平方向 (90° | 270°)。

垂直渐变

#
css
<div class="grey-box">
  <div class="red-box">
    Lorem ipsum
  </div>
</div>

.grey-box {
    background-color: #e0e0e0; /* grey 300 */
    width: 320px;
    height: 240px;
    font: 900 24px Roboto;
    display: flex;
    align-items: center;
    justify-content: center;
}
.red-box {
    padding: 16px;
    color: #ffffff;
    background: linear-gradient(180deg, #ef5350, rgba(0, 0, 0, 0) 80%);
}
dart
final container = Container(
  // 灰色盒子
  width: 320,
  height: 240,
  color: Colors.grey[300],
  child: Center(
    child: Container(
      // 红色盒子
      decoration: const BoxDecoration(
        gradient: LinearGradient(
          begin: Alignment.topCenter,
          end: Alignment(0.0, 0.6),
          colors: <Color>[
            Color(0xffef5350),
            Color(0x00ef5350),
          ],
        ),
      ),
      padding: const EdgeInsets.all(16),
      child: Text(
        'Lorem ipsum',
        style: bold24Roboto,
      ),
    ),
  ),
);

水平渐变

#
css
<div class="grey-box">
  <div class="red-box">
    Lorem ipsum
  </div>
</div>

.grey-box {
    background-color: #e0e0e0; /* grey 300 */
    width: 320px;
    height: 240px;
    font: 900 24px Roboto;
    display: flex;
    align-items: center;
    justify-content: center;
}
.red-box {
    padding: 16px;
    color: #ffffff;
    background: linear-gradient(90deg, #ef5350, rgba(0, 0, 0, 0) 80%);
}
dart
final container = Container(
  // 灰色盒子
  width: 320,
  height: 240,
  color: Colors.grey[300],
  child: Center(
    child: Container(
      // 红色盒子
      padding: const EdgeInsets.all(16),
      decoration: const BoxDecoration(
        gradient: LinearGradient(
          begin: Alignment(-1.0, 0.0),
          end: Alignment(0.6, 0.0),
          colors: <Color>[
            Color(0xffef5350),
            Color(0x00ef5350),
          ],
        ),
      ),
      child: Text(
        'Lorem ipsum',
        style: bold24Roboto,
      ),
    ),
  ),
);

操作形状

#

以下示例显示如何创建和自定义形状。

圆角

#

要使矩形形状的角变圆,请使用 BoxDecoration 对象的 borderRadius 属性。创建一个新的 BorderRadius 对象,该对象指定每个角的圆角半径。

css
<div class="grey-box">
  <div class="red-box">
    Lorem ipsum
  </div>
</div>

.grey-box {
    background-color: #e0e0e0; /* grey 300 */
    width: 320px;
    height: 240px;
    font: 900 24px Roboto;
    display: flex;
    align-items: center;
    justify-content: center;
}
.red-box {
    background-color: #ef5350; /* red 400 */
    padding: 16px;
    color: #ffffff;
    border-radius: 8px;
}
dart
final container = Container(
  // 灰色盒子
  width: 320,
  height: 240,
  color: Colors.grey[300],
  child: Center(
    child: Container(
      // 红色圆形
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: Colors.red[400],
        borderRadius: const BorderRadius.all(
          Radius.circular(8),
        ),
      ),
      child: Text(
        'Lorem ipsum',
        style: bold24Roboto,
      ),
    ),
  ),
);

添加方框阴影

#

在 CSS 中,您可以使用 box-shadow 属性以简写方式指定阴影偏移量和模糊度。此示例显示两个方框阴影,其属性为:

  • xOffset: 0px, yOffset: 2px, blur: 4px, color: black @80% alpha
  • xOffset: 0px, yOffset: 06x, blur: 20px, color: black @50% alpha

在 Flutter 中,每个属性和值都是单独指定的。使用 BoxDecorationboxShadow 属性创建 BoxShadow 小部件列表。您可以定义一个或多个 BoxShadow 小部件,这些小部件可以堆叠在一起以自定义阴影深度、颜色等等。

css
<div class="grey-box">
  <div class="red-box">
    Lorem ipsum
  </div>
</div>

.grey-box {
    background-color: #e0e0e0; /* grey 300 */
    width: 320px;
    height: 240px;
    font: 900 24px Roboto;
    display: flex;
    align-items: center;
    justify-content: center;
}
.red-box {
    background-color: #ef5350; /* red 400 */
    padding: 16px;
    color: #ffffff;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.8),
              0 6px 20px rgba(0, 0, 0, 0.5);
}
dart
final container = Container(
  // 灰色盒子
  width: 320,
  height: 240,
  margin: const EdgeInsets.only(bottom: 16),
  decoration: BoxDecoration(
    color: Colors.grey[300],
  ),
  child: Center(
    child: Container(
      // 红色盒子
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: Colors.red[400],
        boxShadow: const <BoxShadow>[
          BoxShadow(
            color: Color(0xcc000000),
            offset: Offset(0, 2),
            blurRadius: 4,
          ),
          BoxShadow(
            color: Color(0x80000000),
            offset: Offset(0, 6),
            blurRadius: 20,
          ),
        ],
      ),
      child: Text(
        'Lorem ipsum',
        style: bold24Roboto,
      ),
    ),
  ),
);

创建圆形和椭圆形

#

在 CSS 中创建圆形需要一种变通方法,即将 50% 的 border-radius 应用于矩形的四个边,尽管存在基本形状

虽然此方法受 BoxDecorationborderRadius 属性支持,但 Flutter 为此目的提供了具有 BoxShape 枚举shape 属性。

css
<div class="grey-box">
  <div class="red-circle">
    Lorem ipsum
  </div>
</div>

.grey-box {
    background-color: #e0e0e0; /* grey 300 */
    width: 320px;
    height: 240px;
    font: 900 24px Roboto;
    display: flex;
    align-items: center;
    justify-content: center;
}
.red-circle {
    background-color: #ef5350; /* red 400 */
    padding: 16px;
    color: #ffffff;
    text-align: center;
    width: 160px;
    height: 160px;
    border-radius: 50%;
}
dart
final container = Container(
  // 灰色盒子
  width: 320,
  height: 240,
  color: Colors.grey[300],
  child: Center(
    child: Container(
      // 红色圆形
      decoration: BoxDecoration(
        color: Colors.red[400],
        shape: BoxShape.circle,
      ),
      padding: const EdgeInsets.all(16),
      width: 160,
      height: 160,
      child: Text(
        'Lorem ipsum',
        style: bold24Roboto,
        textAlign: TextAlign.center,
      ),
    ),
  ),
);

操作文本

#

以下示例显示如何指定字体和其他文本属性。它们还显示如何转换文本字符串、自定义间距和创建摘录。

调整文本间距

#

在 CSS 中,您可以分别为 letter-spacing 和 word-spacing 属性指定长度值来指定每个字母或单词之间的空格量。空格量可以是 px、pt、cm、em 等。

在 Flutter 中,您可以为 Text 小部件的 TextStyle 子项的 letterSpacingwordSpacing 属性指定逻辑像素作为空格(允许负值)。

css
<div class="grey-box">
  <div class="red-box">
    Lorem ipsum
  </div>
</div>

.grey-box {
    background-color: #e0e0e0; /* grey 300 */
    width: 320px;
    height: 240px;
    font: 900 24px Roboto;
    display: flex;
    align-items: center;
    justify-content: center;
}
.red-box {
    background-color: #ef5350; /* red 400 */
    padding: 16px;
    color: #ffffff;
    letter-spacing: 4px;
}
dart
final container = Container(
  // 灰色盒子
  width: 320,
  height: 240,
  color: Colors.grey[300],
  child: Center(
    child: Container(
      // 红色盒子
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: Colors.red[400],
      ),
      child: const Text(
        'Lorem ipsum',
        style: TextStyle(
          color: Colors.white,
          fontSize: 24,
          fontWeight: FontWeight.w900,
          letterSpacing: 4,
        ),
      ),
    ),
  ),
);

进行内联格式更改

#

Text 小部件允许您显示具有某些格式特征的文本。要显示使用多种样式的文本(在此示例中,一个带有强调的单词),请改用 RichText 小部件。它的 text 属性可以指定一个或多个 TextSpan 对象,这些对象可以单独设置样式。

在以下示例中,“Lorem”位于具有默认(继承)文本样式的 TextSpan 中,“ipsum”位于具有自定义样式的单独 TextSpan 中。

css
<div class="grey-box">
  <div class="red-box">
    Lorem <em>ipsum</em>
  </div>
</div>

.grey-box {
    background-color: #e0e0e0; /* grey 300 */
    width: 320px;
    height: 240px;
    font: 900 24px Roboto;
    display: flex;
    align-items: center;
    justify-content: center;
}
.red-box {
    background-color: #ef5350; /* red 400 */
    padding: 16px;
    color: #ffffff;
}
.red-box em {
    font: 300 48px Roboto;
    font-style: italic;
}
dart
final container = Container(
  // 灰色盒子
  width: 320,
  height: 240,
  color: Colors.grey[300],
  child: Center(
    child: Container(
      // 红色盒子
      decoration: BoxDecoration(
        color: Colors.red[400],
      ),
      padding: const EdgeInsets.all(16),
      child: RichText(
        text: TextSpan(
          style: bold24Roboto,
          children: const <TextSpan>[
            TextSpan(text: 'Lorem '),
            TextSpan(
              text: 'ipsum',
              style: TextStyle(
                fontWeight: FontWeight.w300,
                fontStyle: FontStyle.italic,
                fontSize: 48,
              ),
            ),
          ],
        ),
      ),
    ),
  ),
);

创建文本摘录

#

摘录显示段落中的初始行,并处理溢出文本,通常使用省略号。

在 Flutter 中,使用 Text 小部件的 maxLines 属性指定要包含在摘录中的行数,并使用 overflow 属性处理溢出文本。

css
<div class="grey-box">
  <div class="red-box">
    Lorem ipsum dolor sit amet, consec etur
  </div>
</div>

.grey-box {
    background-color: #e0e0e0; /* grey 300 */
    width: 320px;
    height: 240px;
    font: 900 24px Roboto;
    display: flex;
    align-items: center;
    justify-content: center;
}
.red-box {
    background-color: #ef5350; /* red 400 */
    padding: 16px;
    color: #ffffff;
    overflow: hidden;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
}
dart
final container = Container(
  // 灰色盒子
  width: 320,
  height: 240,
  color: Colors.grey[300],
  child: Center(
    child: Container(
      // 红色盒子
      decoration: BoxDecoration(
        color: Colors.red[400],
      ),
      padding: const EdgeInsets.all(16),
      child: Text(
        'Lorem ipsum dolor sit amet, consec etur',
        style: bold24Roboto,
        overflow: TextOverflow.ellipsis,
        maxLines: 1,
      ),
    ),
  ),
);

(这段内容本身就是链接和对应中文名称的映射,不需要进行翻译。)