Flutter基础 -- Flutter容器布局

news2025/4/19 12:02:25

目录

1. MaterialApp

1.1 组件定义

1.2 主要功能和属性

1.3 示例

2. 脚手架 Scaffold

2.1 定义

2.2 Scaffold 的属性

2.3 示例

PS: 对于 Scaffold 和 MaterialApp

3. 线性布局 Column Row

3.1 Row

3.2 Column

4. 盒模型 Box Model

4.1 定义

4.2 示例

5. 容器 Container

5.1 定义

5.2 示例

6. 弹性布局 Flex

6.1 Flex

6.2 Expanded

6.3 留白 Spacer 

7. 层叠布局 Stack

7.1 Stack

7.2 Positioned

7.3 示例

8. 流式布局 Wrap

8.1 定义

8.2 示例

9. 对齐定位 Align

9.1 Align

9.2 Alignment

9.3 FractionalOffset

9.4 Center


博主wx:yuanlai45_csdn 博主qq:2777137742

后期会创建粉丝群,为同学们提供分享交流平台以及提供官方发送的福利奖品~

1. MaterialApp

1.1 组件定义

Material 风格的程序的构建,当然相对应的是 ios 风格是 CupertinoApp

MaterialApp class - material library - Dart API

CupertinoApp class - cupertino library - Dart API

MaterialApp 是整个应用的根组件,它提供了应用的基础配置和框架。它承担了设定应用主题、路由以及其他全局配置的责任。

1.2 主要功能和属性

  1. title: 应用的标题,通常在任务管理器中显示
  2. theme: 应用的全局主题,定义了颜色、字体等统一样式
  3. home: 应用启动时的默认页面或根页面
  4. routes: 定义命名路由,用于应用内导航
  5. navigatorKey: 全局唯一的 Navigator,用于导航管理
  6. locale: 用于指定应用语言和区域的 Locale
  7. localizationsDelegates: 本地化的代理,用于支持多语言
  8. debugShowCheckedModeBanner: 控制是否显示调试模式横幅
const MaterialApp({
  Key key,
  // 导航键 , key的作用提高复用性能
  this.navigatorKey,
  // 主页
  this.home,
  // 路由
  this.routes = const <String, WidgetBuilder>{},
  // 初始命名路由
  this.initialRoute,
  // 路由构造
  this.onGenerateRoute,
  // 未知路由
  this.onUnknownRoute,
  // 导航观察器
  this.navigatorObservers = const <NavigatorObserver>[],
  // 建造者
  this.builder,
  // APP 标题
  this.title = '',
  // 生成标题
  this.onGenerateTitle,
  // APP 颜色
  this.color,
  // 样式定义
  this.theme,
  // 主机暗色模式
  this.darkTheme,
  // 样式模式
  this.themeMode = ThemeMode.system,
  // 多语言 本地化
  this.locale,
  // 多语言代理
  this.localizationsDelegates,
  // 多语言回调
  this.localeListResolutionCallback,
  this.localeResolutionCallback,
  // 支持的多国语言
  this.supportedLocales = const <Locale>[Locale('en', 'US')],
  // 调试显示材质网格
  this.debugShowMaterialGrid = false,
  // 显示性能叠加
  this.showPerformanceOverlay = false,
  // 检查缓存图片的情况
  this.checkerboardRasterCacheImages = false,
  // 检查不必要的setlayer
  this.checkerboardOffscreenLayers = false,
  // 显示语义调试器
  this.showSemanticsDebugger = false,
  // 显示debug标记 右上角
  this.debugShowCheckedModeBanner = true,
})

1.3 示例

代码

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      // APP 标题
      // ios 没有用、 android 进程名称 、 web 标题tab栏名称
      title: 'Material App',

      // APP 颜色
      color: Colors.green,

      // 样式
      theme: ThemeData(
        primarySwatch: Colors.yellow,
      ),

      // 主机暗色模式
      darkTheme: ThemeData(
        primarySwatch: Colors.red,
      ),

      // 显示debug标记 右上角
      // debugShowCheckedModeBanner: false,

      // 调试显示材质网格
      // debugShowMaterialGrid: true,

      // 显示性能叠加
      // showPerformanceOverlay: true,

      // 检查缓存图片的情况
      // checkerboardRasterCacheImages: true,

      // 检查不必要的setlayer
      // checkerboardOffscreenLayers: true,

      // 显示语义调试器
      // showSemanticsDebugger: true,

      // 首页
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Material App'),
        ),
        body: Center(
          child: Column(
            children: const [
              Text("data"),
              FlutterLogo(
                size: 100,
              ),
            ],
          ),
        ),
      ),
    );
  }
}

