Flutter 常见布局模型

Flutter的常见的布局模型有容器(Container)、弹性盒子布局(Flex、Row、Column、Expanded)、流式布局(Wrap、Flow)、层叠布局(Stack、Position)、滚动布局(ListView、GridView)等。
布局模型也都是 widget,很多布局widget都继承自Container,其布局UI树状图如图:
布局

布局容器 Container

创建一个项目:

flutter create buju

lib/main.dart 代码

import 'dart:math' as math;
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(),
        body: Container(
          height: 50,
          width: 100,
          alignment: Alignment.center,
          decoration: BoxDecoration(
            color: Colors.grey,
            borderRadius: BorderRadius.all(Radius.circular(10.0)),
            border: Border.all(color: Colors.black, width: 2.0),
          ),
          margin: EdgeInsets.fromLTRB(200, 50, 0, 0),
          transform: Matrix4.rotationZ(30 * math.pi / 180),
          child: Text("Container \n布局"),
        ),
      ),
    );
  }
}

从上面代码可以看到 Container 布局有很多属性:
color 设置容器的背景色。
width 设置容器的宽。
height 设置容器的高。
alignment 设置子widget的对齐方式,如居中。
decoration 设置背景装饰,如阴影、背景图等。
foregroundDecoration 设置前景装饰,比如前景色。
margin 设置容器等外边距。
padding 设置容器等内边距。
transform 设置形变,如需旋转、拉长等。
child 设置容器包裹的子Widget。
更多请见文档。

效果图如下:
1

弹性盒子布局

Flex

direction 设置主轴排列方向

Flex 有个重要的属性 direction,用来指定主轴的方向,子元素会按照主轴的方向排列。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(),
        body: Flex(
          direction: Axis.horizontal,
          children: <Widget>[
            Container(
              width: 30,
              height: 50,
              color: Colors.red,
            ),
            Container(
              width: 30,
              height: 50,
              color: Colors.green,
            ),
            Container(
              width: 30,
              height: 50,
              color: Colors.grey,
            ),
          ],
        ),
      ),
    );
  }
}

这里主轴方向是horizontal水平方向,效果图如下:
Flex
改成垂直direction: Axis.vertical,后的效果:
Flex

mainAxisAlignment 设置子元素排列方式

另一个重要属性是mainAxisAlignment,用来决定主轴的排列方式。
默认是start:mainAxisAlignment: MainAxisAlignment.start
end:指最后一个元素排在主轴的最后。这里以主轴水平方向排列为例,如下图:
1
center:所有子元素按照主轴方向依次排列,并居中显示在父容器中。如下图:
center
spaceAround:每个子元素之间的间隔相等,第一个元素和最后一个元素距离父容器的边距为孩子之间间距的一半。如下图:
spaceAround
spaceBetween:子元素两端对齐,第一个子元素和最后一个子元素分别位于容器中主轴的起始处和终止处,同时各个子元素之间的间隔相等,如下图:
spaceBetween
spaceEvenly: 各个子元素之间的间隔相等,同时第一个子元素和最后一个子元素距离父容器的边距也为各子元素之间的间隔。
spaceEvenly

mainAxisSize 设置主轴大小

mainAxisSize默认是max,Flex容器占据主轴全部空间。
还可以设置为min,Flex容器尽可能占据少的主轴空间。

direction: Axis.horizontal,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.min,

mainAxisSize
这里把Flex容器设置为最小的大小,导致三个子元素挤在了一起。

crossAxisAlignment 设置交叉轴对齐方式

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(),
        body: Flex(
          direction: Axis.horizontal,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            Container(
              width: 30,
              height: 100,
              color: Colors.red,
            ),
            Container(
              width: 30,
              height: 50,
              color: Colors.green,
            ),
            Container(
              width: 30,
              height: 50,
              color: Colors.grey,
            ),
          ],
        ),
      ),
    );
  }
}

crossAxisAlignment 用来设置元素在交叉轴方向上的对齐方式。
默认值是center,各个子元素在交叉轴上居中对齐。如下图(这里以主轴沿水平方向):
center
end:子元素布局在Flex容器交叉轴方向的尾部。
end

start:子元素布局在Flex容器交叉轴方向的头部。
start
stretch:子元素填充满交叉轴方向的空间。
stretch

verticalDirection 设置交叉轴布局的对齐方向

这个属性和上面的crossAxisAlignment属性配合使用,用于指定交叉轴布局的对齐方向
默认值是down,表示默认对齐的方向是从上到下,crossAxisAlignment默认start时,三个元素在顶部。
如果将verticalDirection改成up,表示从下到上,crossAxisAlignment还是默认start时,效果图如下:
verticalDirection
Row 和 Column 都继承自Flex,所以Flex都属性同样适用于Row和Column,只是预先指定好了主轴的方向。
Row表示在水平方向上布局子元素,主轴方向是水平方向。
Column表示在垂直方向上布局子元素,主轴方向是垂直方向。
Flex 更多参数见:https://api.flutter-io.cn/flutter/widgets/Flex-class.html

