一,概述  

  Flutter中拥有30多种预定义的布局widget,常用的有ContainerPaddingCenterFlexRowColumListViewGridView。按照《Flutter技术入门与实战》上面来说的话,大概分为四类

  • 基础布局组件Container(容器布局),Center(居中布局),Padding(填充布局),Align(对齐布局),Colum(垂直布局),Row(水平布局),Expanded(配合Colum,Row使用),FittedBox(缩放布局),Stack(堆叠布局),overflowBox(溢出父视图容器)。
  • 宽高尺寸处理SizedBox(设置具体尺寸),ConstrainedBox(限定最大最小宽高布局),LimitedBox(限定最大宽高布局),AspectRatio(调整宽高比),FractionallySizedBox(百分比布局)
  • 列表和表格处理ListView(列表),GridView(网格),Table(表格)
  • 其它布局处理:Transform(矩阵转换),Baseline(基准线布局),Offstage(控制是否显示组件),Wrap(按宽高自动换行布局)

二,宽高尺寸处理

    • SizedBox(设置具体尺寸)

      • 介绍  
        比较常用的一个控件,设置具体尺寸。SizeBox组件是一个特定大小的盒子,这个组件强制它的chird有特定的宽度和高度,如果宽度和高度为null,则此组件将调整自身大小匹配该纬度中child的大小。
      • 布局行为

      SizedBox布局行为相对较简单:

        • child不为null时,如果设置了宽高,则会强制把child尺寸调到此宽高;如果没有设置宽高,则会根据child尺寸进行调整;
        • child为null时,如果设置了宽高,则自身尺寸调整到此宽高值,如果没设置,则尺寸为0;
      • 继承关系
        Diagnosticable > DiagnosticableTree > Widget > RenderObjectWidget > SingleChildRenderObjectWidget > SizedBox
      • 构造方法
        const SizedBox({ 
        Key key,
        this.width, //宽
        this.height, //高
        Widget child //子组件
        })
      • 参数解析

        width:宽度值,如果具体设置了,则强制child宽度为此值,如果没设置,则根据child宽度调整自身宽度。

        height:同上。

    • ConstrainedBox(限定最大最小宽高布局)
      • 介绍

        这个控件的作用是添加额外的限制条件(constraints)到child上,本身挺简单的,可以被一些控件替换使用。Flutter的布局控件体系,梳理着发现确实有点乱,感觉总体思想是缺啥就造啥
      • 布局行为
        ConstrainedBox的布局行为非常简单,取决于设置的限制条件,而关于父子节点的限制因素生效优先级,可以查看之前的文章,在这里就不做具体叙述了。
      • 继承关系
        Object > Diagnosticable > DiagnosticableTree > Widget > RenderObjectWidget > SingleChildRenderObjectWidget > ConstrainedBox

        ConstrainedBox也是一个基础的布局控件。

      • 构造函数
         包含了一个constraints属性,且不能为null。
        ConstrainedBox({
        Key key,
        @required this.constraints,
        Widget child
        })
      • 参数解析
        constraints
            添加到child上的额外限制条件,其类型为BoxConstraints。BoxConstraints的作用是干啥的呢?其实很简单,就是限制各种最大最小宽高。说到这里插一句,double.infinity在widget布局的时候是合法的,也就说,例如. 想最大的扩展宽度,可以将宽度值设为double.infinity。  

         LimitedBox

      (限定最大宽高布局)
      介绍LimitedBox,通过字面意思,也可以猜测出这个控件的作用,是限制类型的控件。这种类型的控件前面也介绍了不少了,这个是对最大宽高进行限制的控件。
    布局行为从布局的角度讲,LimitedBox是将child限制在其设定的最大宽高中的,但这个限定是有条件的。当LimitedBox最大宽度不受限制时,child的宽度就会受到这个最大宽度的限制,高度同理。

    • 继承关系

      Object > Diagnosticable > DiagnosticableTree > Widget > RenderObjectWidget > SingleChildRenderObjectWidget > LimitedBox
    • 构造函数
      const LimitedBox({
      Key key,
      this.maxWidth = double.infinity,
      this.maxHeight = double.infinity,
      Widget child,
      })
    • 参数解析 

      maxWidth:限定的最大宽度,默认值是double.infinity,不能为负数。

      maxHeight:同上。

  • AspectRatio(调整宽高比)
    • 介绍
      AspectRatio的作用是调整child到设置的宽高比,这种控件在其他移动端平台上一般都不会提供,Flutter之所以提供,我想最大的原因,可能就是自定义起来特别麻烦吧。
    • 布局行为

      AspectRatio的布局行为分为两种情况:

      • AspectRatio首先会在布局限制条件允许的范围内尽可能的扩展,widget的高度是由宽度和比率决定的,类似于BoxFit中的contain,按照固定比率去尽量占满区域。
      • 如果在满足所有限制条件过后无法找到一个可行的尺寸,AspectRatio最终将会去优先适应布局限制条件,而忽略所设置的比率。
    • 继承关系
      Object > Diagnosticable > DiagnosticableTree > Widget > RenderObjectWidget > SingleChildRenderObjectWidget > AspectRatio

      从继承关系看,AspectRatio是基础的布局控件。

    • 构造函数
      const AspectRatio({
      Key key,
      @required this.aspectRatio,
      Widget child
      })

      构造函数只包含了一个aspectRatio属性,其中aspectRatio不能为null。

    • 参数解析 
      aspectRatio:aspectRatio是宽高比,最终可能不会根据这个值去布局,具体则要看综合因素,外层是否允许按照这种比率进行布局,只是一个参考值。

      

  • FractionallySizedBox(百分比布局)
      • 介绍
        FractionallySizedBox控件会根据现有空间,来调整child的尺寸,所以说child就算设置了具体的尺寸数值,也不起作用。
      • 布局行为

    FractionallySizedBox的布局行为主要跟它的宽高因子两个参数有关,当参数为null或者有具体数值的时候,布局表现不一样。当然,还有一个辅助参数alignment,作为对齐方式进行布局。

      • 当设置了具体的宽高因子,具体的宽高则根据现有空间宽高 * 因子,有可能会超出父控件的范围,当宽高因子大于1的时候;
      • 当没有设置宽高因子,则填满可用区域;
    • 继承关系
      Object > Diagnosticable > DiagnosticableTree > Widget > RenderObjectWidget > SingleChildRenderObjectWidget > FractionallySizedBox
    • 构造函数
      const FractionallySizedBox({
      Key key,
      this.alignment = Alignment.center,
      this.widthFactor,
      this.heightFactor,
      Widget child,
      })
    • 参数解析 

      alignment:对齐方式,不能为null。

      widthFactor:宽度因子,跟之前介绍的控件类似,宽度乘以这个值,就是最后的宽度。

      heightFactor:高度因子,用作计算最后实际高度的。

      其中widthFactorheightFactor都有一个规则

      • 如果不为null,那么实际的最大宽高度则为child的宽高乘以这个因子;
      • 如果为null,那么child的宽高则会尽量充满整个区域。

