Flutter布局——一段代码解释最常见的约束错误

2023-05-16

flutter布局的原理

Constraints go down, Sizes go up, Parent sets position

  • 父节点向子节点传约束
  • 子节点向父节点上传大小
  • 最后由父节点决定位置

不是按照直接约束显示

问题代码

Scaffold(
      body: Center(
        child: ConstrainedBox(
          constraints: BoxConstraints.tight(const Size(300, 300)),
          child: ColoredBox(
            color: Colors.yellow,
            child: ConstrainedBox(
              constraints: BoxConstraints.tight(const Size(100, 200)),
              child: const ColoredBox(
                color: Colors.red,
                child: SizedBox(
                  width: 100,
                  height: 100,
                  child: ColoredBox(color: Colors.teal),
                ),
              ),
            ),
          ),
        ),
      ),
    );

显示效果

最终只显示了蓝绿色,而且没有按照我们对蓝绿色组件直接的约束大小显示。

错误分析

  • 这段代码,我们逐步移出蓝绿色、黄色代码,发现黄色和红色均显示为300*300
  • 我们想显示的蓝绿色、红色均没有按照我们直接的约束显示,都被黄色父节点约束覆盖了。
  • 而黄色可以理解为按照起父级约束显示。

我们发现黄色的父级约束盒子的父级是Center, 这个就是重点

  1. Center的继承关系是:SingleChildRenderObjectWidget>Align>Center
  2. ConstrainedBox的继承关系是:SingleChildRenderObjectWidget>ConstrainedBox
  3. SizedBox的继承关系是:SingleChildRenderObjectWidget>SizedBox

这里先插入一个知识,我们在屏幕上看到的UI都是通过RenderObjectWidget实现的。而RenderObjectWidget中有个creatRenderObject方法生成RenderObject对象,RenderObject实际负责layout()和paint()。

其中Align的creatRenderObject方法返回的是RenderPositionedBox;

SizedBoxConstrainedBox的creatRenderObject方法返回的是RenderConstrainedBox;

RenderPositionedBox 和 RenderConstrainedBox

RenderPositionedBoxRenderConstrainedBox 最终集成的都是RenderBox

我们先来对比一下用于计算布局的performLayout方法

RenderPositionedBox

这里在子节点渲染时,修改了布局约束,改为松约束。
其中constraints.loosen()是把min约束给删除,可以理解为置零

  @override
  void performLayout() {
    final BoxConstraints constraints = this.constraints;
    final bool shrinkWrapWidth = _widthFactor != null || constraints.maxWidth == double.infinity;
    final bool shrinkWrapHeight = _heightFactor != null || constraints.maxHeight == double.infinity;

    if (child != null) {
    // 这里在子节点渲染时,修改了布局约束,改为松约束。
    // 其中constraints.loosen()是把min约束给删除,可以理解为置零
      child!.layout(constraints.loosen(), parentUsesSize: true);
    // 根据子节点大小计算自己的大小
    // 默认是没设置Factor 那么自身size就是最大值double.infinity
      size = constraints.constrain(Size(
        shrinkWrapWidth ? child!.size.width * (_widthFactor ?? 1.0) : double.infinity,
        shrinkWrapHeight ? child!.size.height * (_heightFactor ?? 1.0) : double.infinity,
      ));
    // 根据自身size,子节点size,来绘制子节点位置
      alignChild();
    } else {
      size = constraints.constrain(Size(
        shrinkWrapWidth ? 0.0 : double.infinity,
        shrinkWrapHeight ? 0.0 : double.infinity,
      ));
    }
  }

RenderConstrainedBox

  @override
  void performLayout() {
    final BoxConstraints constraints = this.constraints;
    if (child != null) {
      // 直接把自己的约束传递给子节点,并获取子节点size
      child!.layout(_additionalConstraints.enforce(constraints), parentUsesSize: true);
      // 将子节点的size赋值给自己
      size = child!.size;
      // 自己和子节点的size相同,所以不需要进行align子节点
    } else {
      size = _additionalConstraints.enforce(constraints).constrain(Size.zero);
    }
  }

结论