Expanded 按比例缩放

Expanded 布局能让子元素能够按照一定的比例缩放,来填充满父容器在主轴方向上剩余的剩余空间。通常,Expanded 组件通常是作为Flex 组件的子组件使用。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(),
        body: Flex(
          direction: Axis.horizontal,
          children: <Widget>[
            Expanded(
              flex: 1,
              child: Container(
                height: 150,
                color: Colors.red,
              ),
            ),
            Expanded(
              flex: 1,
              child: Container(
                height: 150,
                color: Colors.green,
              ),
            ),
            Expanded(
              flex: 1,
              child: Container(
                height: 150,
                color: Colors.blue,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

效果图:
Expanded
如果把 Expanded 的 Flex 属性分别设置为 1,2,3,得到的效果图如下:
Flex

流式布局

在弹性布局中,如果宽度或高度超过屏幕尺寸,会抛出异常:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(),
        body: Flex(
          direction: Axis.horizontal,
          children: <Widget>[
            Container(
              width: 150,
              height: 100,
              color: Colors.red,
            ),
            Container(
              width: 280,
              height: 50,
              color: Colors.green,
            ),
            Container(
              width: 50,
              height: 50,
              color: Colors.grey,
            ),
          ],
        ),
      ),
    );
  }
}

1

════════ Exception caught by rendering library ═════════════════════════════════
The following assertion was thrown during layout:
A RenderFlex overflowed by 105 pixels on the right.

这是因为弹性和子布局模型是线性的,不会自动换行。

Wrap 自动换行的容器

Wrap支持子元素自动换行,默认主轴水平方向。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(),
        body: Wrap(
          direction: Axis.horizontal,
          spacing: 10,
          runAlignment: WrapAlignment.start,
          verticalDirection: VerticalDirection.down,
          runSpacing: 10,
          children: <Widget>[
            Container(
              width: 150,
              height: 150,
              color: Colors.red,
            ),
            Container(
              width: 200,
              height: 50,
              color: Colors.green,
            ),
            Container(
              width: 50,
              height: 50,
              color: Colors.grey,
            ),
            Container(
              width: 200,
              height: 150,
              color: Colors.black,
            ),
          ],
        ),
      ),
    );
  }
}

alignment、crossAxisAlignment、verticalDirection 与 Flex 的同名属性作用相同。
runAlignment 用来设置新一行或新一列的对齐方式。默认值是start,如果主轴方向是水平方向,start就是在交叉轴方向上从顶部开始布局子元素,如下图。end 是在交叉轴方向上从底部开始布局子元素。center 设置居中对齐,子元素会从交叉轴方向上父容器的中心开始布局。
runAlignment

Flow 布局允许用户自定义布局规则,具体参数见:https://api.flutter-io.cn/flutter/widgets/Flow-class.html

层叠布局:绝对定位

Stack 布局类似Web开发中的绝对定位。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar(),
          body: Center(
            child: Stack(
              children: <Widget>[
                Container(
                  width: 150,
                  height: 150,
                  color: Colors.red,
                ),
                Positioned(
                  left: 8.0,
                  right: 8.0,
                  top: 8.0,
                  child: Text('测试'),
                )
              ],
            ),
          )),
    );
  }
}

这个例子是对Text组件和Container组件的重叠,其中Positioned是定位组件,只能放在Stack中。
Stack

滚动布局

ListView 处理大量数据

当数据量特别大时,上面的布局方式实现起来会非常麻烦,而用滚动布局,直接将数据放入滚动布局模型的 children 数据中即可。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar(),
          body: ListView.builder(
              itemCount: 50,
              itemExtent: 50,
              itemBuilder: (BuildContext context, int index) {
                return Container(
                  height: 50,
                  child: Row(
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: [Text('索引: ${index + 1}')],
                  ),
                );
              })),
    );
  }
}

1
详细参数见文档:https://api.flutter-io.cn/flutter/widgets/ListView-class.html。

ListView.separated 增加分割线

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar(),
          body: ListView.separated(
              itemCount: 50,
              separatorBuilder: (BuildContext context, int ndex) {
                return Divider();
              },
              itemBuilder: (BuildContext context, int index) {
                return SizedBox(
                  height: 50,
                  child: Row(
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: [Text('索引: ${index + 1}')],
                  ),
                );
              })),
    );
  }
}

1

GridView 构建多行多列表格

