GSYFlutterBook/Z3.md

233 lines
19 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Flutter 工程化框架选择 — 搞定 UI 生产力
```
本文为稀土掘金技术社区首发签约文章14天内禁止转载14天后未获授权禁止转载侵权必究
```
这是 《Flutter 工程化框架选择》 系列的第二篇 ,就像之前说的,这个系列只是单纯告诉你,创建一个 Flutter 工程,或者说搭建一个 Flutter 工程脚手架,应该如何快速选择适合自己的功能模块,或者说这是一个指引系列,所以比较适合新手同学。
本篇主要介绍 UI 相关的,**但是完全单纯介绍 UI 好像又有点水,那就是加一些小知识来吸吸水分吧**。
做为前端开发,我们的大部分职责就是开发 UI ,但是如果有人帮我们提前把 UI 做好,那岂不美哉?事实上很多时候 UI 确实是可以模版化,而前端领域也一直是这样,例如 `Ant Design` 、`Element-UI` 等 ,那 Flutter 上是否也有这样的支持?
答案肯定是有的,但是在介绍它们之前,**我们先聊一个 Flutter UI 的问题:嵌套**。
> 为了不太水,我们前言聊技术,后半部分推荐项目。
# 前言- UI 嵌套
谈到 Flutter 肯定就有人说嵌套,是的, Flutter 本身就是通过直接嵌套 `Widget` 来渲染 UI 所以大家可能就会吐槽类似下面的代码,虽然这段代码没有意义,但是这里我们要先思考两个问题:
- **Flutter 怕不怕 `Widget `嵌套影响性能**
- **Flutter 有没有办法解决嵌套**
![](http://img.cdn.guoshuyu.cn/20220923_Z3/image1.png)
**首先第一点就是Flutter 一般情况下不怕嵌套影响性能,因为 “众所周知” 的原因Flutter 里的 `Widget` 并不是真正的控件,我更愿意说 `Widget` 是配置文件,真正的绘制和布局对象是它背后的 `RenderObejct` 等相关逻辑**
> 嵌套层级看起来很多的原因,是因为 `Widget` 颗粒度太细。
当然这个还要看你嵌套的 `Widget` 做了什么?或者说是嵌套的 `Widget``RenderObject` 做了什么,例如:
- `Padding``RenderPadding` 就是在 layout 时多了一个 `Size``childParentData.offset` 计算
- `ColoredBox``_RenderColoredBox` 就是多一句 `drawRect`
- `Align``RenderPositionedBox` 就是多计算一个 `childParentData.offset`
所以这些 `Widget` 的颗粒度很细,但是也很轻,我们直接用的时候可能会一层一层嵌套,看起来不美观,但是实际渲染时对性能影响不大。
> **当然,并不是所有的 `Widget` 都很轻不怕嵌套**,例如 `Clip` 、`Transform` 和 `Opacity ` 等,如果涉及到 `pushLayer` 等操作时,在需要做图层合成的时候,那确实对性能影响还是比较大的。
**那第二个问题,如何解决嵌套?这时候你就需要 “配置模版” ,通过封装来优化代码结构**
“配置模版”是什么意思?举个例子 `Container` 应该用过吧? `Container` 其实就是官方给大家准备的 “模版” ,它本身只是一个 `StatelessWidget` ,也就是一个没有 `RenderObject``Widget` ,它靠的就是把各种功能的 `Widget ` 组合起来使用,如下图就是使用 `Container` 的对比情况。
| ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image2.png) | ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image3.png) |
| ----------------------------------------------------------- | ----------------------------------------------------------- |
所以在使用 Flutter 构建 UI 时,就可以谈及到两个点:
- `Widget` 是配置文件,它一般很轻,不怕嵌套,真正绘制渲染的是它背后的 `RenderObject`
- 通过各种 UI 配置模版来解决嵌套,特别是抽象出适合自己业务逻辑的 UI 模版
举个例子,如下方的第三方开源布局包 [dashboard](https://github.com/Mehmetyaz/dashboard) ,在这种复杂的 UI 布局上难道就靠直接一级一级嵌套 `Column``Row` 来解决?答案肯定不是!
| ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image4.gif) | ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image5.png) |
| --------------------------------------------- | ----------------------------------------------------------- |
[dashboard](https://github.com/Mehmetyaz/dashboard) 的是通过 `Stack` + `Positioned` 组成模版,在手势移动时计算,通过 `AnimatedBuilder` 实现动画偏移,自动计算控件位置。
> 其实也可以直接用 `AnimatedPositioned` ,具体可见 [《Flutter 小技巧之有趣的动画技巧》](https://juejin.cn/post/7111071430292275213)
所以可以看到, **Flutter 里你其实可以不那么嵌套,具体还是看你的封装方式**,除了这样,还有就是直接在 `RenderObject` 上进行自定义布局,比如下方这两个例子:
| [cloud](https://github.com/CarGuo/gsy_flutter_demo/tree/master/lib/widget/cloud) | [custom_multi_render](https://github.com/CarGuo/gsy_flutter_demo/blob/master/lib/widget/custom_multi_render_demo_page.dart) |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| ![image-20220922120414245](http://img.cdn.guoshuyu.cn/20220923_Z3/image6.png) | ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image7.png) |
你说上面的布局用 `Stack` + `Positioned` 的模式能不能做?肯定是可以,但是在 `RenderObject` 层实现不是更优雅吗?**把脏活累活写在 `RenderObject` 通过 `Widget` 提供配置接口,这样就不会一上来就向用户露 “底裤” 不是么**。
> 所以,把眼界打开,不要什么都盯着 `Widget` 嵌套,往 `RenderObject` 层面探索,你会发现 Flutter 其实不像表面那么浮躁,再不济来尝试下 `CustomMultiChildLayout` ,它也可以帮助你解决一些复杂布局下的嵌套问题。
当然,还有一些项目另辟蹊径,**比如 [niku](https://github.com/SaltyAom/niku) ,这个项目通过 `typedef` 和抽象拓展,利用语法对官方控件进行二次封装**,实现创建了一个 “非正道” 的 UI 配置效果,具体如下图所示,喜不喜欢就看个人爱好了,但是它确实一定程度解决了嵌套可视化的问题。
![](http://img.cdn.guoshuyu.cn/20220923_Z3/image8.png)
> 作者是个二次元,但是看地址他应该是泰国哥们
当然,我们这一期的关键是提高 UI 生产力,单说源码实现就没劲了,所以重点让我们看后半部分。
# UI 套件
在前端领域,**使用统一的 UI 套件可以加快开发的节奏,减少开发和设计之间的摩擦,而且风格统一**。一般情况下,在企业内部都是在不知不觉中沉淀下来各种组件,最后形成组件池,从而落地成 UI 套件。
比如**贝壳的 [bruno](https://github.com/LianjiaTech/bruno) ,我愿意称它为 Flutter 界的 `Element-UI`** ,目前已经支持到 Flutter 3 ,作为少有国内大厂维护的 Flutter UI 项目,甚至它还提供了 [sketch 设计指引](https://bruno.ke.com/page/guide/sketch) 和 [设计物料下载](https://bruno.ke.com/download/sketch) 。
| [bruno](https://github.com/LianjiaTech/bruno) | [getwidget](https://github.com/ionicfirebaseapp/getwidget) | [fsuper](https://github.com/Fliggy-Mobile/fsuper) |
| ----------------------------------------------------------- | ----------------------------------------------------------- | ----------------------------------------------------------- |
| ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image9.png) | ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image10.png) | ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image11.png) |
当然,除了 bruno 之后,像 [getwidget](https://github.com/ionicfirebaseapp/getwidget) 、 [fsuper](https://github.com/Fliggy-Mobile/fsuper) 也提供了日常开发中常用的 UI 套件,虽然风格风格上可能并没有 bruno 统一,但是还是可以在一定程度提高开发的生产力。
> 事实上对于个人开发者来说,这种套件可以解决很多设计上的问题。
**另外聊到 Flutter UI 套件就要一定要介绍国内的 [fluttercandies](https://github.com/fluttercandies)** 组织fluttercandies 是由大佬们共同维护的一系列 Flutter 开源项目,记住,是大佬们,并且一直在持续更新:
- [extended_image](https://pub.flutter-io.cn/packages/extended_image)
- [extended_nested_scroll_view](https://pub.flutter-io.cn/packages/extended_nested_scroll_view)
- [extended_text](https://pub.flutter-io.cn/packages/extended_text)
- [extended_text_field](https://pub.flutter-io.cn/packages/extended_text_field)
- [extended_list](https://pub.flutter-io.cn/packages/extended_list)
- [extended_sliver](https://pub.flutter-io.cn/packages/extended_sliver)
- [extended_tabs](https://pub.flutter-io.cn/packages/extended_tabs)
- [wechat_assets_picker](https://pub.flutter-io.cn/packages/wechat_assets_picker)
- [waterfall_flow](https://pub.flutter-io.cn/packages/waterfall_flow)
> 举个例子,如果 flutter framework 短期不能解决的问题,那就大佬就会 cv 一份控件自己维护,这就是 fluttercandies 的节奏和优势。
## PC
既然介绍 Flutter UI ,就不得不介绍 PC 相关的风格的 UI ,因为 Flutter 不只是 Android 和 iOS ,它还支持 Web 和 PC 所以类似 PC 的 UI 风格也值得推荐,**比如 ant_design_flutter 就是一个很有意思的项目**。
| [fluent_ui](https://github.com/bdlukaa/fluent_ui) | [macos_ui](https://github.com/GroovinChip/macos_ui) | [ant_design_flutter](https://github.com/CalsRanna/ant_design_flutter) |
| ----------------------------------------------------------- | ----------------------------------------------------------- | ------------------------------------------------------------ |
| ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image12.png) | ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image13.png) | ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image14.png) |
## Responsive
那有的人可能就说,**我想要一套代码适配多平台的屏幕尺寸**行不行?答案肯定是可以的,下面这几个 package 就提供了不同屏幕尺寸下一套代码的动态适配方案,我个人可能会比较喜欢 ResponsiveFramework 。
| [ResponsiveFramework](https://github.com/Codelessly/ResponsiveFramework) | [responsive_sizer](https://github.com/CoderUni/responsive_sizer/) | [flutter_adaptive_ui](https://github.com/mohammadtaherri/flutter_flexible_ui/tree/main/packages/flutter_adaptive_ui) |
| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
| ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image15.gif) | ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image16.png) | ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image17.png) |
## Appbar
这类 Appbar 的实现其实是我被问过最多的,其实它的核心实现都是 Sliver ,严格意义上我觉得并不需要第三方库,自己用 Sliver 就可以实现,但是本着能不动手就不动手原则,也推荐几个库吧:
| [draggable_home](https://github.com/4-alok/draggable_home) | [extended_sliver](https://github.com/fluttercandies/extended_sliver) | [scroll_app_bar](https://github.com/edsonbonfim/scroll_bars/tree/master/scroll_app_bar) |
| ---------------------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image18.gif) | ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image19.gif) | ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image20.gif) |
> [gsy_flutter_demo](https://github.com/CarGuo/gsy_flutter_demo) 里也提供了几种实现思路,其实并不复杂。
## Drawer
可能有人会觉得,不会吧不会吧, Drawer 也需要第三方库?
还真有,因为有时候可能需要不一样的动画效果,另外这里的 `sidebarx` ,也和官方提供的 `NavigationRail`有异曲同工之妙,能在 UI 上适配多平台的操作习惯。
| [sidebarx](https://github.com/Frezyx/sidebarx) | [flutter_advanced_drawer](https://github.com/alex-melnyk/flutter_advanced_drawer) | [curved_drawer](https://github.com/undrbridge/curved_drawer) |
| ---------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image21.gif) | ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image22.png) | ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image23.GIF) |
## Tarbar
既然都说到 `Drawer `,那 `Tabbar` 也提供几个花里胡哨的动画效果,主要是切换时的动画效果,另外 `tab_container` 可能算是比较有意思的库,用的 `Path` 来编绘背景动画效果。
| [flutter-cupertino-tabbar](https://github.com/aliyigitbireroglu/flutter-cupertino-tabbar) | [tab_indicator_styler](https://github.com/adar2378/tab_indicator_styler) | [tab_container]( https://github.com/sourcemain/tab_container) |
| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
| ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image24.gif) | ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image25.gif) | ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image26.gif) |
## BottomBar
说到 `Tabbar` 相对应的还有 BottomBar 相关,这里也提供几个库,主要是动画效果很有趣,我个人还是挺喜欢这种曲线的动画效果。
| [curved_navigation_bar](https://github.com/rafalbednarczuk/curved_navigation_bar) | [salomon_bottom_bar](https://github.com/lukepighetti/salomon_bottom_bar) | [bubble_bottom_bar](https://github.com/westdabestdb/bubble_bottom_bar) |
| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
| ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image27.gif) | ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image28.gif) | ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image29.gif) |
## 指引
启动指引这个需求,正常情况下一个 `PageView` 就可以满足产品经理的场景,但是有时候可能会需要你来“亿”点点动画效果来增加 KPI所示拿着也许就对你有用了当然你也可以把它当作 `PageView` 动画来使用。
| [concentric_transition](https://pub.dev/packages/concentric_transition) | [nice_intro](https://github.com/Ethiel97/nice_intro) | [intro_views_flutter](https://github.com/aagarwal1012/IntroViews-Flutter) |
| ------------------------------------------------------------ | ---------------------------------------------------- | ------------------------------------------------------------ |
| ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image30.gif) | ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image31.gif) | ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image32.gif) |
## 角标
这个应该无需多言了,基本上 App 都会需要用到,这两个库基本覆盖了 90% 的场景
| [flutter_badges](https://github.com/yadaniyil/flutter_badges) | [corner_decoration](https://github.com/kalaganov/corner_decoration) |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image33.png) | ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image34.png) |
## 动画按键
这个可能一般情况下大家都不需要这么花里胡哨的效果但是万一呢Material 风格上这种交互还是挺多的,不过国内对 Material 确实不是很感冒。
| [flutter_animated_button](https://github.com/NikhilVadoliya/FlutterAnimatedButton) | [progress_state_button](https://github.com/slm/progress-state-button) |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image35.gif) | ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image36.gif) |
## 头像
没想到吧?头像为什么还需要库?
其实就是下面的这个场景,相信这个场景可能大家都不会陌生,有社交需求的时候,经常会存在这样的 UI ,掘金沸点不也有类似 UI 么?
| [avatar_stack](https://github.com/cyrax111/avatar_stack) | [overflow_view](https://github.com/letsar/overflow_view) | |
| -------------------------------------------------------- | -------------------------------------------------------- | ---- |
| ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image37.gif) | ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image38.gif) | |
## swipe 卡片
这个需求可能一般人不会需要,推荐它是因为我还记得几年的时候,收了 1000 给人做了这样的一个外包,就是做一个这样的控件。
| [swipe_deck](https://github.com/retroportalstudio/swipe_deck.git) | [swipeable_card_stack](https://github.com/codetoart/cta-flutter-tinder-card-animation) | [appinio_swiper](https://github.com/appinioGmbH/flutter_packages/tree/main/packages/appinio_swiper) |
| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
| ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image39.gif) | ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image40.gif) | ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image41.gif) |
## bottom sheet
这其实更多是一个 Route 相关的动画效果,感觉好像国内也不常用到,但是之前确实有好几次咨询有没有类似的实现。
| [we_slide](https://github.com/luciano-work/we_slide) | [sliding_up_panel](https://github.com/akshathjain/sliding_up_panel) |
| ---------------------------------------------------- | ------------------------------------------------------------ |
| ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image42.gif) | ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image43.gif) |
## 时间轴 UI
这是我在群里被问过好多次的一个需求场景,我也不知道为什么那么多应用会需要用到这样的 UI ?不过这类需求自己从头实现确实会比较费事。
| [timeline_tile](https://github.com/JHBitencourt/timeline_tile) | [timelines](https://pub.dev/packages/timelines) |
| ------------------------------------------------------------ | ----------------------------------------------- |
| ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image44.gif) | ![](http://img.cdn.guoshuyu.cn/20220923_Z3/image45.gif) |
好了,关于 Flutter UI 相关的内容推荐就到这里,**本篇主要还是提供给大家如何理解 Flutter 的 UI 布局,并且尽可能去解决嵌套,同时提供一些有意思的第三方 package ,进一步提高大家开发 UI 的生产力**。
最后,如果你还有什么关于 Flutter 工程或者框架的疑问,欢迎留言评论,也许新的素材又有了~