输出

2. 脚手架 Scaffold

2.1 定义

Scaffold 是一个页面布局脚手架,实现了基本的 Material 布局,继承自 StatefulWidget,是有状态组件。我们知道大部分的应用页面都是含有标题栏,主体内容,底部导航菜单或者侧滑抽屉菜单等等构成,那么每次都重复写这些内容会大大降低开发效率,所以 Flutter 提供了 Material 风格的 Scaffold 页面布局脚手架,可以很快地搭建出这些元素部分

对应 ios 的是 CupertinoPageScaffold

Scaffold class - material library - Dart API

CupertinoPageScaffold class - cupertino library - Dart API

2.2 Scaffold 的属性

以下是 Scaffold 组件的一些常用属性:

  1. appBar:即顶栏,可以包含标题、导航按钮、动作按钮等
  2. body:应用的主体部分,显示页面的主要内容
  3. bottomNavigationBar:底部导航栏,用于页面间的切换
  4. floatingActionButton:浮动操作按钮,通常用于表示主要操作,如添加或编辑
  5. drawer:侧边栏菜单,用于导航到不同的页面或显示其他选项
  6. backgroundColor:背景颜色
  7. resizeToAvoidBottomInset:控制应用在有键盘弹出时是否调整布局以避免遮挡输入框
const Scaffold({
    Key key,
    // 菜单栏
    this.appBar,
    // 中间主体内容部分
    this.body,
    // 悬浮按钮
    this.floatingActionButton,
    // 悬浮按钮位置
    this.floatingActionButtonLocation,
    // 悬浮按钮动画
    this.floatingActionButtonAnimator,
    // 固定在下方显示的按钮
    this.persistentFooterButtons,
    // 左侧 侧滑抽屉菜单
    this.drawer,
    // 右侧 侧滑抽屉菜单
    this.endDrawer,
    // 底部菜单
    this.bottomNavigationBar,
    // 底部拉出菜单
    this.bottomSheet,
    // 背景色
    this.backgroundColor,
    // 自动适应底部padding
    this.resizeToAvoidBottomPadding,
    // 重新计算body布局空间大小,避免被遮挡
    this.resizeToAvoidBottomInset,
    // 是否显示到底部,默认为true将显示到顶部状态栏
    this.primary = true,
    this.drawerDragStartBehavior = DragStartBehavior.down,
  })

2.3 示例

代码

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';

// class CupertinoPage extends StatelessWidget {
//   const CupertinoPage({Key? key}) : super(key: key);

//   @override
//   Widget build(BuildContext context) {
//     return const CupertinoPageScaffold(
//       navigationBar: CupertinoNavigationBar(
//         middle: Text('我是标题'),
//       ),
//       child: Center(
//         child: Text('我是内容'),
//       ),
//     );
//   }
// }

class ScaffoldPage extends StatelessWidget {
  const ScaffoldPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // 菜单栏
      appBar: AppBar(
        title: const Text('Material App Bar'),
      ),

      // 悬浮按钮
      // floatingActionButton: FloatingActionButton(
      //   onPressed: () {},
      //   child: const Icon(Icons.add_photo_alternate),
      // ),

      // 悬浮按钮位置
      // floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,

      // 固定在下方显示的按钮
      // persistentFooterButtons: const [
      //   Text('persistentFooterButtons1'),
      //   Text('persistentFooterButtons2'),
      // ],

      // 压缩顶部菜单空间
      // primary: true,

      // 左侧 侧滑抽屉菜单
      // drawer: const Drawer(
      //   child: Text('data'),
      // ),

      // 右侧 侧滑抽屉菜单
      // endDrawer: const Drawer(
      //   child: Text('data'),
      // ),

      // 检测手势行为方式,与drawer配合使用 down 方式有卡顿,可以 start 方式
      // drawerDragStartBehavior: DragStartBehavior.start,

      // 底部导航栏
      // bottomNavigationBar: const Text('bottomNavigationBar'),