我们可以得到结论,当直接父节点是CenterAlign等约束Widget,他们的creatRenderObject返回的是RenderPositionedBox, 而RenderPositionedBox计算会先计算子节点大小,然后结算自己的大小,最后根据约束子组件偏移,子组件是可以显示其自身约束,前提是在RenderPositionedBox的松约束下。

而ConstrainedBox、SizeBox等最终的creatRenderObject返回的是RenderConstrainedBox,其直接把父节点约束传递给子节点,当父节点的约束是紧约束,即是expand显示,所有creatRenderObject返回的是RenderConstrainedBox的子节点均会继承约束,即自身约束并不生效。

欢迎各位大佬批评指正

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Flutter布局——一段代码解释最常见的约束错误 的相关文章

  • 如何删除 Flutter 中的调试横幅?

    我在用着flutter screenshot我预计屏幕截图不会有横幅 但它有 请注意 我得到了not supported for emulator配置文件和发布模式的消息 On your MaterialApp set debugShowC
  • flutter run 无法在 iOS 模拟器上运行,但 Xcode 可以构建

    在我的 Flutter 项目中 flutter run命令无法将项目构建到 iOS 模拟器 但在 Xcode 中 当我单击构建按钮时 Xcode 可以毫无问题地构建它 我正在使用 AgoraRTC 库 添加 Flutter Quill 后就
  • 当用户尝试使用 flutter_inappwebview 在移动应用程序中上传文件时,如何请求用户权限?

    我正在尝试使用 flutter inappwebviewplugin 创建一个 flutter web 应用程序 在应用程序中 我添加了一个用于文件上传的 dropzone 插件 此功能在浏览器和 Android 应用程序上都运行良好 但在
  • 对于哪些 flutter 小部件我们需要使用 const?

    我了解的好处const并且小部件不会在状态更改时重建 但当您看到下面的代码时 仍然很明显它们是常量 我希望 flutter 自动处理它 或者 flutter 已经在处理它而我却没有意识到 This makes sense to me but
  • Dart 是单线程的,但为什么它使用 Future 对象并执行异步操作

    在文档中 Dart 是单线程的 但为了一次执行两个操作 我们使用与线程相同工作的 future 对象 使用Future对象 futures 来执行异步操作 如果 Dart 是单线程的 那么为什么它允许执行异步操作 Note 异步操作是并行操
  • Flutter:从子级检索顶级状态返回 null

    我正在尝试使用 of 方法获取应用程序的顶级状态 类似于 Scaffold of 函数 这是 精简的 代码 class IApp extends StatefulWidget override IAppState createState g
  • 没有为类型“Object”定义运算符“[]”。尝试定义运算符“[]”

    我的代码在下面给出了我在这一行中从 firebase 访问用户名时遇到的问题的错误 snapshot data username 它给出了上面提到的错误 我知道访问地图数据的唯一方法是这个 FutureBuilder future Fire
  • 渲染时 Flutter SVG 延迟

    我在行中显示 SVG 文件形式的图像和文本 由于某些原因 svg 图像的渲染速度比屏幕的其余部分慢 从而导致延迟 这不利于用户体验 这种延迟正常吗 我该怎么做才能使整个屏幕同时渲染 Row mainAxisAlignment MainAxi
  • 如何使用 Firebase_Auth 和 Flutter 登录 Twitter

    一个人应该如何编程使用 Twitter 登录特征使用firebase auth https pub dev packages firebase auth和颤动 我看到一些使用的例子flutter twitter login https pu
  • 颤振动态形式无法正常工作

    在我的应用程序中 我想创建一组动态表单 用户可以在其中添加更多项目 在这种动态形式中 它由两个文本字段 1 电话字段 2 电子邮件字段和一个下拉字段组成 但我尝试的任何事情都无法正常工作 我已经要求修复我的代码 但没有得到答复 堆栈溢出问题
  • 由于 mapEventToState 不起作用而引起的 Flutter 块迁移

    我正在关注移民 https bloclibrary dev migration id packagebloc 1到新的块 8 0 0 我正在尝试删除映射事件到状态但我这样做有困难 你能帮我看看该怎么做吗 我已经在下面尝试过 但它不起作用 旧
  • 如何在 Flutter App 中按时间注销?

    如果用户在登录后对应用程序没有反应或不活动超过 5 分钟 我需要从应用程序中注销用户 该应用程序将转到主登录页面 我尝试实施给定的解决方案here https stackoverflow com questions 52602606 how
  • 在没有动画的情况下替换 MaterialApp 中的初始路线?

    我们的应用程序建立在Scaffold到目前为止 我们已经能够使用内部提供的调用来满足我们的大部分路由和导航要求NavigatorState pushNamed pushReplacementNamed ETC 但我们不想要的是 当用户从抽屉
  • 谷歌字体包是否会下载设备上的字体?

    在我的 flutter Android 应用程序中 第一次启动时 该应用程序显示默认字体 一秒钟后它更改为我从 google fonts flutter 包中使用的字体 我想我的问题是 应用程序第一次启动时是否会立即下载字体 如果是 可以使
  • 如何将 Dart 代码迁移到不可空 (NNBD)?

    我有一个之前编写的 Flutter 应用程序Dart 中引入了 null 安全性 https stackoverflow com questions 60068435 what is nullability in dart non null
  • 将 SQL Server 与 Dart 结合使用

    我还没有找到很好的答案 所以我想尝试一下得到答案 将 Microsoft SQL Server 与 Dart 结合使用的最佳方式是什么 我需要它能够从基本上任何操作系统 网络和移动设备上使用它 我觉得最好的方法可能是 GraphQL 但我对
  • Android Studio 无法运行 Xcode 模拟器

    我正在尝试使用 Xcode iPhone 模拟器模拟我的 Flutter 应用程序 但收到此错误 在升级 Android Studio 和 Xcode 之前 它运行良好 Launching lib main dart on iPhone X
  • 从后台恢复后,Flutter GoogleMap 为空白

    我遇到以下问题 我的 Flutter 应用程序使用 GoogleMap 地图最初加载得很好 但是 如果我将应用程序置于后台并稍后恢复 地图将保持空白 Google 徽标仍然显示 就像未指定 API 密钥时发生的情况一样 我的多边形叠加层也不
  • 如何在Flutter中获取ScrollView中的子滚动偏移位置

    我制作了一个 CustomScrollView 小部件 其中包含 银应用栏 Sliver持久标头 银格 Sliver持久标头 银格 SliverPercientHeader 将是 SliverGrid 中项目的描述 一旦点击 我用 Gest
  • Flutter - 选择 TextFormField 时键盘不显示

    我目前遇到一个问题 当我选择任何一个时 键盘不会出现TextFormFielda 内的小部件Form小部件 这是表单的代码 位于我的内部CreateAccountForm有状态的小部件 import package flutter mate

