目录
- 参考文章
1.Flutter是什么?
- Flutter是Google papa推出的一款全新的,响应式·跨平台·高性能的移动开发框架。
2. Flutter与其他框架对比
- 在移动开发的中的跨平台中有以下几种方案:
- 基于WebView 和JavaScript(Cordova,AppCan)
- 基于HTML和JavaScript渲染映射成原生控件(ReatNative、Weex)
- 基于微信生态的小程序
- 基于原生编码无桥接(Flutter)
方案 | 优点 | 缺点 |
---|---|---|
基于WebView和JavaScript的方案(Cordova) | 1. 可以继承Web开发的所有成果 (丰富的控件库,满足各种需求的页面框架,完全动态化,自动化测试工具等) 2.学习成本低(不需要太多的成本和迁移成本就可以开发一个app) | 1.WebView渲染效率和JavaScript的执行性能太差 2.由于Android各个系统版本和厂商的定制,很难保证在所有设备有一致的效果 |
基于HTML(vue)和JavaScript渲染映射成原生控件(ReatNative,Weex) | 1.将渲染工作交给原生,性能体验好 2.Facebook出品推出时间较长,社区资源丰富 | 随系统版本变化和API的变化,需要处理不同平台的差异,有的特性不能满足所有平台(第三方库良莠不齐,维护困难) |
基于微信生态的小程序 | 1.迭代速度快,学习成本低 2.可以实现动态无缝更新,可以利用微信强大的用户基数 | 依赖于微信产品生态,定制程度大打折扣 |
基于原生编码无桥接的Flutter | 1.热重载 2.渲染引擎依赖跨平台的Skia图形库(一个开源的2D图形库在一系列硬件和软件平台提供通用的API),可以最大程度保证不同平台和设备的体验一致性 3.使用支持AOT的Dart语言,执行效率比JavaScript好很多 4.美观可定制的组件 | 1.dart 语言的生态小,精通成本比较高 2.嵌入外部 platform view 成本高这块(基于官方代码)目前在 iOS 端有支持,android 上还没有,但相关开发者博客上有提到实现了webview,mapview 等 platform view 的嵌入。从 iOS 端的实现来看,每嵌入一层 platform view 会额外多一层 surface,内存代价比较高 3.flutter 目前提供的开箱即用的功能只有 UI framework + dart 语言的能力,平台能力需要通过 platform channel 来扩展。(目前丰富的程度有限,未来可期) |
3.Flutter的Dart架构和Dart语言
-
Flutter的框架部分全部完全使用Dart语言实现,有着清晰的分层架构。分层架构使得我们可以在调用Flutter提供的便捷开发功能之外,还可以修改每一层额实现Framework的底层是flutter引擎,引擎主要负责图形绘制(skia),文字排版(libtxt)和提供Dart运行时,引擎全部使用C++实现,Framework层使我们可以用Dart语言引擎的强大能力.
Dart部分的最低层为Foundation其中大都是非常基础的,提供给其他所有层的工具类和方法。
绘制库(Painting 封装了Flutter Engine 提供的绘制接口,主要是为了在绘制控制等固定样式时提供更直观,更方便的接口,比如绘制缩放后的位图,绘制文本,插值生成阴影以及在盒子周围绘制边框等。
Animation动画类提供了类似Android系统的ValueAnimator的功能,并且提供了丰富的内置插值器。
Gesture手势类提供了手势识别相关功能,包括触摸事件类定义和多种内置的手势识别器。GestureBinding类是Flutter中处理手势的抽象服务类,继承自BindingBase类。Binding系列的类在Flutter中充当类似于Android中的SystemService系列(ActivityManager,PackageManager)功能,每个Binding类提供一个服务的单例对象,App最顶层的Binding会包含所有相关的Binding抽象类。如果使用Flutter提供的控件开发,则需要使用WidgetsFlutterBinding,如果不使用Flutter提供的控件而直接调用Render层,则需要使用RenderingFlutterBinding。
-
渲染库(Rendering)
-
Flutter的控件在实际显示时会转换成对应的渲染对象(RenderObject)树来实现布局和绘制操作。一般情况下,我们只会在调试布局,或者需要使用自定义控件来实现某些特殊效果的时候,才需要考虑渲染对象的细节。渲染库主要提供的功能类有:
(对于mixin的Dart语言机制可以参考Flutter基础:理解Dart的Mixin继承机制)/// The glue between the render tree and the Flutter engine. //RendererBinding是渲染树和Flutter引擎的胶水:负责管理帧重绘,窗口尺寸和渲染相关变化的监听 mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, SemanticsBinding, HitTestable { } /// RenderObject渲染树中所有节点的基类,定义了布局,绘制和合成相关的接口 abstract class RenderBox extends RenderObject { } /// An image in the render tree. class RenderImage extends RenderBox { } /// A table where the columns and rows are sized to fit the contents of the cells. class RenderTable extends RenderBox { } /// Displays its children in a one-dimensional array. class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, FlexParentData>, RenderBoxContainerDefaultsMixin<RenderBox, FlexParentData>, DebugOverflowIndicatorMixin { } /// A render object that displays a paragraph of text class RenderParagraph extends RenderBox { }
-
-
在Flutter界面渲染过程分为三个阶段:布局,绘制,合成,其中布局和绘制在Flutter框架中完成,合成交由Engine负责
- UI绘制流程
- 1.运行动画,动画的结果会导致 Widget State 的改变;
- 2.State Changes 触发 Flutter 生成一棵新的 Widget 树;
- 3.Flutter 根据新/旧 Widget 树的差异更新 Render 树,重新排版更新界面布局;
- 4.Flutter 根据新的 Render 树更新 Composited Layer(合成图层)的 Display List;
- 5.输出新的图层树;
- UI绘制流程
-
Widgets库
- Flutter提供了非常丰富的控件,包括最基本的文件,图片,容器,输入框和动画等。在Flutter中“一切皆是控件”,通过组合,嵌套不同类型的控件可以构成任意功能,任意复杂度的界面,以下为widget库中重要的几个类:
WidgetsBinding是widgets 层和Flutter引擎的胶水层
- Widget就是所有控件的基类,它本身的所有数据是只读的。RenderingObjectWidgets所有的实现类负责提供配置信息并创建具体的RenderObjectElement。widget的属性最好都是immutable。
- Element是Flutter用来分离控件和真正渲染对象的中间层,控件用来描述对应的element属性,存放上下文,通过Element遍历视图树,Element同时持有Widget和RenderObject。控件重建后可能会复用同一个element。RenderObjectElement持有真正负责布局,绘制和碰撞测试(hit test)的RenderObject对象。
- RenderObject:根据Widget的布局属性进行layout,paint Widget传入的内容。
- 为什么widget都是immutable?
flutter界面开发是一种响应式编程,主张simple is fast,flutter设计的初衷希望数据变更时发送通知到对应的可变更节点(可能是一个StatefulWidget子节点,也可以是rootWidget),由上到下重新create widget树进行刷新,这种思路比较简单,不用关心数据变更会影响到哪些节点。
2.widget重新创建,element树和RenderObject树是否也重新创建?
widget只是一个配置数据结构,创建是非常轻量的,加上flutter团队对widget的创建/销毁做了优化,不用担心整个widget树重新创建所带来的性能问题,但是RenderObject就不一样了,RenderObject涉及到layout、paint等复杂操作,是一个真正渲染的view,整个view 树重新创建开销就比较大,所以答案是否定的。
- 为什么widget都是immutable?
-
-
Dart语言
- Dart语言的重要理念
- 放在变量中的所有东西都是一个对象,每个对象都是一个类的实例。即使是数字,功能, null也是对象。所有对象都从Object类继承。
- 虽然Dart是强类型的,但类型注释是可选的,因为Dart可以推断类型。在上面的代码中,number 被推断为是类型的int。当你想明确地说没有类型时, 使用特殊类型dynamic。
- Dart支持泛型类型,如List(整数列表)或List(任何类型的对象列表)。
- Dart支持顶层函数(如main()),以及与类或对象绑定的函数(分别为静态方法和实例方法)。你也可以在函数中创建函数(嵌套函数或局部函数)。
- Dart支持顶级变量以及绑定到类或对象(静态变量和实例变量)的变量。实例变量有时称为字段或属性。与Java,dart不具备关键字public,protected和private。如果标识符以下划线(_)开头,则它的库是私有的。有关详细信息,请参阅 库和可见性。
- 标识符可以以字母或下划线(_)开头,然后是这些字符和数字的任意组合。有时候,重要的是某件事是一种表达式还是一种 声明,所以这两个词的确切含义很有帮助。
- Dart工具可以报告两种问题:warnings 和errors。警告只是表明您的代码可能无法正常工作,但它们不会阻止您的程序执行。错误可以是编译时或运行时。编译时错误导致代码无法执行; 运行时错误导致 代码执行时引发异常。
- Dart语言入门
- 可以参考系列文章对Dart语法有一个初步的了解
- Dart语言的重要理念
4.Flutter 初体验
- Flutter纵使千般好,纸上得来终觉浅。按照官网下载了Flutter SDK,使用Android Studio 3.3.2,使用了Github的下列教程代码 awesome-flutter的FlutterWhatsAppClone项目
- pubspec.yaml
- 依赖配置声明文件
#在Flutter中,依赖包由Pub仓库管理,项目依赖配置在这个文件中声明即可, #对于未发布在Pub仓库的插件可以使用git仓库地址或文件路径 name: flutterwhatsapp description: A new Flutter project. dependencies: flutter: sdk: flutter # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^0.1.0 camera: dev_dependencies: flutter_test: sdk: flutter # For information on the generic Dart part of this file, see the # following page: https://www.dartlang.org/tools/pub/pubspec # The following section is specific to Flutter. flutter: # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. uses-material-design: true # To add assets to your application, add an assets section, like this: # assets: # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.io/assets-and-images/#resolution-aware. # For details regarding adding assets from package dependencies, see # https://flutter.io/assets-and-images/#from-packages # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a # "family" key with the font family name, and a "fonts" key with a # list giving the asset and other descriptors for the font. For # example: # fonts: # - family: Schyler # fonts: # - asset: fonts/Schyler-Regular.ttf # - asset: fonts/Schyler-Italic.ttf # style: italic # - family: Trajan Pro # fonts: # - asset: fonts/TrajanPro.ttf # - asset: fonts/TrajanPro_Bold.ttf # weight: 700 # # For details regarding fonts from package dependencies, # see https://flutter.io/custom-fonts/#from-packages ```
- 依赖配置声明文件
- main.dart
- app的入口文件
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutterwhatsapp/whatsapp_home.dart'; import 'package:camera/camera.dart'; List<CameraDescription> cameras; Future<Null> main() async { cameras = await availableCameras(); runApp(new MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return new MaterialApp( title: "WhatsApp", theme: new ThemeData( primaryColor: new Color(0xff075E54), accentColor: new Color(0xff25D366), ), debugShowCheckedModeBanner: false, home: new WhatsAppHome(cameras), ); } }
- app的入口文件
- whatsapp_home.dart
- app主页
import 'package:flutter/material.dart'; import 'package:flutterwhatsapp/pages/call_screen.dart'; import 'package:flutterwhatsapp/pages/camera_screen.dart'; import 'package:flutterwhatsapp/pages/chat_screen.dart'; import 'package:flutterwhatsapp/pages/status_screen.dart'; class WhatsAppHome extends StatefulWidget { var cameras; WhatsAppHome(this.cameras); @override _WhatsAppHomeState createState() => new _WhatsAppHomeState(); } class _WhatsAppHomeState extends State<WhatsAppHome> with SingleTickerProviderStateMixin { TabController _tabController; @override void initState() { super.initState(); _tabController = new TabController(vsync: this, initialIndex: 1, length: 4); } @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: new Text("WhatsApp"), elevation: 0.7, bottom: new TabBar( controller: _tabController, indicatorColor: Colors.white, tabs: <Widget>[ new Tab(icon: new Icon(Icons.camera_alt)), new Tab(text: "CHATS"), new Tab( text: "STATUS", ), new Tab( text: "CALLS", ), ], ), actions: <Widget>[ new Icon(Icons.search), new Padding( padding: const EdgeInsets.symmetric(horizontal: 5.0), ), new Icon(Icons.more_vert) ], ), body: new TabBarView( controller: _tabController, children: <Widget>[ new CameraScreen(widget.cameras),// 相机模块 new ChatScreen(),//聊天模块 new StatusScreen(),//状态模块 new CallsScreen(),//电话模块 ], ), floatingActionButton: new FloatingActionButton( backgroundColor: Theme.of(context).accentColor, child: new Icon( Icons.message, color: Colors.white, ), onPressed: () => print("open chats"), ), ); } }
- app主页
- pubspec.yaml