      // 底部拉出菜单
      // bottomSheet: const Text('bottomSheet'),

      // 背景色
      // backgroundColor: Colors.amberAccent,

      // 自动适应底部padding
      // resizeToAvoidBottomInset: true,

      // 正文
      body: Builder(
        builder: (BuildContext context) {
          return Center(
            child: ElevatedButton(
              onPressed: () {
                // 脚手架管理
                // Scaffold.of(context).openDrawer();

                // 应用消息管理
                ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
                  content: Text('Hello!'),
                ));
              },
              child: const Text('showSnackBar'),
            ),
          );
        },
      ),
    );
  }
}

输出

PS: 对于 Scaffold 和 MaterialApp

MaterialApp 是整个应用根组件,它提供了应用的基础配置和框架。它承担了设定应用主题、路由以及其他全局配置的责任

Scaffold 是用来构建单个页面布局框架。它提供了一个包含顶栏、底部导航栏、浮动按钮和主体内容的基本结构

3. 线性布局 Column Row

3.1 Row

Row 布局组件类似于 Android 中的 LinearLayout 线性布局,它用来做水平横向布局使用,里面的 children 子元素按照水平方向进行排列。

Row class - widgets library - Dart API

定义

Row({
    Key key,
  	
  	// * 子元素集合
    List<Widget> children = const <Widget>[],
  
    // 主轴方向上的对齐方式(Row的主轴是横向轴)
    MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
    // 在主轴方向(Row的主轴是横向轴)占有空间的值,默认是max
    MainAxisSize mainAxisSize = MainAxisSize.max,
    // 在交叉轴方向(Row是纵向轴)的对齐方式,Row的高度等于子元素中最高的子元素高度
    CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
    
 		// 水平方向子元素的排列方向:从左到右排列还是反向
    TextDirection textDirection,
    // 表示纵轴(垂直)的对齐排列方向,默认是VerticalDirection.down,表示从上到下。这个参数一般用于Column组件里
    VerticalDirection verticalDirection = VerticalDirection.down,
    // 字符对齐基线方式
    TextBaseline textBaseline,

  })

MainAxisAlignment

主轴属性:主轴方向上的对齐方式,Row 是横向轴为主轴

enum MainAxisAlignment {
  // 按照主轴起点对齐,例如:按照靠近最左侧子元素对齐
  start,

  // 将子元素放置在主轴的末尾,按照末尾对齐
  end,

  // 子元素放置在主轴中心对齐
  center,

  // 将主轴方向上的空白区域均分,使得子元素之间的空白区域相等,首尾子元素都靠近首尾,没有间隙。有点类似于两端对齐
  spaceBetween,

  // 将主轴方向上的空白区域均分,使得子元素之间的空白区域相等,但是首尾子元素的空白区域为1/2
  spaceAround,

  // 将主轴方向上的空白区域均分,使得子元素之间的空白区域相等,包括首尾子元素
  spaceEvenly,
}

CrossAxisAlignment

交叉属性:在交叉轴方向的对齐方式,Row 是纵向轴。Row 的高度等于子元素中最高的子元素高度

enum CrossAxisAlignment {
  // 子元素在交叉轴上起点处展示
  start,

  // 子元素在交叉轴上末尾处展示
  end,

  // 子元素在交叉轴上居中展示
  center,

  // 让子元素填满交叉轴方向
  stretch,

  // 在交叉轴方向,使得子元素按照baseline对齐
  baseline,
}

MainAxisSize

在主轴方向子元素占有空间的方式,Row 的主轴是横向轴。默认是 max

enum MainAxisSize {
  // 根据传入的布局约束条件,最大化主轴方向占用可用空间,也就是尽可能充满可用宽度
  max,

  // 与max相反,是最小化占用主轴方向的可用空间
  min,
}

3.2 Column

Column 是纵向排列子元素

参数用法同上

Column class - widgets library - Dart API

代码

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        color: Colors.amber,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          // mainAxisSize: MainAxisSize.min,
          children: const [
            FlutterLogo(
              size: 24,
            ),
            FlutterLogo(
              size: 48,
            ),
            FlutterLogo(
              size: 128,
            ),
            FlutterLogo(
              size: 200,
            ),
          ],
        ),
      ),
    );
  }

