跨端开发的前世今生
大帅曾经是一名闪客
。
之所以提到这个,是因为我说Flash是曾经的Web1.0时代的跨端之王,应该没有人反对吧(我个人拿Flash做过网页,在当时还没有Adobe AIR的时候,我就拿.net +
ActiveObjectX实现过桌面端),后来的ActionScript3.0更是ES4
的唯一实现。不过那个时候还没有诞生移动互联网,直到乔帮主给Flash下了驱逐令。
跨端真正变成一种开发方式,要从移动互联时代开始说起
1.基于Webview的跨端模式
就是使用网页浏览容器(Webview)来呈现html页面,配合Webview和原生系统的通讯api,可以调用原生方法。优点是开发效率高,成本最低,缺点是Webview的内存开销较高,启动白屏问题以及没有原生的页面跳转体验等(这个问题后来的引擎通过webview多开都解决了)。
2.使用JS+受限的HTML和CSS的Native渲染模式
为了解决Webview跨端的问题,另一种新的方案被提出来。代码仍然使用Javascript编写,运行在独立的JS内核(如JSCore,V8)中,使用受限的HTML,受限的CSS来编写界面,但最终会使用原生的UI框架来渲染(如UIKit)。Facebook旗下的RN,Apache基金会的Weex都属于这种方式。
3.Hybrid渲染模式
注意,不是混合开发,而是指混合渲染。是在一个页面里既使用Webview来渲染又使用原生的UI来渲染。比如微信小程序
第2,3种方式都有一个问题,就是JS代码是运行在独立的JS内核中,和视图层的渲染不在一个线程里,那逻辑层和视图层里的数据要互通,会有通讯折损,这个时间差大部分时候我们感受不到。但我们去尝试做一个跟手的交互效果,就能明显感受到。
为了解决这个问题,在RN/Weex里我们有了BindingX方案,微信小程序里有了WXS方案。
自渲染的Flutter
Flutter是自己“独创
”的一套渲染模式,即不使用webview来渲染,也不使用原生UI来渲染,而是自己实现了一套声明式的UI体系,然后在画布里画出来。
这套东西并不新鲜
十几年前的Flash也是“自渲染”呀,当年就很多“传统工程师
”反映在Flash里做UI太麻烦了,后来有了第三方的UI框架Aswing等,再后来有了Flex。各种知名的游戏引擎也是如此,比如Unity3D,Unreal。
游戏里不也有各种UI吗?它们的跨端表现不也是一致的吗?游戏里要绘制那么多图形,浮点运算,3D渲染....效率不也挺高的吗?
所以,别被这些新词搞蒙了,“自渲染”就是自己有一套规范约束声明UI,然后自己在一个独立的“画布”里把它们绘制出来。这个画布在游戏引擎里叫OpenGL
,WebGL
....在Flutter里,它叫SGL
(SkiaGraphicsLibrary)。
而Skia
本身就很强大,Chrome浏览器,Android系统的底层绘制库都是它。
Dart语言
对于Web前端开发者而言,Dart绝对不是把你拦在门外的因素,毕竟Dart语言也是ECMA的标准。但Dart在提供一些新特性的同时,也有其特立独行的一面,这些差异会增加Web前端开发者的学习和记忆成本。
举个简单的例子,获取一个0.0到1.0之间的随机浮点值
//JS的随机浮点值 Math.random(); //Dart的随机浮点值 Random().nextDouble();
//JS的数组 var list = []; list.push(1); list.push(2,3,4); //Dart的数组 var list = []; list.add(1); list.addAll([2,3,4]);
像这样的差异还有挺多,如果你的工作需要在两种语言间反复切换,那就换个工作吧~~ 哈哈:p!开个玩笑,但你应该感受到了什么叫做记忆成本的增加。
安装Flutter开发环境
这里就不废话了,请查看 安装教程 。开发环境支持Win/Mac/Linux。
不安装开发环境,我们也能在网页里 dartpad.cn 来编写调试感受一下Dart和Flutter的魅力
IDE选择
- VSCode
安装插件:Flutter,Dart,Bracket Pair Colorizer,Awesome Flutter Snippets
- Android Studio
无论是是否使用Android Studio来编写Dart代码,Android Studio都是Flutter开发环境安装的必选项。
我平时属于经常在多个前端语言里切换的,主要使用的IDE就是VSCode,所以我基本不使用Android Studio。但我在看了很多其他大佬的视频后发现,Android Studio更配Flutter,有一些特性VSCode里暂时还没有插件可以实现。
嵌套地狱?
Flutter是一种声明式UI框架,每个组件,会有个build函数,这里会返回一个能够完整描述UI的对象结构。
而Flutter的嵌套地狱问题,主要就来自这个声明式UI的特性。我们可以用拆解嵌套
来解决嵌套过深的问题,但嵌套的究竟是什么?
来,让我换一个说法
给你介绍
声明式UI
就是 虚拟Dom
万物皆Widgets!
像 万物皆Widgets ,一切皆组件
这样的话很多文章都说过了。
我提一杯,不是,提一句
子不教,父之过
- 当儿子没有这个能力的时候,找他爹!
- 他爹没有这个能力的时候,找他爷爷!
- 他爹没有这个能力的时候,是不是可以换个爹!
我把官方文档中列举的所有Widgets做成一个脑图
微信搜索 大帅老猿
关注后回复 flutter
即可下载
Flutter项目基本结构
创建项目
flutter create projectname
配置文件
pubspec.yaml
这个文件就等于我们熟悉的packages.json
- 配置依赖
dependencies: flutter: sdk: flutter flame: ^1.0.0-rc5 dev_dependencies: flutter_test: sdk: flutter
- 配置图片和字体
assets: - assets/images/ - assets/images/xxx.jpg fonts: - family: MyFont fonts: - asset: assets/fonts/myfont.ttf
pubspec.yaml的配置采用缩进式结构体,在配置时要注意缩进的规则。
入口代码
lib/main.dart
你所有的代码都应该在lib这个文件夹下,你可以根据自己的习惯来组织你的代码。
项目内常用命令
查看当前可run的设备列表
flutter devices
将Flutter项目运行到设备列表中的默认项
flutter run
将Flutter项目运行到设备列中的指定设备
flutter run -d macos
入门demo之点不到的按钮
界面里有一个按钮,点击后就随机改变坐标
double left = 100;//x坐标 double top = 100;//y坐标 //爷爷是Stack,爸爸是Positioned,儿子是ElevatedButton Stack( children:[ Positioned( left:left, //x坐标 top:top, //y坐标 child:ElevatedButton( child:Text("点我呀"), onPressed:(){ setState((){ left = Random().nextDouble()*300; top = Random().nextDouble()*300; }) } ) ) ] )
加入动画
位置改变的时候加入动画效果?So easy~
Flutter的Widget封装得太好了,记得我们前面说的。
儿子不行找爸爸
爸爸不行,换一个爸爸
我们只需要把Positioned换成AnimatedPositioned,然后设置一下动画持续时长
Stack( children:[ AnimatedPositioned( duration:Duration(millsecond:500),//动画持续500毫秒 left:left, //x坐标 top:top, //y坐标 child:ElevatedButton( child:Text("点我呀"), onPressed:(){ setState((){ left = Random().nextDouble()*300; top = Random().nextDouble()*300; }) } ) ) ] )
Flutter里的路由
使用Navigator
推入新页面
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context){ return PageDetail(); }));
退出当前页
Navigator.pop(context);
动画之神奇移动?
两个路由页之间相同元素的动画怎么做?比如A页面是个通讯录列表页,B页面是点击之后的联系人详情页。A页面的头像和昵称要以动画的方式移动到B页面里的状态。
好好感受一下这个动画,它在两个页面之间
在其它框架里,要实现这个动画效果,要么你创建一个独立于两个页面的顶级元素,在A页面的动画开始时隐藏元素,B页面先隐藏元素推入,在动画结束后再将其显示出来。要么把两个页面整合到一个页面里。
而在Flutter里,我们只需要用Hero动画将目标动画元素包裹起来,即可直接实现。
//A页面 Hero( tag: "logo", child: FlutterLogo( size: 64, )
//B页面 Hero( tag: "logo", child: FlutterLogo( size: 128, )
就是这么简单!
结束语
简简单单的一个入门导读,并没有特别系统的介绍到Flutter的方方面面,但希望能让更多的Web前端工程师们对Flutter产生兴趣,加入进来吧!