三,常用方法

  • SizeBox(设置具体尺寸)

    /**
    * MySizeBox
    */
    class MySizeBox extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
    // TODO: implement build
    return new Container(
    color: Colors.green,
    padding: const EdgeInsets.all(5.0),
    child: SizedBox(
    width: 200.0,
    height: 200.0,
    child: new Container(
    color: Colors.red,
    width: 100.0,
    height: 300.0,
    ),
    ),
    );
    }
    }

    效果图

    源码解析
    SizedBox内部是通过RenderConstrainedBox来实现的。具体的源码就不解析了,总体思路是,根据宽高值算好一个constraints,然后强制应用到child上。

  • ConstrainedBox(限定最大最小宽高布局)
    /**
    * ConstrainedBox
    * 在一个宽高200.0的Container上添加一个约束最大最小宽高的ConstrainedBox,实际的显示中,则是一个宽高为150.0的区域。
    */
    class MyConstrainedBox extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
    // TODO: implement build
    return new ConstrainedBox(
    constraints: const BoxConstraints(
    minWidth: 100.0,
    minHeight: 100.0,
    maxWidth: 150.0,
    maxHeight: 150.0,
    ),
    child: new Container(
    width: 200.0,
    height: 200.0,
    color: Colors.red,
    ),
    );
    }
    }

    效果图

    源码解析

    @override
    RenderConstrainedBox createRenderObject(BuildContext context) {
    return new RenderConstrainedBox(additionalConstraints: constraints);
    }

    RenderConstrainedBox实现其绘制。其具体的布局表现分两种情况:

    如果child不为null,则将限制条件加在child上;
    如果child为null,则会尽可能的缩小尺寸。
    具体代码如下:

    @override
    void performLayout() {
    if (child != null) {
    child.layout(_additionalConstraints.enforce(constraints), parentUsesSize: true);
    size = child.size;
    } else {
    size = _additionalConstraints.enforce(constraints).constrain(Size.zero);
    }
    }

    使用场景

    需要添加额外的约束条件可以使用此控件,例如设置最小宽高,尽可能的占用区域等等。笔者在实际开发中使用的倒不是很多,倒不是说这个控件不好使用,而是好多约束因素是综合的,例如需要额外的设置margin、padding属性能,因此单独再套个这个就显得很繁琐了。
  • LimitedBox(限定最大宽高布局)
    class MyLimitedBox extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
    // TODO: implement build
    return new Row(
    children: <Widget>[
    new Container(
    color: Colors.red,
    width: 100.0,
    ),
    LimitedBox(
    maxWidth: 150.0,
    child: new Container(
    color: Colors.blue,
    width: 250.0,
    ),
    )
    ],
    );
    }
    }

    效果图:

    源码解析

    先不说其源码,单纯从其作用,前面介绍的SizedBox、ConstrainedBox都类似,都是通过强加到child的constraint,来达到相应的效果。

    我们直接看其计算constraint的代码

    minWidth: constraints.minWidth,
    maxWidth: constraints.hasBoundedWidth ? constraints.maxWidth : constraints.constrainWidth(maxWidth),
    minHeight: constraints.minHeight,
    maxHeight: constraints.hasBoundedHeight ? constraints.maxHeight : constraints.constrainHeight(maxHeight)

    LimitedBox只是改变最大宽高的限定。具体的布局代码如下:

    if (child != null) {
    child.layout(_limitConstraints(constraints), parentUsesSize: true);
    size = constraints.constrain(child.size);
    } else {
    size = _limitConstraints(constraints).constrain(Size.zero);
    }

    根据最大尺寸,限制child的布局,然后将自身调节到child的尺寸。

    使用场景
       是不可能清楚了,光是找例子,就花了不少时间。Flutter的一些冷门控件,真的是除了官方的文档,啥材料都木有。
       谷歌说这个很有用,还是一脸懵逼。这种控件,也有其他的替代解决方案,LimitedBox可以达到的效果,ConstrainedBox都可以实现。

  • AspectRatio(调整宽高比)
    /**
    * AspectRatio
    * 定义了一个高度为200的区域,内部AspectRatio比率设置为1.5,最终AspectRatio的是宽300高200的一个区域。
    */
    class MyAspectRatio extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
    // TODO: implement build
    return new Container(
    height: 200.0,
    child: new AspectRatio(
    aspectRatio: 1.5,
    child: new Container(
    color: Colors.red,
    ),
    ),
    );
    }
    }

    效果图

    源码解析

    @override
    RenderAspectRatio createRenderObject(BuildContext context) => new RenderAspectRatio(aspectRatio: aspectRatio);

    经过前面一些控件的解析,我想大家对这种构造应该不会再陌生了,绘制都是交由RenderObject去完成的,这里则是由RenderAspectRatio去完成具体的绘制工作。

    RenderAspectRatio的构造函数中会对aspectRatio做一些检测(assert)

    aspectRatio不能为null;
    aspectRatio必须大于0;
    aspectRatio必须是有限的。

    接下来我们来看一下RenderAspectRatio的具体尺寸计算函数:

    (1)如果限制条件为isTight,则返回最小的尺寸(constraints.smallest);

    if (constraints.isTight)
    return constraints.smallest;

    (2)如果宽度为有限的值,则将高度设置为width / _aspectRatio。 如果宽度为无限,则将高度设为最大高度,宽度设为height * _aspectRatio;

    if (width.isFinite) {
    height = width / _aspectRatio;
    } else {
    height = constraints.maxHeight;
    width = height * _aspectRatio;
    }

    (3)接下来则是在限制范围内调整宽高,总体思想则是宽度优先,大于最大值则设为最大值,小于最小值,则设为最小值。

    如果宽度大于最大宽度,则将其设为最大宽度,高度设为width / _aspectRatio;

    if (width > constraints.maxWidth) {
    width = constraints.maxWidth;
    height = width / _aspectRatio;
    }

    如果高度大于最大高度,则将其设为最大高度,宽度设为height * _aspectRatio;

    if (height > constraints.maxHeight) {
    height = constraints.maxHeight;
    width = height * _aspectRatio;
    }

    如果宽度小于最小宽度,则将其设为最小宽度,高度设为width / _aspectRatio;

    if (width < constraints.minWidth) {
    width = constraints.minWidth;
    height = width / _aspectRatio;
    }

    如果高度小于最小高度,则将其设为最小高度,宽度设为height * _aspectRatio。

    if (height < constraints.minHeight) {
    height = constraints.minHeight;
    width = height * _aspectRatio;
    }
  • FractionallySizedBox(百分比布局)
    /**
    * MyFractionallySizeBox
    */ class MyFractionallySizeBox extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
    // TODO: implement build
    return new Container(
    color: Colors.blue,
    height: 150.0,
    width: 150.0,
    padding: const EdgeInsets.all(10.0),
    child: new FractionallySizedBox(
    alignment: Alignment.topLeft,
    widthFactor: 1.5,
    heightFactor: 0.5,
    child: new Container(
    color: Colors.red,
    ),
    ),
    );
    }
    }

    效果图

    源码解析
    FractionallySizedBox内部具体渲染是由RenderFractionallySizedOverflowBox来实现的,通过命名就可以看出,这个控件可能会Overflow。

    我们直接看实际计算尺寸的代码

    double minWidth = constraints.minWidth;
    double maxWidth = constraints.maxWidth;
    if (_widthFactor != null) {
    final double width = maxWidth * _widthFactor;
    minWidth = width;
    maxWidth = width;
    }
    double minHeight = constraints.minHeight;
    double maxHeight = constraints.maxHeight;
    if (_heightFactor != null) {
    final double height = maxHeight * _heightFactor;
    minHeight = height;
    maxHeight = height;
    }

    源代码中,根据宽高因子是否存在,来进行相对应的尺寸计算。

    使用场景
    当需要在一个区域里面取百分比尺寸的时候,可以使用这个,比方说,高度40%宽度70%的区域。当然,AspectRatio也可以达到近似的效果。