输出

4. 盒模型 Box Model

Flutter 布局是混入了 RenderBox 特性,我们来了解下什么是盒模型

4.1 定义

盒子模型在 web 中是基础,所以本文参考了 mozilla w3schools

https://developer.mozilla.org/zh-CN/docs/Learn/CSS/Building_blocks/The_box_model

​​​​​​CSS Box Model

不同部分的说明:

  • Margin(外边距) - 边框意外的距离。
  • Border(边框) - 围绕在内边距和内容外的边框。
  • Padding(内边距) - 边框内部到内容的距离。
  • Content(内容) - 盒子的内容,显示文本和图像。

4.2 示例

代码

class BoxPage extends StatelessWidget {
  const BoxPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.blue,
      body: Container(
        // color: Colors.amber,

        // Margin(外边距)
        margin: const EdgeInsets.all(50),

        // Padding(内边距)
        padding: const EdgeInsets.all(20),

        // Content(内容)
        child: const Text("我是内容"),

        // 装饰样式
        decoration: BoxDecoration(
          // 背景色
          color: Colors.amber,

          // 边框
          border: Border.all(
            color: Colors.red,
            width: 10,
          ),
        ),
      ),
    );
  }
}

输出

5. 容器 Container

5.1 定义

Container 是一个组合类容器,它本身不对应具体的 RenderObject,它是 DecoratedBox、ConstrainedBox、Transform、Padding、Align 等组件组合的一个多功能容器,所以我们只需通过一个 Container 组件可以实现同时需要装饰、变换、限制的场景

Container class - widgets library - Dart API

下面是 Container 的定义:

Container({
    Key key,
    // 容器子Widget对齐方式
    this.alignment,
    // 容器内部padding
    this.padding,
    // 背景色
    Color color,
    // 背景装饰
    Decoration decoration,
    // 前景装饰
    this.foregroundDecoration,
    // 容器的宽度
    double width,
    // 容器的高度
    double height,
    // 容器大小的限制条件
    BoxConstraints constraints,
    // 容器外部margin
    this.margin,
    // 变换,如旋转
    this.transform,
    // 容器内子Widget
    this.child,
  })

BoxDecoration 装饰

const BoxDecoration({
  // 背景色
  this.color,
  // 背景图片
  this.image,
  // 边框样式
  this.border,
  // 边框圆角
  this.borderRadius,
  // 阴影
  this.boxShadow,
  // 渐变
  this.gradient,
  // 背景混合模式
  this.backgroundBlendMode,
  // 形状
  this.shape = BoxShape.rectangle,
})

5.2 示例

代码

import 'package:flutter/material.dart';

const img1 =
    "https://ducafecat.tech/2021/12/09/blog/2021-jetbrains-fleet-vs-vscode/2021-12-09-10-30-00.png";

class MyPage extends StatelessWidget {
  const MyPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        // 约束父容器
        constraints: const BoxConstraints.expand(
          height: 300.0,
        ),

        // 外边距
        margin: const EdgeInsets.all(20.0),

        // 内边距
        padding: const EdgeInsets.all(30.0),

        // 背景色
        // color: Colors.teal.shade700,

        // 子Widget居中
        alignment: Alignment.centerLeft,

        // 子Widget元素
        child: Text(
          'Hello World',
          style: TextStyle(
            fontSize: 34,
            fontWeight: FontWeight.bold,
            color: Colors.white,
          ),
        ),

        // 背景装饰
        decoration: const BoxDecoration(
          // 背景色
          color: Colors.blueAccent,
          // 圆角
          borderRadius: BorderRadius.all(
            Radius.circular(20.0),
          ),
          // 渐变
          // gradient: RadialGradient(
          //   colors: [Colors.red, Colors.orange],
          //   center: Alignment.topLeft,
          //   radius: .98,
          // ),
          // 阴影
          boxShadow: [
            BoxShadow(
              blurRadius: 2,
              offset: Offset(0, 2),
              color: Colors.blue,
            ),
          ],
          // 背景图
          image: DecorationImage(
            image: NetworkImage(img1),
            fit: BoxFit.cover,
          ),
          // 背景混合模式
          backgroundBlendMode: BlendMode.color,
          // 形状
          // shape: BoxShape.circle,
        ),

