1. Flutter UI架构

Flutter将视图数据抽象成为三个部分,即Widget树、Element树和RenderObject树。

  • Widget树:控件的配置信息,不涉及渲染,更新代价极低。
  • RenderObject树:真正的UI渲染树,负责渲染UI,更新代价极大。
  • Element树:Widget树和RenderObject树之间的粘合剂,负责将Widget树的变更以最低的代价映射到RenderObject树上。

2. Flutte布局原理

1. 源码分析

RenderObject是Flutter真正的UI渲染树,负责界面的测量,布局和绘制,Flutter页面布局相关的源码都在RenderObject及其子类中。

上图是RenderObject类中和布局相关的属性和方法.

  • constrainst属性由直接父布局提供的布局约束(最大高度,最小高度,最大宽度,最小宽度),
  • layout方法由父RenderObject调用,计算当前RenderObject的布局,父RenderObject传递给子RenderObject约束信息,子RenderObject必须服从约束信息。如果父RenderObject需要子RenderObject的布局信息,parentUsesSize参数应该传true,否则传false。
  • performLayout:子类必须重写的方法,计算当前RenderObject和子RenderObject的布局信息。
  • performResize:子类必须重写的方法,仅使用约束更新RenderObject的布局。RenderConstrainedBox是ConstrainedBox对应的RenderObject,最多有一个子RenderObject, 如果子RenderoObject不为空,则对子RenderObject进行布局,并计算布局的大小。RenderFlex是Column和Row对应的RenderObject,可以包含多个子RenderObject, 如果子RenderoObject不为空,则对子RenderObject依次进行布局,并计算布局的大小。

2. Flutte布局原理总结

  1. RenderObject会通过它的父级获得自身的约束。 约束实际上就是4个浮点类型的集合:最大/最小宽度,以及最大/最小高度。
  2. 然后,这个RenderObject将会逐个遍历它的children列表。向子级传递约束子级之间的约束可能会有所不同),然后询问它的每一个子级需要用于布局的大小。
  3. 然后,这个RenderObject就会对它子级的children逐个进行布局。(水平方向是x轴,竖直是y轴)
  4. 最后,RenderObject将会把它的大小信息向上传递至父RenderObject(包括其原始约束条件)。

3. Flutter布局限制

由于父RenderObject传递给子RenderObject约束信息,子RenderObject传递给父RenderObject大小信息,Flutter布局存在一些限制:

  • 一个RenderObject仅在其父级给其约束的情况下才能决定自身的大小。 这意味着RenderObject通常情况下不能任意获得其想要的大小。
  • 一个RenderObject无法知道,也不需要决定其在屏幕中的位置。 因为它的位置是由其父级决定的。
  • 当轮到父级决定其大小和位置的时候,同样的也取决于它自身的父级,所以,在不考虑整棵树的情况下,几乎不可能精确定义任何RenderObject的大小和位置。

4. Flutter布局实战

1.线性布局

线性布局的子布局在主轴上长度不能设置无限大(double.infinity),因为线性布局给子布局在主轴上的最大长度的约束就是无限大(double.infinity),会导致无限大的子布局无法计算当前布局的大小,布局失败。如下:

// 第一个子Container的高度设置为无限大,导致布局失败Column(  children: [    Container(      width: 200.0,      height: double.infinity,      color: Colors.blue,    ),    Container(      width: 200.0,      height: 200.0,      color: Colors.red,    ),  ],);// 子Column的高度为无限大,导致布局失败Column(  children: [    Column(      children: [        Container(          width: 200.0,          height: 200.0,          color: Colors.blue,        ),      ],    ),    Container(      width: 200.0,      height: 200.0,      color: Colors.red,    ),  ],);

如果想要让子布局占满全屏可以增加Expanded布局。如下:

Column(  children: [    Expanded(      child: Container(        width: 200.0,        height: double.infinity,        color: Colors.blue,      ),    ),    Container(      width: 200.0,      height: 200.0,      color: Colors.red,    ),  ],);Column(  children: [    Expanded(      child: Column(        children: [          Container(            width: 200.0,            height: 200.0,            color: Colors.blue,          ),        ],      ),    ),    Container(      width: 200.0,      height: 200.0,      color: Colors.red,    ),  ],);

2. 栈布局

栈布局的子布局设置相对位置推荐使用Padding代替Position,并把fit属性设置StackFit.loose,构建时Stack会自适应大小,否则需要使用Container设置Stack和Position的大小;并且Padding默认对上下左右都有相对距离(0),但Position没有默认的相对布局,如果忘记设置,会使Position的子布局无法自动换行或布局不显示。

不推荐:

// Text无法自动换行// Container布局不显示Stack(  children: [    Positioned(      top: 100.0,      child: Text(          '测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试'),    ),    Positioned(      top: 0.0,      child: Column(        children: [          Container(            height: 100.0,            width: double.infinity,            color: Colors.red,          ),        ],      ),    )  ],);

推荐:

Stack(  children: [    Padding(      padding: const EdgeInsets.only(top: 10.0),      child: Text(          '测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试'),    ),    Padding(      padding: const EdgeInsets.only(top: 0.0),      child: Column(        children: [          Container(            height: 100.0,            width: double.infinity,            color: Colors.red,          ),        ],      ),    )  ],);

3. 可滚动布局

可滚动布局在主轴方向上的长度是无限大,父布局需要转递给可滚动布局最大长度的约束。

Column(  children: [    Expanded(      child: ListView(        children: [          Text('测试'),        ],      ),    ),  ],);