随机推荐

  • 关于特定网页打不开问题的解决

    如果有一些特定的网站打不开 排除被屏蔽的可能性的话 xff0c 试着把DNS设置成了自动获取ip试试看 我就这样子解决了打不开学校官网的问题
  • 渲染业务领域全景图

    最近图形学应用领域愈发广泛 xff0c 根据我的理解 xff0c 制作了一张渲染相关业务全景图 xff0c 希望对大家的职业规划有一定帮助
  • AI 入门怎么学?这份学习指南请收好!

    万事开头难 xff01 AI 入门对很多初学 AI 的同学来说是一大难题 搜集了一大堆入门资料 xff0c Python 数学 深度学习应有尽有 xff0c 但就是无从下手 xff0c 总是在第一章与放弃之间徘徊 那么 xff0c AI 应
  • FTP如何设置用户名密码

    1 新建FTP站点 xff0c 指定名称和物理路径 2 身份验证 选择 基本 xff0c 允许访问 选择 指定用户 xff0c 下面文本框中输入 本地用户和组 中现有的一个用户名即可 注意 xff1a 只能是 本地用户和组 中的用户 xff
  • Android布局 -- Navigation实现底部导航栏

    底部导航栏加页卡的切换 xff0c 很多App采用这种布局设计 xff0c 在以前的开发中 xff0c 需要自定义底部导航栏以及使用FragmentTransaction来管理Fragment的切换 xff0c 代码量较大 xff0c 而使
  • ViewModelProviders is deprecated

    原有的创建ViewModel的方法 xff1a viewModel 61 ViewModelProviders of this get ViewModel class 提示ViewModelProviders过时 改为 xff1a view
  • Android Fragment退出 返回上一个Fragment与直接退出

    例如应用底部有两个导航按钮A与B xff0c 刚进入的时候显示为第一个AFragment xff0c 点击B切换到BFragment 如果需求是在BFragment点击返回键回到AFragment xff0c 需要配置 app defaul
  • Android基础 -- 子线程可以修改UI吗?

    子线程可以修改UI吗 xff1f 为什么会产生这样的问题 xff0c 可能是因为在开发过程中遇到了 34 Only the original thread that created a view hierarchy can touch it
  • leetcode 417. 太平洋大西洋水流问题

    https leetcode cn com problems pacific atlantic water flow 思路是从海洋开始逆流 如果可以逆流到 就标记为1 然后检查两个海洋都可以逆流到的区域 DFS public List lt
  • Android模拟器检测常用方法

    在Android开发过程中 xff0c 防作弊一直是老生常谈的问题 xff0c 而模拟器的检测往往是防作弊中的重要一环 xff0c 接下来有关于模拟器的检测方法 xff0c 和大家进行一个简单的分享 1 传统的检测方法 传统的检测方法主要是
  • RecyclerView 隐藏部分分割线

    在项目中遇到复杂点的RecyclerView xff0c 可能会有隐藏部分分割线的需求 xff0c 例如item1和item3之间的分割线隐藏 xff0c item4和item5之间的分割线隐藏等 在看了文档里的ItemDecoration
  • 浅谈去中心化应用

    1 中心化应用 现在我们所使用的应用基本上都是中心化的应用 xff0c 什么是中心化应用呢 xff0c 举个栗子 xff0c 我们在天猫买东西的时候 xff0c 需要先付款给支付宝 xff0c 然后卖家发货 xff0c 我们确认收货之后 x
  • EGL综述

    参考 xff1a https www khronos org registry EGL specs eglspec 1 5 pdf 什么是EGL EGL是支持多平台 多操作系统的 xff0c 比如安卓 Unix Windows等 为了扩展性
  • Java二分搜索树及其添加删除遍历

    对于树这种结构 xff0c 相信大家一定耳熟能详 xff0c 二叉树 二分搜索树 AVL树 红黑树 线段树 Trie等等 xff0c 但是对于树的应用以及编写一棵解决特定问题的树 xff0c 不少同学都会觉得不是一件简单的事情 xff0c
  • Android自定RadioGroup实现点击切换效果

    一 xff1a java文件 public class SegmentedGroup extends RadioGroup private int mMarginDp private Resources resources private
  • opencv--将本地摄像头数据转换成ip摄像头数据流,并在客户端获取该流进行显示

    项目介绍 xff1a 在本项目中 xff0c 实现从本地摄像头获取数据帧 xff0c 然后将其转换成ip摄像头数据流并在客户端通过opencv代码实时获取该图像数据进行显示 xff1a 当然也能在浏览器通过输入地址进行视频的访问 方式一 x
  • 8. &和&&的区别?

    答 xff1a amp 运算符有两种用法 xff1a 1 按位与 xff1b 2 逻辑与 amp amp 运算符是短路与运算 逻辑与跟短路与的差别是非常巨大的 xff0c 虽然二者都要求运算符左右两端的布尔值都是true整个表达式的值才是t
  • 记InheritedWidget使用思考

    InheritedWidget 是项目中必不可少的组件 xff0c 用户数据共享 老生常谈的Provider框架也是基于InheritedWidget实现的 简介 InheritedWidget组件是功能性组局 xff0c 实现了由上向下共
  • flutter数据共享系列——随记

    Provider InheritedWidget 解决了数据共享问题 迎面也带来数据刷新导致的组件不必要更新问题 Provider基于InheritedWidget实现数据共享 xff0c 数据更新 xff0c 定向通知组件更新等 接下来我
  • Flutter布局——一段代码解释最常见的约束错误

    flutter布局的原理 Constraints go down Sizes go up Parent sets position 父节点向子节点传约束子节点向父节点上传大小最后由父节点决定位置 不是按照直接约束显示 问题代码 xff1a