四,参考  

Flutter学习之认知基础组件
Flutter布局

【Flutter学习】页面布局之宽高尺寸处理的更多相关文章

  1. Android如何在初始化的时候获取加载的布局的宽高

    在自定义ListView中,需要将下拉刷新的View在初始化的时候设置padding隐藏起来,这时就要在初始化的时候获得要加载的布局View的高度. private View headView; he ...

  2. 前端 JS 获取 Image 图像 宽高 尺寸

    前端 JS 获取 Image 图像 宽高 尺寸 简介 项目中用到获取图片的原始尺寸,然后适配宽高:网上的大部分前端解决方案,都是new Image()后,在onload事件中获取image的尺寸. 在 ...

  3. js 获取页面可视区域宽高

    获取浏览器窗口的可视区域高度和宽度,滚动条高度有需要的朋友可参考一下. 1.IE中,浏览器显示窗口大小只能以下获取: 代码如下复制代码 代码如下 document.body.offsetWidth d ...

  4. 微信 小程序 drawImage wx.canvasToTempFilePath wx.saveFile 获取设备宽高 尺寸问题

    以下问题测试环境为微信开发者0.10.102800,手机端iphone6,如有不对敬谢指出. 根据我的测试,context.drawImage,在开发者工具中并不能画出来,只有预览到手机中显示. wx ...

  5. js判断图片上传时的文件大小,和宽高尺寸

    今天在做图片上传的小功能,使用了一个kissy上传组件.很好奇它是如何在图片上传前,检测到图片的大小和尺寸的?我们来写个小实例实现一下吧 如何读取图片的size 首先,原生input file控件有个 ...

  6. handsontable组件和jqwidgets(jqxdragdrop组件)在一个页面产生调整宽高bug

    修改handsontable.full.js handsontable绑定的"mouseup"事件,默认是window区域太大.引起冲突.

  7. 【Flutter学习】页面布局之其它布局处理

    一,概述 Flutter中拥有30多种预定义的布局widget,常用的有Container.Padding.Center.Flex.Row.Colum.ListView.GridView.按照< ...

  8. 【Flutter学习】页面布局之列表和表格处理

    一,概述 Flutter中拥有30多种预定义的布局widget,常用的有Container.Padding.Center.Flex.Row.Colum.ListView.GridView.按照< ...

  9. 【Flutter学习】页面布局之基础布局组件

    一,概述 Flutter中拥有30多种预定义的布局widget,常用的有Container.Padding.Center.Flex.Row.Colum.ListView.GridView.按照< ...

