likes
comments
collection
share

Flutter中的布局

作者站长头像
站长
· 阅读数 52
重点是什么?
· 小部件是用于构建UI的类
· 小部件用于布局和UI元素
· 组合简单的小部件来构建复杂的小部件

Flutter布局机制的核心是widgets。在Flutter中,几乎一切都是小部件——甚至布局模型也是小部件。您在Flutter应用程序中看到的图像、图标和文本都是小部件。但是你看不到的东西也是小部件,例如排列、约束和对齐可见小部件的行、列和网格。

您通过组合小部件来创建创建布局以构建更复杂的小部件。例如,下面的第一个屏幕截图显示了3个图标,每个图标下面都有一个标签:

Flutter中的布局 Flutter中的布局

第二个屏幕截图显示了视觉布局 ,显示一行3列,其中每列包含一个图标和标签。

这是此UI的小部件树图: Flutter中的布局

其中大部分看起来应该与您的预期一样,但您可能想追到容器(以粉红色显示)。Container是一个小部件类,允许您自定义其子小部件。当您想要添加填充、边距、边框或背景颜色时,请使用Container来命名它的一些功能。

在此示例中,每个Text小部件都放置在Container中以添加 边距。整个行也放置在Container中以在行中为添加padding。

此示例中的其余UI由属性控制。使用其color属性设置图标 的颜色。使用Text.style属性设置字体、颜色、粗细等。列和行的属性允许您指定它们的子元素如何垂直或水平对齐,以及 子元素应占据多少空间。

一、布置一个小部件

如何在Flutter布局单个小部件?本节向您展示如何创建和显示一个简单的小部件。它还显示了一个简单的Hello World应用程序的完整代码。

在Flutter中,只需几个步骤 即可将文本、图标或图像显示在屏幕上。

1、选择一个布局小部件

根据您希望如何对齐或约束可见小部件,从各种layout. widgets中进行选择,因为这些特征通常会传递给包含的小部件。

此示例使用Center,其中水平和垂直居中。

2、创建一个可见的小部件

例如,创建一个Text小部件:

Text('Hello World'),

创建一个Image小部件:

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

创建一个Icon小部件:

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

3、在布局widget中添加visible widget

所有布局小部件都具有以下之一:

  • 如果他们带一个孩子,使用child属性——例如,Center或者Container
  • 如果他们采用小部件列表,使用children属性,例如RowColumnListViewStack.

Text将小部件添加到Center部件:

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

4、在页面中添加布局小部件

Flutter应用程序本身就是一个小部件,大多数小部件都有一个build()方法。在应用程序的方法中实例化并返回一个小部件build()会显示该小部件。

Material apps

对于Material应用程序,您可以使用Scaffold小部件;它提供默认banner、background color,并且有用于添加drawer、snack bars,和bottom sheet的API。然后您可以将Center小部件直接添加到body属性中。

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

Non-Material apps

对于非Material应用程序,您可以将Center小部件添加到应用程序的build()方法中:

class MyApp extends StatelessWidget {
    const MyApp(Key? key) : super(key: key);
    
    @override
    Widget build(BuildContext context) {
        return Container(
            decoration: const BoxDecoration(color: Colors.white),
            child: Text(
                'Hello World',
                textDirection: TextDirection.ltr,
                style: TextStyle(
                    fontSize: 32,
                    color: Colors.black87,
                ),
            ),
        );
    }
}

默认情况下,非Material应用程序不包含AppBar、标题或背景颜色。如果您想在非Material应用程序中使用这些功能,则必须自己构建它们。此应用程序将背景颜色更改为白色,将文本更改为深灰色以模仿Material应用程序。

就是这样!运行应用程序时,您应该会看到Hello World

Flutter中的布局

二、垂直和水平布局多个小部件

最常见的布局模式之一是垂直或水平排列小部件。您可以使用Row小部件水平排列小部件,使用Column小部件垂直排列小部件。

重点是什么?
· `Row``Column`是两种最常用的布局模式。
· `Row``Column`每个都有一个子布局列表。
· 子小部件本身可以是`Row``Column`或其他复杂小部件。
· 您可以指定行或列如何垂直和水平对齐其子项。
· 您可以拉伸或约束特定的子部件。
· 您可以指定子部件如何使用行或列的可用空间。

要在Flutter中创建行或列,您可以将子部件列表添加到RowColumn部件。反过来,每个孩子本身可以是一行或 一列,等等,以下示例显示了如何在行或列内嵌套行或列。