GridView 的创建需要一个 delegate 代表,即属性 gridDelegate , Flutter SDK 默认提供了两个 SliverGridDelegate 的子类,分别是: SliverGridDelegateWithFixedCrossAxisCount 和 SliverGridDelegateWithMaxCrossAxisExtent 。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar(),
          body: GridView(
            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 3, crossAxisSpacing: 8, mainAxisSpacing: 8),
            children: [
              Container(
                width: 50,
                height: 50,
                color: Colors.red,
              ),
              Container(
                width: 50,
                height: 50,
                color: Colors.red,
              ),
              Container(
                width: 50,
                height: 50,
                color: Colors.red,
              ),
              Container(
                width: 50,
                height: 50,
                color: Colors.red,
              ),
              Container(
                width: 50,
                height: 50,
                color: Colors.red,
              ),
              Container(
                width: 50,
                height: 50,
                color: Colors.red,
              ),
            ],
          )),
    );
  }
}

效果图:
1

动态创建 GridView

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(),
        body: GridView.builder(
            gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
                maxCrossAxisExtent: 8,
                mainAxisSpacing: 8,
                crossAxisSpacing: 8,
                childAspectRatio: 2.0),
            itemBuilder: (BuildContext context, int index) {
              return Container(
                color: Colors.red,
                width: 50,
                height: 50,
              );
            }),
      ),
    );
  }
}

1
maxCrossAxisExtent 设置条目的宽度。
mainAxisSpacing 设置主轴的间隔。
crossAxisSpacing 设置交叉轴间隔。
childAspectRatio 设置子元素的宽高比。

相关链接

https://docs.flutter.cn/ui/layout/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/970401.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java类与类的关系

类与类之间最常见的关系主要有以下三种&#xff1a; 依赖&#xff08;或uses–a&#xff09;聚合&#xff08;或has–a&#xff09;继承&#xff08;或is–a&#xff09; 依赖 依赖关系是类中最常见的关系&#xff0c;例如订单类&#xff08;order&#xff09;需要访问用户账…

神经网络的学习 求梯度

import sys, ossys.path.append(os.pardir) import numpy as npfrom common.functions import softmax, cross_entropy_error from common.gradient import numerical_gradient# simpleNet类 class simpleNet:def __init__(self):self.W np.random.rand(2, 3) # 随机形状为2*…

架构——Nginx功能、职责、原理、配置示例、应用场景

以下是关于 Nginx 的功能、职责、原理、配置示例、应用场景及其高性能原因的详细说明&#xff1a; 一、Nginx 的核心功能 1. 静态资源服务 功能&#xff1a;直接返回静态文件&#xff08;如 HTML、CSS、JS、图片、视频等&#xff09;。配置示例&#xff1a;server {listen 80…

如何在 Mac 上解决 Qt Creator 安装后应用程序无法找到的问题

在安装Qt时&#xff0c;遇到了一些问题&#xff0c;尤其是在Mac上安装Qt后&#xff0c;发现Qt Creator没有出现在应用程序中。通过一些搜索和操作&#xff0c;最终解决了问题。以下是详细的记录和解决方法。 1. 安装Qt后未显示Qt Creator 安装完成Qt后&#xff0c;启动应用程…

优选算法《位运算》

在本篇当中我们将会复习之前在C语言阶段学习的各种位运算&#xff0c;并且在复习当中将再补充一些在算法题当中没有进行总结的位运算的使用方法&#xff0c;再总结完常见的位运算使用方法之和接下来还是和之前的算法篇章一样通过几道算法题来对这些位运算的方法技巧进行巩固。在…

应对DeepSeek总是服务器繁忙的解决方法

最近由于访问量过大&#xff0c;DeepSeek服务器官网经常弹出&#xff1a;“服务器繁忙&#xff0c;请稍后再试”的提示&#xff0c;直接卡成PPT怎么办&#xff1f;服务器繁忙直接看到视觉疲劳&#xff1a; 解决DeepSeek卡顿问题 DeepSeek使用卡顿问题&#xff0c;是因为访问量…

docker容器部署jar应用导入文件时候报缺少字体错误解决

如题&#xff0c;在导入文件时候报错如下&#xff1a; Handler dispatch failed; nested exception is java.lang.NoClassDefFoundError: Could not initialize class sun.awt.X11FontManager 经查是缺少对应字体&#xff0c;解决办法有两张&#xff1a; 第一种&#xff1a;…

工作室如何实现一机一IP

对于工作室而言&#xff0c;多开游戏账号却是其运营模式的核心需求。他们通过大量囤积金币、资源&#xff0c;再将其变现来获取利润。在这种运营模式下&#xff0c;账号数量直接关系到工作室的收益&#xff0c;所以解决 IP 问题就成了手游工作室发展道路上的首要难题&#xff0…

使用grafana v11 建立k线(蜡烛图)仪表板