        // 前景装饰
        // foregroundDecoration: BoxDecoration(
        //   image: DecorationImage(
        //     image: AssetImage('assets/flutter.png'),
        //   ),
        // ),

        // Container旋转
        // transform: Matrix4.rotationZ(0.1),
      ),
    );
  }
}

void main() {
  runApp(MaterialApp(
    home: const MyPage(),
    theme: ThemeData(
      primarySwatch: Colors.blue,
    ),
  ));
}

6. 弹性布局 Flex

弹性布局允许子组件按照一定比例来分配父容器空间。

Flex class - widgets library - Dart API

6.1 Flex

我们可以发现 Column Row 组件都是继承与 Flex,功能非常强大,通常我们直接用 Column Row 即可

flutter/lib/src/widgets/basic.dart

/// * [Row], for a horizontal equivalent.

/// * [Flex], if you don't know in advance if you want a horizontal or vertical

/// arrangement.

/// * [Expanded], to indicate children that should take all the remaining room.

/// * [Flexible], to indicate children that should share the remaining room but

/// that may size smaller (leaving some remaining room unused).

/// * [SingleChildScrollView], whose documentation discusses some ways to

/// use a [Column] inside a scrolling container.

/// * [Spacer], a widget that takes up space proportional to its flex value.

/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).

class Column extends Flex {

...

6.2 Expanded

Expanded 只能放在 Flex、Column、Row 中使用

把包裹的元素撑开

代码

class FlexPage extends StatelessWidget {
  const FlexPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Row(
        children: [
          Expanded(
            child: Container(
              color: Colors.amber,
            ),
          ),
          const FlutterLogo(
            size: 32,
          ),
        ],
      ),
    );
  }
}

输出

Flex 属性调整比例

代码

  children: [
    Expanded(
      flex: 1,
      child: Container(
        color: Colors.amber,
      ),
    ),
    const Expanded(
      flex: 2,
      child: FlutterLogo(
        size: 32,
      ),
    ),
  ],

输出

6.3 留白 Spacer 

留白撑开,很适合用在标题按钮的场景中

代码

  children: [
    Container(
      width: 50,
      color: Colors.amber,
    ),
    const Spacer(),
    const FlutterLogo(
      size: 32,
    ),
  ],

输出

7. 层叠布局 Stack

7.1 Stack

Stack 允许子组件堆叠

Stack class - widgets library - Dart API

定义

Stack({

	Key key,
	
	// 对齐方式,默认是左上角(topStart)
	this.alignment = AlignmentDirectional.topStart,
	
	// 对齐方向
	this.textDirection,
	
	// 定义如何设置无定位子元素尺寸,默认为loose
	this.fit = StackFit.loose,
  
  // 对超出 Stack 显示空间的部分如何剪裁
  this.clipBehavior = Clip.hardEdge,
	
	// 子元素
	List<Widget> children = const <Widget>[],

})

7.2 Positioned

根据 Stack 的四个角来确定子组件的位置

定义

const Positioned({

	Key key,
	
	this.left, // 上下左右位置
	this.top,
	this.right,
	this.bottom,
	
	this.width, // 宽高
	this.height,
	
	@required Widget child,
  
})

7.3 示例

代码

import 'package:flutter/material.dart';

class StackPage extends StatelessWidget {
  const StackPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SizedBox(
        width: 300,
        height: 300,
        child: Stack(
          // 居中对齐
          alignment: Alignment.center,
          // 子元素溢出, none 不裁剪
          clipBehavior: Clip.none,
          // 子元素层叠放
          children: [
            // 三个色块
            Container(
              width: 300,
              height: 300,
              color: Colors.amber,
            ),
            Container(
              width: 200,
              height: 200,
              color: Colors.blue,
            ),
            Container(
              width: 100,
              height: 100,
              color: Colors.green,
            ),
            // 绝对定位
            const Positioned(
              left: 0,
              bottom: -50,
              child: FlutterLogo(size: 100),
            ),
          ],
        ),
      ),
    );
  }
}

输出

8. 流式布局 Wrap

用 Row 的时候可以发现子元素不会自动换行,这时候就需要 Wrap 了。

Wrap class - widgets library - Dart API

8.1 定义

