Fllutter UI 上的内容
绝对布局组件用来按计算值进行布局.
Flutter 里面的许多 Widget 结构都是: 一个包裹 Widget, 一个提供数据的对象组合起来. 比如 Image + Provider, Icon + Data
布局时约束考虑就是自己的约束和父级的约束
布局 cheatsheet: https://medium.com/flutter-community/flutter-layout-cheat-sheet-5363348d037e 动画 cheatsheet: https://medium.com/flutter-community/flutter-animations-cheat-sheet-7f8cebfb850c https://docs.flutter.dev/development/ui/widgets/layout https://docs.flutter.dev/development/ui/layout https://docs.flutter.dev/resources/inside-flutter https://github.com/flutter/flutter https://docs.flutter.dev/development/ui/layout/constraints 动画: 值的变化 + 具体的动作(比如旋转) + 触发
- Layout 的详细内涵
- 官网文档和例子
- Widget 熟悉
- 书
记住: Constraints go down. Sizes go up. Parent sets position.
一个典型的布局流程如下:
- Widget 从
parent
获取自己的constraints
. constraints 只是 4 个值, 即 最大/最小 宽度/高度. - Widget 遍历自己的孩子, 告诉自己的每个孩子约束是什么, 然后让孩子确定孩子自己的大小.
- Widget 根据尺寸定位自己的孩子(孩子的 x 和 y 值, x 按从左到右, y 按上向下).
- Widget 告诉自己的父自己的尺寸, 从而让它的父也可以根据尺寸定位这个 Widget.
在一个 Padding 包裹 Column, 且 Column 有两个孩子的 Widget 布局中, 父容器有最多 300 * 85 的可用空间, 孩子和父的沟通过程在实际例子中的情况如下:
1. Widget: 向 parent 请求自己的 constraints
1. Parent: 你的约束是 width(80~300), height(30~85)
1. Widget: 我有 5 px 的 padding, 因此我的孩子只有最多 width(290) 和 height(75) 的可用空间
1. Widget: 孩子 1, 你有 width(0~290) height(0~75) 的可用空间
1. 孩子 1: 可以, 我会占 width(290), height(20)
1. Widget: 收到, 由于我 Column 的布局特性, 第一个孩子在顶上放入, 可以给孩子 2 剩下的空间是 width(0~290), height(0~55).
1. Widget: 孩子2, 你的可用空间是 width(0~290), height(0~55).
1. 孩子 2: 可以, 我想占 width(140), height(30)
1. Widget: 收到, 因为设置的是主轴居中, 这样我第一个孩子位置 (x:5, y:5), 第二个孩子的位置 (x: 80, y: 25).
1. Widget: Hi parent, 我决定自己的尺寸是 width(300), height(60). (因为 Column 是匹配孩子大小的, 高度是 20 + 30 + 5 * 2, 宽度按最大孩子的宽度).
Flutter 布局限定:
- Widget 只能在父级给定约束条件下决定自己的尺寸. 因此自己的尺寸并不能脱离父级约束而自己直接决定采用多大.
- Widget 不能决定自己的位置, 位置是由 Parent 确定的.
- 由于 Parent 的尺寸和位置也是 Parent 的 Parent 给的, 因此要确定某个 Widget 的位置, 只有整棵树全盘考虑.
- 如果孩子需要需要的尺寸和父级给的约束不同, 但父级没有足够信息来确定它的位置, 孩子的尺寸设置可能被忽略. 因此在对齐时必须具体.(一个简单例子就是当设置孩子尺寸, 但父约束要求孩子占满自己的情况下, 设置的大小就会被忽略.)
细节:
- 约束有两类: loose 和 tight, tight 优先级大于 loose
- 约束值可以是具体, 也可以是无限.
- 如果孩子要的大小比父能给的多, 则父只能允许孩子在可用范围内要到最多...
- UnconstrainedBox 是个特例, 它给孩子说我可以给你任意大小, 孩子要得多的话会出现 overflow. 如果孩子要无限, 则不能渲染任何东西并且有错误日志打印.
- Container 匹配孩子大小, 且传入孩子的约束最大是它的父所能给的最大大小
- LimitedBox 只有在父给的是无限时才会起作用
- Screen(就是根容器) 对孩子施加的约束是 tight 的约束, 让孩子和自己一样大.
- FittedBox 只能限制已有限制的孩子, 如果孩子没有限制则无法缩放展示.
- Row/Column 不会对其孩子引入任何额外的约束.
Weekly Widget
列表地址: https://www.youtube.com/playlist?list=PLjxrf2q8roU23XGwz3Km7sQZFTdB996iG
- 导航: NavigationRail: index=4
- 桌面端按钮自定义: FocusableActionDetector 6
- UserDefaults: shared_preferences 7
- google_fonts: 可以在本地缓存使用的字体 8
- RepaintBoundary: 将孩子限制在自己的图层中渲染, 不会全部重绘, 提升性能: 9
- StatefulBuilder: 限制仅该区域的重建 10
- ScaffoldMessenger: 弹窗的跨导航保持 11
- DropdownButton: 下拉按钮 12
- Badges: 帮助实现 APP 内部的 Barge 展示, 比如有好多消息 13
- Baseline: Flutter 中的 Widget 通过它的顶部和高度来确定位置, 如果想要关心从底部开始布局的时候, 使用这个. 14
- get_it: 依赖注入 15
- path_provider: 用于访问设备的文件系统 16
- Freezed: 不可变数据建模 17
- GestureDetector: 不是按钮, 但还是想让某个 Widget 可交互, 比如可以在 Stack 中拖动孩子进行交互 18
- CachedNetworkImage: 缓存网络图片的包 19
- Theme: 可以在任意层级包裹并提供自定义的 ThemeData 20
- TabPageSelector: 几个 Tab 切换, 配合 TabBarWidget, 使用 TabController 控制这个 selector 21
- Flow: 可以对展开的流式布局进行编排, 还可以添加动画 22
- font_awesome_flutter: Font Awesome 的图标库 23
- RefreshIndicator: 列表下拉刷新的那种 24
- HeroMode: 用来设置 Hero 动画的开关 26
- Collection: 提供集合类的许多算法的包 27
- MouseRegion: 判断鼠标是否在某个区域内, 在桌面实现时比较有用, 还可以改变鼠标的样式, 监听进入退出 29
- animated_text_kit: 提供许多的文本动画的包, 比如 typewritter 动画等 30
- Connectivity: 监听网络状态的包, 比如什么网络, 有没有网络等 32
- Scrollbar: 正常情况下 scrollView 没有滚动条, 要展示的话, 需要添加这个. 还可以横竖滚动条 33
- ExpansionPanel: 对 Widget 进行折叠和展开的组件, 在列表或展示详细信息时非常有用 34
- RotatedBox: 可以对界面组件进行旋转, 而且和直接变换不同, 因为它可以遵守之前整体的布局方式, 就好像那个部分没有旋转一样, 另外还可以用来动画 35
- flutter_slidable 包: 可以在列表上展示那种划过去有多个按钮的样式 36
- Animations 包: 提供非常有用的动画, 需要熟悉!! 37
- PhysicalModel: 如果有自定义阴影的需求, 这个非常好用! 38
- ImageFiltered: 虽然叫 ImageFiltered, 但实际上它是对渲染出来的任意图层进行加工, 只需要包裹 Widget 即可!! 提供比如 blur 等效果, 非常有用! 如果想对它下面的背景进行比如 blur 加工, 则可以使用 BackdropFilter. 只是 backdrop 的性能不是太高... 39
- Device_info 包: 提供设备的详细信息, 在事件记录时非常有用, 实际已升级为了 device_info_plus! 40 https://pub.dev/packages/device_info_plus 40
- SwitchListTile: 列表中的带 开关按钮的行, 实际还有类似的比如 RatioListTile, CheckboxListTile, xxxTile, 都是一个道理 42
- GridView: 网格滑动视图 43
- url_launcher: 启动 URL, 打开网页, 邮件等 47
- Package:async 包, 提供异步编程的许多支持功能 48
- Padding: 基础组件 51
- AnimatedWidget: 其他的 Widget 可以继承它, 用来实现自定义动画 52
- ClipOval: 可以将孩子包裹起来, 提供圆角等, 还可以提供任意图形的自定义 clipper. 53
- CupertinoActivityIndicator: apple 风格的菊花图标. 54
- IgnorePointer: 非常有用的一个组件, 可以将孩子区域设置为用户是否可交互, 但不会影响到它的外观, 类似 AbsorbPointer. 55
- Divider: 基础组件, 在布局时提供一个横隔 56
- CircularProgressIndicator 和 LinearProgressIndicator: 提供进度展示支持 57
- ClipPath: Clip 孩子, 任意形状 58
- Builder: 基础组件 59
- NotificationListener: 基础组件, 提供各类事件通知的监听 60
- ShaderMask: 提供对孩子的渲染 Mask, 比如对文字提供渐变展示等 61
- ListWheelScrollView: 可以实现比如日期设置的那种中间一个变大的效果, 轮式的选择列表 62
- SnackBar: 基础组件, 提供简单的消息通知, 比如"设备已连接" 这类的, 在展示的时候需要一个 Scaffold 提供上下文环境, 如果要在导航的前后都能展示, 则可以结合 ScaffoldMessenger 使用 63
- Drawer: 侧边可隐藏的菜单 64
- DefaultTabController & TabBar: 提供分 Tab 的展示, 内容可以通过 TabView 提供, 配合 TabController 实现转换 65
- Image: 基础组件, 展示图片, 还可以提供加载过程的数据, 这样可以添加加载进度, 支持若干图片格式, 包括 webp, gif, 如果 svg, 则需要使用 svg 的包 66
- TweenAnimationBuilder: 插值动画 67
- CupertinoActionSheet: 苹果风格的 一个选项列表 68
- ToggleButtons: 类似编辑器上的一系列开关, 比如点击加粗的按钮 69
- ColorFiltered: 对 Widget 颜色进行过滤, 比如可以对图片设置不同颜色, 还有许多的 Blend 模式可选 70
- DraggableScrollableSheet: 可以将一个 Widget 滑动到屏幕内, 到达屏幕内后, 可以持续滚动, 类似电信营业厅客户端的下面那个可以拖上来的界面 71
- AnimatedCrossFade: 可以在两个不同 Widget 间实现 Fade 动画转换, 比如将未连接状态动画变化为已连接 72
- AlertDialog: 实现类似 SheetWindow 那种的弹窗, 有 苹果和 Material 风格可选, 内容可以自定义, 风格可以自定义, 还可以自定义用户点击外部是否隐藏弹窗的能力 73
- Slider, RangeSlider, and CupertinoSlider: 通过滚动条的形式设置某个值, 另外还可以用来展示步骤, 这个在 step 1 -> step4 这类的情况非常有用 74
- DataTable: 数据表, 比较适合展示设备信息等的列表 75
- SelectableText: 可选的文本 76
- Container: 基础组件, 比如设置背景图/背景色, 大小约束, 孩子在容器中的位置等 77
- ListView: 滑动列表组件 79
- FractionallySizedBox: 包裹某个组件, 可以设置自己的size约束是父级的百分比, 在 Row 或 Column 中, 需要结合 Flexible 使用 80
- AnimatedOpacity: 可以动画改变某个组件的透明度, 这样它在一系列的组件中就可以突出展示(同时降低其他组件的透明度), 且隐式动画. 如果要详细控制, 可以使用 FadeTransition 81
- Stack: 在内部可以对多个孩子进行层叠布局, 可以设置自己的约束模式(匹配孩子还是匹配父), 配合 Positioned 来对每个孩子的位置进行设置 82
- ConstrainedBox: 基础组件, 可以对包裹的孩子设置 max/min 的 width/height, 比如一个图片, 可以约束它在窗口扩大缩小时候的最大大小 83
- IndexedStack: 可 以同时保持多个孩子的状态, 每次只展示某个孩子在界面上, 这样用户就可以切换不同的孩子来看(类似非整个屏幕的 tab 切换), 配合 Slider 的一系列, 可以实现比如 step1 到 4 的这样, 或用在引导页面上 85
- AnimatedPadding: 动画 Padding, 可以根据值进行动画 86
- AnimatedPositioned: 用在 Stack 中(和 Positioned 类似), 可以让这个孩子根据值进行动画, 比如 Slider 实际就是这样实现的 87
- AnimatedSwitcher: 在两个不同组件间使用自定义动画进行切换, 默认的是 Fade 动画, 但可以自定义, 比如魔术效果切换, 如果两个 Widget 类型相同, 需要设置 key 来区分 88
- ReorderableListView: 可以拖动来改变 list 的行 89
- RichText: 类似 AttributedString 的那种文本组件, 可以设置文字风格, 段落... 90
- Placeholder: 基础组件, 特别适合在创建 UI 草图的时候, 使用它进行占位, 然后进行详细实现. 默认它会占满父空间, 如果放到没有宽度/高度约束的父内部, 还可以提供一个默认的大小 91
- LimitedBox: 基础组件, 在父本身约束为非绑的情况下, 给那些匹配父约束的孩子设置约束, 如果父有约束, 这个组件不会生效. 它在 ListView 中非常有用, 比如在 ListView 中展示 Container 时(Container 是匹配父约束的设置, 然后 ListView 自己又没有高度约束), 这个时候使用本组件就可以限制 Container 的尺寸 92
- AspectRatio: 基础组件, 在需要关心宽高比而非宽高具体数值的情况下非常有用, 提供的比例是 宽 / 高. 93
- 还有一个情况是 AspectRatio 的父级没有某个约束(比如 Expanded), 但 AspectRatio 本身是匹配孩子的, 此时不确定 AspectRatio 应放到哪个位置, 可以在中间加一个 Align, 这样父还是填满父的父空间, 而 AspectRatio 自己就可以根据设置定位到具体的放置位置.
- AnimatedIcon: 基础组件, Flutter 提供的一系列动画图标 94
- InheritedWidget: 基础组件, 可以说是现代状态管理框架的基础. 它自己可以在树中任意位置插入, 这样子树中任意位置都可以拿到它, 孩子可以观察它并对应进行更新(它内部有 updateShouldNotify 方法), 配合 Notifier 就可以实现状态更新后的通知. 95
- Spacer: 基础组件, 用在 Row 或 Column 中, 提供额外的 Space 从而可以进行更好的自定义分配. 96
- MediaQuery: 基础组件, 查询屏幕相关的信息, 比如宽度, 用户字体大小系统设置等, 即用户 UI 设置. 97
- Flexible: 在 Row 或 Column 中自定义孩子的宽高占比, 比如设置三个孩子是 1 : 3 : 1. 还可以设置孩子是匹配父大小还是孩子匹配自己或自己孩子大小. 98
- AnimatedList: 提供 LIst 的动画能力, 比如插入删除更新表行. 99
- Draggable: 提供非常便捷的拖动交互能力, 比如把一个 Widget 拖到另外一个里面. 100
- ValueListenableBuilder: 注入后可以观察这个值的改变 101
- SizedBox: 基础组件, 提供 Widget 的具体尺寸, 比如固定大小的按钮, 并且如果有填满 Parent 的需求, 可以设置为 infinite, 或使用 SizedBox.expand 便捷生成 102
- Dismissible: 提供 Widget 的滑动移除能力 103
- AnimatedBuilder: 提供直接构造动画 Widget 的能力, 这里面说了如何写动画 104
- Positioned: 配合在 Stack 中指定孩子的位置 106
- Align: 在任意 Parent Widget 中指定孩子的位置, 也可以在 Stack 中, 类似 Positioned 的能力 107
- BackdropFilter: 提供 Widget 的渲染改变能力, 比较适合一些特殊效果的实现 108
- Transform: 提供将 Widget 进行三维转换的能力, 109
- AbsorbPointer: 同样是一个提供被包裹的 Widget 不被点击的能力, 类似 IgnorePointer. 110
- LayoutBuilder: 提供一个 build 回调, 在孩子进行前获取 constraints, 从而在 builder 中决定孩子的具体处理 111
- FittedBox: 基础组件, 提供让孩子在容器中以指定方式放入的能力 112
- Tooltip: 提供任意 Widget 的 Tooltip 113
- CustomPaint: 基础组件, 提供自定义绘制的能力. 实现时传入自定义的 Painter 类(继承 CustomPainter 重写里面的方法)作为绘制代码的实现. 114
- Hero: 实现 Hero 动画. 即提供在两个 Route 之间进行 Hero 动画的能力, 两个 route 内有一个共通的 Widget 作为 Hero 115
- ClipRRect: 提供 Widget 圆角能力, 同时有一些属性可以自定义, Flutter 还提供了 ClipPath, ClipOval 等... 116
- InheritedModel: 类似 selector 的能力, 配合 InheritedWidget, 当孩子用 InheritedModel 包裹时, 可以观察仅某个属性改变才更新 117
- StreamBuilder: 可以和一个 Stream 配合使用, 当 stream 有新 Event 后触发更新 118
- FadeInImage: 在图片加载时提供 PlaceHolder, 而且可以展示进度. 类似 SDWebImage 提供的能力 119
- SliverList & SliverGrid: 提供滚动组合的能力, Sliver 只是可滚动区域的部分描述. 它们两个一起可以实现复杂的滚动效果. 120
- SliverAppBar: 提供针对 AppBar 的滚动展示能力 121
- Table: 提供数据表的展示能力, 不需要滚动的时候 122
- PageView: 提供 Page 展示能力, 可以在多个 Page 间切换, 只需要配合 PageController 使用 123
- FloatingActionButton: 浮动的按钮 124
- FadeTransition: 简单的 Fade 动画 125
- FutureBuilder: 基础组件, 可以在 Future 满足后重建孩子. 126
- Opacity: 提供设置 Widget 的透明度能力, 动画版本是 AnimatedOpacity, 比如在 Stack 中层叠两 个孩子, 上层有透明度这样. 实现 welcome 的时候可以参考 127
- AnimatedContainer: 基础组件, 隐式动画容器 128
- Wrap: 流式布局, 在孩子空间不足时自动换行(换列) 129
- Expanded: 配合 Row 或 Column 使用, 让孩子可以占满可用空间, 或设置 flex 属性让孩子占多少百分比(是 Flexible 的再封装) 130
- SafeArea: 提供安全区, 避免被弄. 在桌面实现时, 用在弹窗中, 可以避开系统的一些区域. 131