先看实现的结果 沪铜主力合约 2025-02-12 的1分钟k线图 功能介绍: 左上角支持切换主力合约,日期,实现动态加载数据. 项目背景: 我想通过前端展示期货指定品种某1天的1分钟k线,类似tqsdk 的web_gui 生成图形化界面— TianQin Python SDK 3.7.8 文档 项目架构: 后端: fastap…

20250214在ubuntu20.04下使用obs studio录制外挂的1080p的USB摄像头【下载安装】

20250214在ubuntu20.04下使用obs studio录制外挂的1080p的USB摄像头 2025/2/14 9:10 缘起&#xff1a;笔记本电脑在ubuntu20.04下使用Guvcview录制自带的摄像头&#xff0c;各种问题。 1、降帧率。WIN10/11自带的相机应用可以满速30fps&#xff0c;马上重启到ubuntu20.04&#…

【开源免费】基于Vue和SpringBoot的旅游管理系统(附论文)

本文项目编号 T 229 &#xff0c;文末自助获取源码 \color{red}{T229&#xff0c;文末自助获取源码} T229&#xff0c;文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…

基于Python的Optimal Interpolation (OI) 方法实现

前言 Optimal Interpolation (OI) 方法概述与实现 Optimal Interpolation (OI) 是一种广泛应用于气象学、海洋学等领域的空间数据插值方法。该方法通过结合观测数据与模型预测数据&#xff0c;最小化误差方差&#xff0c;从而实现对空间数据的最优插值。以下是OI方法的一般步骤…

从无序到有序:上北智信通过深度数据分析改善会议室资源配置

当前企业普遍面临会议室资源管理难题&#xff0c;预约机制不完善和临时会议多导致资源调度不合理&#xff0c;既有空置又有过度拥挤现象。 针对上述问题&#xff0c;上北智信采用了专业数据分析手段&#xff0c;巧妙融合楼层平面图、环形图、折线图和柱形图等多种可视化工具&a…

CAS单点登录(第7版)9.属性

如有疑问&#xff0c;请看视频&#xff1a;CAS单点登录&#xff08;第7版&#xff09; 属性 属性定义 概述 属性定义 从身份验证或属性存储库源获取和解析 CAS 中属性的定义时&#xff0c;往往使用其名称进行定义和引用&#xff0c;而无需任何其他元数据或修饰。例如&#…

Halo 配置QQ邮箱验证教程

一、准备工作 获取QQ邮箱授权码 登录QQ邮箱网页版&#xff08;https://mail.qq.com&#xff09;。 点击顶部导航栏 "设置" → "账户" → 找到 "POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务"。 点击 "生成授权码"&#xff0c;按页面…

双轴伺服电机驱动控制器AGV、AMR专用双伺服电机驱动控制器解决方案

工业机器人数控机床XY机械手双轴机器人堆垛机专用双轴伺服电机驱动控制器48V 14ARMS带有STO功能&#xff0c;隔离高压CAN/RS485/USB通讯支持编码器和霍尔输入 双伺服电机驱动控制器TMCM2611功能介绍 集成2个伺服电机的控制和驱动于一体供电电压48V&#xff0c;驱动电流14A RM…

Springboot中使用Elasticsearch(部署+使用+讲解 最完整)

目录 引言 一、docker中安装Elasticsearch 1、创建es专有的网络 2、开放端口 3、在es-net网络上安装es和kibana 4、可能出现的问题 5、测试 6、安装IK分词器 7、测试IK分词器 二、结合业务实战 1、准备依赖 2、配置yml 3、读取yml配置 4、准备es配置类 5、编写测…

NVIDIA Jetson Orin Nano 刷机过程

1. 背景 新到手 NVIDIA Jetson Orin Nano 插上显示屏&#xff0c;显示如下&#xff1a; 这是UEFI Shell&#xff0c;UEFI Shell&#xff08;统一可扩展固件接口外壳程序&#xff09;是一种基于UEFI规范的交互式命令行工具&#xff0c;它运行在UEFI固件环境中&#xff0c;为用…

buu-jarvisoj_level2_x64-好久不见37

覆盖缓冲区和 RBP&#xff1a; 使用 128 8 字节覆盖 buf 和 rbp。 构造 ROP 链&#xff1a; pop rdi; ret 地址&#xff1a; 将 pop rdi; ret 指令的地址写入返回地址位置。 /bin/sh 地址&#xff1a; 将 /bin/sh 字符串的地址压入栈顶&#xff0c;作为 system 函数的参数。…

UE求职Demo开发日志#32 优化#1 交互逻辑实现接口、提取Bag和Warehouse的父类

1 定义并实现交互接口 接口定义&#xff1a; // Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h" #include "UObject/Interface.h" #include "MyInterActInterface.generated.h…