Wrap({
  this.direction = Axis.horizontal,
  // 主轴方向的对齐方式
  this.alignment = WrapAlignment.start,
  // 主轴方向子widget的间距
  this.spacing = 0.0,
  // 纵轴方向的对齐方式
  this.runAlignment = WrapAlignment.start,
  // 纵轴方向的间距
  this.runSpacing = 0.0,
  // 交叉轴对齐方式
  this.crossAxisAlignment = WrapCrossAlignment.start,
  this.textDirection,
  this.verticalDirection = VerticalDirection.down,
  List<Widget> children = const <Widget>[],
})

8.2 示例

代码

import 'package:flutter/material.dart';

class WrapPage extends StatelessWidget {
  const WrapPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Wrap(
        // 主轴方向子widget的间距
        spacing: 10,
        // 纵轴方向的间距
        runSpacing: 100,
        // 主轴方向的对齐方式
        alignment: WrapAlignment.start,
        children: const [
          FlutterLogo(size: 100),
          FlutterLogo(size: 100),
          FlutterLogo(size: 100),
          FlutterLogo(size: 100),
          FlutterLogo(size: 100),
          FlutterLogo(size: 100),
        ],
      ),
    );
  }
}

输出

9. 对齐定位 Align

调整子元素在父元素的位置

Align class - widgets library - Dart API

9.1 Align

定义

Align({
  Key key,
  
  // 需要一个AlignmentGeometry类型的值
  // AlignmentGeometry 是一个抽象类,
  // 它有两个常用的子类:Alignment和 FractionalOffset
  this.alignment = Alignment.center,
  
  // 两个缩放因子
  // 会分别乘以子元素的宽、高,最终的结果就是 Align 组件的宽高
  this.widthFactor,
  this.heightFactor,
  Widget child,
})

代码

import 'package:flutter/material.dart';

class AlignPage extends StatelessWidget {
  const AlignPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Align(
        widthFactor: 2,
        heightFactor: 2,
        alignment: Alignment.bottomLeft,
        child: FlutterLogo(
          size: 50,
        ),
      ),
    );
  }
}

输出

可以发现,Align 的高宽=子元素高宽*高宽因子factor,如果 null 采用父元素高度约束

9.2 Alignment

Alignment 是从 Align 的中心点出发

定义

 /// The top left corner.
  static const Alignment topLeft = Alignment(-1.0, -1.0);

  /// The center point along the top edge.
  static const Alignment topCenter = Alignment(0.0, -1.0);

  /// The top right corner.
  static const Alignment topRight = Alignment(1.0, -1.0);

  /// The center point along the left edge.
  static const Alignment centerLeft = Alignment(-1.0, 0.0);

  /// The center point, both horizontally and vertically.
  static const Alignment center = Alignment(0.0, 0.0);

  /// The center point along the right edge.
  static const Alignment centerRight = Alignment(1.0, 0.0);

  /// The bottom left corner.
  static const Alignment bottomLeft = Alignment(-1.0, 1.0);

  /// The center point along the bottom edge.
  static const Alignment bottomCenter = Alignment(0.0, 1.0);

  /// The bottom right corner.
  static const Alignment bottomRight = Alignment(1.0, 1.0);

Alignment(-1.0, -1.0) 标识从中心点出发,左上角

代码

...
    return const Scaffold(
      body: Align(
        alignment: Alignment(-1, -1),
        child: FlutterLogo(
          size: 50,
        ),
      ),
    );

输出

Alignment.topLeft == Alignment(-1, -1) ,用哪种方式都可以

9.3 FractionalOffset

这种方式是固定从左上角出发

代码

...
  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Align(
        alignment: FractionalOffset(0.5, 0.1),
        child: FlutterLogo(
          size: 50,
        ),
      ),
    );
  }

用 FractionalOffset 对象,输入 0~1 的比例值

输出

9.4 Center

Center 是集成了 Align 对象,默认 alignment=Alignment.center

Center 定义, 少了一个 alignment 参数

class Center extends Align {
  /// Creates a widget that centers its child.
  const Center({ Key? key, double? widthFactor, double? heightFactor, Widget? child })
    : super(key: key, widthFactor: widthFactor, heightFactor: heightFactor, child: child);
}

然后 Align 定义, 默认了 this.alignment = Alignment.center,