此布局组织为Row。该行包含两个子项 :左侧的一列和右侧的图像:

Flutter中的布局

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

Flutter中的布局

2.1、对齐小部件

mainAxisAlignment您可以使用和crossAxisAlignment属性控制行或列如何对齐子项。对于一行,主轴水平运行,横轴垂直运行。对于列,主轴垂直运行,横轴水平运行。

Flutter中的布局

和 枚举提供了多种用于控制对齐的常量MainAxisAlignmentCrossAxisAlignment

在下面的示例中,3个图像中的每一个都是100像素宽。渲染框(在本例中为整个屏幕)超过300像素宽,因此将主轴对齐设置为spaceEvenly在每个图像之间、之前和之后平均划分自由水平空间。

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

Flutter中的布局

列的工作方式与行相同。以下示例显示一列3个图像,每个图像高100像素。渲染框(在本例中为整个屏幕)的高度超过3000像素,因此将主轴对齐设置为spaceEvenly,在每个图像、上方和下方平均划分 自由垂直空间。

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

Flutter中的布局

2.2、调整大小的小部件

当布局太大而不合适设备时,受影响的边缘会出现黄色和黑色条纹图案。这是一个太宽的行的示例:

Flutter中的布局 可以使用小部件调整小部件的大小以适应行或列Expanded。要修复前面示例中图像行对于其渲染框太宽的问题,请使用Expanded小部件包装每个图像。

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

Flutter中的布局

也许您希望小部件占用的空间是其兄弟部件的两倍。为此,请使用Expanded widget flex属性,它是一个整数,用于确定widget的弹性因子。默认弹性因子为1,以下代码将中间图像的弹性因子设置为2:

Flutter中的布局

Flutter中的布局

2.3、包装小部件

默认情况下,行或列沿其主轴占据尽可能多的空间,但如果您想将子项紧密地打包在一起,请将其设置mainAxisSizeMainAxisSize.min.以下示例使用此属性将星形图表打包在一起。

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]),
          const Icon(Icons.star, color: Colors.black),
          const Icon(Icons.star, color: Colors.black),
    ],
)

Flutter中的布局

2.4、嵌套行和列

布局框架允许您根据需要在行和列中嵌套行和列。让我们 看一下以下布局的概述部分的代码:

Flutter中的布局

概述部分实现为两行。评分行包含五颗星和评论数。图表行包含三列图表和文本。 评级行的小部件树:

Flutter中的布局

ratings变量创建一行,其中包含较小的一行5个星形图表和文本:

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

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

提示:  为了最大限度地减少嵌套布局代码可能导致的视觉混乱,请在变量和函数中实现 UI 的各个部分。

评级行下方的图标行包含3列;每列包含一个图标和两行文本,如您在其小部件树中所见:

Flutter中的布局

iconList变量定义图标行:

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

final iconList = DefaultTextStyle.merge(
    style: descTextStyle,
    child: Container(
        padding: const EdgeInsets.all(20),
        child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
                Column(
                    children: [
                        Icon(Icons.kitchen, color: Colors.green[500]).
                        const Text('PREP:'),
                        const Text('25 min'),
                    ],
                ),
                Column(
                    children: [
                        Icon(Icons.timer, color: Colors.green[500]),
                        const Text('COOK:'),
                        const Text('1 hr'),
                    ],
                ),
                Column(
                    children: [
                        Icon(Icons.restuarant, color: Colors.green[500]),
                        const Text('FEEDS:'),
                        const Text('4-6'),
                    ],
                ),
            ],
        ),
    ),
);

leftColumn变量包含评级和图标行,以及描述Pavlova的标题和文本:

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

column左侧放一个限制其宽度的SizedBox小部件。最后,用一个Card来显示UI。

Pavlova图片来自Pixabay 。您可以使用嵌入来自网络的图像,Image.network()但对于本示例,图像将保存到项目中的图像目录,添加到pubspec 文件,并使用 访问Images.asset()

body: Center(
    child: Container(
        margin: const EdgeInsets.fromLTRB(0, 40, 0, 30),
        height: 600,
        child: Row(
            crossAxisAlignment: CrossAxisAlignmeng.start,
            children: [
                SizedBox(
                    width: 440,
                    children: leftColumn,
                ),
                mainImage,
            ],
        ),
    ),
),
转载自:https://juejin.cn/post/7191057584210575416
评论
请登录