横向可滚动布局必须设置高度。

Column(  children: [    Container(      height: 200.0,      child: ListView(        scrollDirection: Axis.horizontal,        children: [          Text('测试'),        ],      ),    ),  ],);

可滚动布局嵌套可滚动布局被嵌套布局的shrinkWrap属性必须设置为true,并且可以将physics属性设置为NeverScrollableScrollPhysics()来解决滑动冲突。

ListView(  children: [    ListView(      shrinkWrap: true,      physics: NeverScrollableScrollPhysics(),      children: [        Text('测试'),      ],    ),  ],);

5. 总结

本文章通过源码分析讲述Flutter布局的过程,分析实战中布局不显示的原因,并给出Flutter布局的一些建议。

flutter listview 滚动到指定位置_Flutter 布局原理及实战相关推荐

  1. flutter listview 滚动到指定位置_flutter入门

    flutter的布局方法 Flutter一切皆组件widget. 使用Scaffold是最容易的,它是 Material Components库中的一个widget,它提供了一个默认banner,背景 ...

  2. Flutter ListView滚动到指定条目

    找遍全网没有看到listview滚动到指定条目的方法,基本都是通过条目的高度计算达到效果.这样比较麻烦.通过研究发现一种简单的方法,但是不能使用listview组件,需要使用SingleChildSc ...

  3. 【小程序】滚动到指定位置

    点击按钮滚动到页面内的指定位置. wxml <view class="btn" catchtap="scrollToElement">去报名< ...

  4. android 输入法键盘弹出与否判断和输入法键盘弹出时将界面滚动到指定位置

    本文章重点谈下如何实现,结合以下demo,来谈谈输入法键盘弹出与否判断和输入法键盘弹出时将界面滚动到指定位置 1.先看下demo的场景,这是个登录界面,因为界面元素比较多,导致在输入法弹出时,下面的登 ...

  5. vue 点击div 获取位置_vue 点击元素滚动到指定位置

    {{item}} {{item}} data() {return{ navgator: ['列表A','列表B','列表C','列表D', ], navgatorIndex:0, listBox: [ ...

  6. 用startSmoothScroll实现RecyclerView滚动到指定位置并置顶,含有动画。

    RecyclerView滚动到指定位置并置顶 RecyclerView本身提供了几个定位的方法,除了手动滑动的scrollTo,smootScrollTo和scrollBy,smoothScrollB ...

  7. 监听某个区域滚动_监听页面滚动及滚动到指定位置

    一.原生js通过window.onscroll监听 window.onscroll = function() { //为了保证兼容性,这里取两个值,哪个有值取哪一个 //scrollTop就是触发滚轮 ...

  8. ios开发之--令UITableView滚动到指定位置

    这个应用场景还是挺多的,代码如下: //获取到需要跳转位置的行数 NSIndexPath *scrollIndexPath = [NSIndexPath indexPathForRow:10 inSe ...

  9. vue 网页滚动到指定位置显示动画效果

    大部分的网页,在滚动到一定位置的时候,当前区块的文案或者图片有一些飞入,淡入淡出,向上划入的动画效果 //向上划入样式 .boxUp {transform: translateY(0%) !impor ...

最新文章

  1. Fundebug录屏插件更新至0.4.0,修复BUG,优化性能
  2. 9.java.lang.ClassCastException
  3. Android复习04(适配器 Get()请求 适配器 getView()方法 Post()请求 保存Cookie 流转字符串 从网上获取图片 重点考Json解析)
  4. 在TreeView查找某一节点
  5. sql如何遍历几百万的表_SQL Server遍历表中记录的2种方法(使用表变量和游标)
  6. 密码学二次剩余困难性问题The Quadratic Residuosity Problem
  7. 4095: 韩信点兵
  8. java json.stringify_JSON.stringify() 方法
  9. java 替换html代码_Java中替换HTML标签的方法代码
  10. JAVAME 还有钱途么?
  11. 【官方文档】Fluent Bit 1.8 官方文档
  12. cisp证书含金量如何
  13. Android WebView监听console错误信息
  14. apple pay
  15. 〖全域运营实战白宝书 - 运营角色认知篇①〗- 初识运营,明晰运营的学习路径
  16. 在windows7上搭建STF
  17. 狸猫哥哥和他的冬葵花
  18. PDF被密码保护怎么解除?一篇文章教会你
  19. 阿里云apt-get安装包时Err:2 http://mirrors.cloud.aliyuncs.com/ubuntu xenial-security/main amd64 git amd64
  20. 深度linux安装spotify,如何在Kali Linux上安装Spotify

热门文章

  1. 软件开发实训需要用到的算法和结构_软件开发实习个人总结
  2. cx_Oracle怎么打包,cx_Oracle 在执行包文件 function 时有多个出参该如何获取
  3. ssm_layui_billmanagersystem账单管理系统(全栈开发)
  4. java socket ftp登录_基于java socket的简单FTP功能实现
  5. python绘制四边螺旋线代_解决python彩色螺旋线绘制引发的问题
  6. linux中循环删除脚本,shell脚本:遍历删除
  7. 如何备份数据_如何通过归档、备份和灾难恢复实现多云数据保护
  8. android 常用命令,Android开发常用命令整理
  9. linux下c代码调用.so,Linux下C程序调用.so(动态链)的一个例子
  10. JAVA两个视图层_MVC - 管理帐户 . 一个视图有两个局部视图和两个模型