class Align extends SingleChildRenderObjectWidget {
  /// Creates an alignment widget.
  ///
  /// The alignment defaults to [Alignment.center].
  const Align({
    Key? key,
    this.alignment = Alignment.center,
    this.widthFactor,
    this.heightFactor,
    Widget? child,
  }) : assert(alignment != null),
       assert(widthFactor == null || widthFactor >= 0.0),
       assert(heightFactor == null || heightFactor >= 0.0),
       super(key: key, child: child);

代码

...
  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Center(
        child: FlutterLogo(
          size: 50,
        ),
      ),
    );
  }

输出

创作不易,希望读者三连支持 💖
赠人玫瑰,手有余香 💖

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ubuntu20.04中设置包含ros节点的文件自启动

若文件里包含了ros话题的发布和接收&#xff0c;那么设置自启动时&#xff0c;应该首先将roscore设置为自启动。 首先确保roscore有一个systemd服务文件。如果还没有&#xff0c;需要在/etc/systemd/system/下创建一个。例如&#xff0c;一个基本的roscore.service文件可能如下…

html文件使用postcss-pxtorem适配移动端 使用tailwindcss库

项目截图 插件下载 npm i -D postcss8.4.38 postcss-cli10.1.0 postcss-pxtorem6.1.0 tailwindcss3.4.3postcss.config.js & tailwind.config.js postcss.config.js const pxToRem require(postcss-pxtorem) module.exports {plugins: [pxToRem({rootValue: 75,propLi…

[office] 快速删除excel中的空行和列的方法 #其他#学习方法#经验分享

快速删除excel中的空行和列的方法 用户在网上下载好的Excel表格打开之后发现有很多空白行&#xff0c;怎么样将这些空白行或单元格一次性删除掉呢?下面教大家在Excel中用定位一次性可以把空白行删除 用户在网上下载好的Excel表格打开之后发现有很多空白行&#xff0c;怎么样将…

【Unity】官方文档学习-光照系统

目录 1 前言 2 光照介绍 2.1 直接光与间接光 2.2 实时光照与烘焙光照 2.3 全局光照 3 光源 3.1 Directional Light 3.1.1 Color 3.1.2 Mode 3.1.3 Intensity 3.1.4 Indirect Multiplier 3.1.5 Shadow Type 3.1.6 Baked Shadow Angle 3.1.7 Realtime Shadows 3.1…

TriForce: 突破长序列生成瓶颈的分层投机解码技术

在人工智能领域&#xff0c;大型语言模型&#xff08;LLMs&#xff09;的长序列生成能力一直是研究的热点。然而&#xff0c;随着模型规模的增长&#xff0c;推理过程中的内存和计算瓶颈成为了限制其应用的主要障碍。为了解决这一问题&#xff0c;Carnegie Mellon University和…

[数据集][目标检测]盲道检测数据集VOC+YOLO格式2173张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;2173 标注数量(xml文件个数)&#xff1a;2173 标注数量(txt文件个数)&#xff1a;2173 标注…

网络安全快速入门(十五)(下)手动创建用户及su,sudo命令

15.8 序言 前面我们已经大概了解了创建用户一些相关文件&#xff0c;接下来我们来手动创建用户&#xff0c;话不多说&#xff0c;我们直接开搞&#xff01;&#xff01;&#xff01; 15.9 手动创建用户&#xff1a; 一般来讲&#xff0c;我们创建用户通过useradd和passwd命令来…

如何合理使用群发短信呢?(短信接口JSON实例)

随着时代的发展&#xff0c;越来越多的营销推广也开始有线下转移到了线上&#xff0c;短信也变成了企业与用户之间交流沟通的桥梁&#xff0c;那么这么多的企业选择使用短信平台&#xff0c;到底群发短信好不好用呢&#xff1f;今天乐讯通短信平台就为大家来介绍一下群发短信营…

3D Gaussian Splatting for Real-Time Radiance Field Rendering

辐射场方法最近在基于多张照片或视频进行新视角合成方面取得了革命性进展。然而&#xff0c;实现高视觉质量仍然需要耗时且计算成本高的神经网络&#xff0c;而最近的快速方法不可避免地在速度和质量之间进行了权衡。对于无界和完整的场景&#xff08;而不是孤立的物体&#xf…

MacOS_奇安信天擎卸载指南,无需管理员密码

背景 奇安信天擎是一款基于云端的终端安全管理软件,在某些情况下,用户可能需要卸载该软件,例如 1、入职企业后使用的是自己的电脑,离职后监控软件还在 2、自己无意下载的软件或被病毒感染后强制下载的垃圾软件 3、员工看不惯企业监控自己的这个行为,使用技术手段屏蔽企业…

微信小程序 画布canvas

属性说明 属性类型默认值必填说明最低版本typestring否指定 canvas 类型&#xff0c;支持 2d (2.9.0) 和 webgl (2.7.0)2.7.0canvas-idstring否canvas 组件的唯一标识符&#xff0c;若指定了 type 则无需再指定该属性1.0.0disable-scrollbooleanfalse否当在 canvas 中移动时且…

python中的函数递归

函数递归&#xff0c;就是一个函数&#xff0c;自己调用自己。 如上图所示&#xff0c;是一段通过定义函数&#xff0c;编写函数体来实现for循环。实现的是从1到n的累乘。即求n的阶乘&#xff0c; 如上图所示&#xff0c;是一段函数的递归来实现1到n的累乘操作&#xff0c;将1*…

问题:前肢的前方称() #微信#经验分享#微信

问题&#xff1a;前肢的前方称&#xff08;&#xff09; A . 掌侧 B . 跖侧 C . 背侧 D . 胫侧 E . 桡侧 参考答案如图所示

数学模型:操作系统中FCFS、SJF、HRRN算法的平均周转时间比较 c语言

摘 要 研究目的&#xff1a;比较操作系统中进程调度FCFS、SJF、HRRN算法的平均周转时间和带权周转时间的大小关系。 研究方法&#xff1a;在建模分析时&#xff0c;分别举4个进程的例子&#xff0c;1个进程用两个字母分别表示到达时间和执行时间。分两种极端情况&#xff0c…

python数据分析-心脏衰竭分析与预测

研究背景 人的心脏有四个瓣膜&#xff0c;主动脉银、二尖、肺动脉和三尖源 不管是那一个膜发生了病变&#xff0c;都会导致心脏内的血流受到影响&#xff0c;这就是通常所说的心脏期膜病&#xff0c;很多是需要通过手术的方式进行改善的。随着人口老龄化的加剧,&#xff0c;心…

如何在快团团上找到优质的供货团长和挑选合适的产品进行推广?

在快团团上找到优质的供货团长和挑选合适的产品进行推广的方法如下&#xff1a; 筛选优质供货团长&#xff1a; 选择专业品类&#xff1a;根据你熟悉的领域和目标客户的需求&#xff0c;选择相应的专业供货团长。查看帮卖口碑标签&#xff1a;通过查看团长的帮卖口碑标签&#…

【排序算法】计数排序(CountSort)

一、定义 计数排序&#xff08;CountSort&#xff09;是一种非比较的排序&#xff0c;它的优势在于在对一定范围内的整数排序时&#xff0c;它的时间夫扎渡为为Ο(nk)&#xff08;其中k是整数的范围&#xff09;&#xff0c;快于任何比较排序算法。 这是一种通过空间换取时间的…

vue antdesgin table 动态表头动态数据示例

以下是一个基于 Vue 和 Ant Design Vue 的示例&#xff0c;可以动态生成表格的表头和数据&#xff1a; <template><div><a-button click"addColumn">添加列</a-button><a-table :columns"columns" :dataSource"dataSource…

2024年全国一高考数学压轴题

(3) 证明: 显然, 等差数列 { a 1 , . . . , a 4 n 2 } \{a_{1},...,a_{4n2}\} {a1​,...,a4n2​} 是 ( i , j ) (i, j) (i,j)-可分的等价于等差数列 { 1 , . . . , 4 n 2 } \{1,...,4n2\} {1,...,4n2} 是 ( i , j ) (i,j) (i,j)-可分的. 前推后显然, 我们考虑后推前, 在去…

U盘文件系统结构损坏的应对与预防

在数字化时代&#xff0c;U盘作为便携式存储设备&#xff0c;其重要性不言而喻。然而&#xff0c;当U盘文件系统结构损坏时&#xff0c;我们可能会面临数据丢失的风险。本文将深入探讨U盘文件系统结构损坏的问题&#xff0c;分析其产生的原因&#xff0c;并给出相应的数据恢复方…