随机推荐

  1. Python爬虫之抓取豆瓣影评数据

    脚本功能: 1.访问豆瓣最受欢迎影评页面(http://movie.douban.com/review/best/?start=0),抓取所有影评数据中的标题.作者.影片以及影评信息 2.将抓取的信息 ...

  2. BZOJ 3456: 城市规划(dp+多项式求逆)

    传送门 解题思路 这道题就是求带标号的无向连通图个数,首先考虑\(O(n^2)\)的做法,设\(f_i\)表示有\(i\)个节点的无向连通图个数,那么考虑容斥,先把所有的无向图求出,即为\(2^{C( ...

  3. BZOJ 3294: [Cqoi2011]放棋子(计数dp)

    传送门 解题思路 设\(f[i][j][k]\)表示前\(k\)个颜色的棋子占领了\(i\)行\(j\)列的方案数,那么转移时可以枚举上一个颜色时占领的位置,\(f[i][j][k]=\sum\lim ...

  4. 怎么更改win7登录界面

    方法/步骤   1 第一步,先打开注册表.快捷键是win+R.Win就是Windows图片那个键.打开会是这个. 2 在其中输入Regedit.就打开了传说中的注册表了.然后在注册表中选择.选择的顺序 ...

  5. arm可以干什么

    ARM开发可以控制各种电机.arm性能很强 ,内存更大, c语言当然可以.ARM是32位的,单片机是8位的,运行速度快很多,最关键的是可以跑操作系统.控制部分的内容ARM当然可以胜任,而且ARM的资源 ...

  6. 题解 P1017 【进制转换】

    我赶jio这个题难道是让我们写快写? 不管了,赶紧把咕咕咕了一万年的题解写出来. 这个题就是考察负进制和在mod意义下的除法运算的基础运算. (其实也没多大问题) 首先我们先假设一个原始数据\(num ...

  7. java并发编程笔记(十)——HashMap与ConcurrentHashMap

    java并发编程笔记(十)--HashMap与ConcurrentHashMap HashMap参数 有两个参数影响他的性能 初始容量(默认为16) 加载因子(默认是0.75) HashMap寻址方式 ...

  8. java 字符串的操作方法

    方法 作用 范例   indexOf() 找到第一个字符出现的位置,()以下标来判断,返回的是字符所在的下标 int  num = String.indexOf("字符")   l ...

  9. 动态调试某个apk的smali代码,微信举例

    本地环境: PC:windows 10,Intellij IDEA (android studio应该一样的) 手机:nexus5 8.1系统, 其他依赖:smalidea插件,xposed 插件 h ...

  10. 面试题:Nginx 是如何实现高并发?常见的优化手段有哪些?

    面试题: Nginx 是如何实现并发的?为什么 Nginx 不使用多线程?Nginx常见的优化手段有哪些?502错误可能原因有哪些? 面试官心理分析 主要是看应聘人员的对NGINX的基本原理是否熟悉, ...