一、Flutter 是什么?
Flutter 是 Google 推出的 UI 框架,帮助开发者通过一套代码同时运行在 iOS 和 Android 上,构建媲美原生体验的精美应用!实际上 Flutter 不止于移动平台,正逐渐从移动设备扩展到多个平台,例如 Web、macOS、Windows、Linux、嵌入式设备等,因此 Flutter 是适用于所有屏幕的便携式界面框架,Flutter 一切皆是 Widget;自绘 UI;Flutter 只接管 UI 层,蓝牙等系统功能通过插件的形式提供。
二、Flutter 有哪些特点?
- 美观:可对 UI 实现像素级的控制,且内置 UI 库 ( Material、Cupertino )
- 快速:硬件加速图形引擎、代码被编译成机器码
- 高效:保持应用状态的热重载 ( hot reload )
- 开放:完全开源的项目 ( BSD 开源协议 )
三、Flutter 系统架构
Flutter 使用 C、C++、Dart 和 Skia ( 2D 渲染引擎 ) 构建,详情见 Flutter 系统架构
Flutter ( Android / iOS ) |
Flutter Web |
 |
 |
四、Flutter 与前端的一些对比
技术都是相通的,寻找相似点能让我们快速上手一门新技术。
Flutter 与前端有不少相似点,比如 Flutter 借鉴了 React 响应式 UI 编程的思想,Flutter 也有 Flexbox、Grid 布局,此外 Dart 与 JavaScript 的语法有不少相似点。
实际上,Flutter 项目正是诞生于 Chrome 团队,详情见 “听 Flutter 创始人 Eric 为你讲述 Flutter 的故事”。此外,Dart 设计之初是为了取代 JavaScript,只不过最终取代失败,因而转换定位,服务于 Flutter。
|
Flutter |
前端 |
编程语言 |
Dart |
JavaScript |
响应式 UI 编程 |
借鉴 React |
React、Vue、Angular |
状态管理 |
Provider、Redux、Mobx |
Redux、Mobx、Vuex |
页面样式 |
Widgets |
CSS、styled-component |
UI 库 |
官方内置 Material Design、Cupertino |
社区 Ant Design、Element |
内嵌视图 |
PlatformView |
iframe |
开发和调试工具 |
Dart DevTools |
Chrome DevTools |
编辑器 |
VS Code、Android Studio |
VS Code、Sublime Text |
在线编辑器 |
DartPad、CodePen |
CodePen、JSFiddle |
包管理工具 |
pub |
npm、yarn |
|
Dart |
JavaScript |
编译 |
即时编译 (JIT) 或提前编译 (AOT) |
即时编译 ( JIT ) |
异步非阻塞 |
单线程、事件循环、微任务、宏任务 |
单线程、事件循环、微任务、宏任务 |
异步编程 |
Future、async、await |
Promise、async、await |
类型系统 |
type safestatic type checking and runtime checks |
TypeScriptstatic type definitions |
继承 |
Class |
原型链 |
密集型计算 |
Isolate |
Web Worker |
|
Flutter |
CSS |
样式化文本 |
Text、RichText |
font-size、font-weight、font-family… |
盒模型 |
只有 border-box |
box-sizing: content-box、border-box; |
弹性盒子布局 |
Row、Column |
display: flex、inline-flex;flex-direction: row、column; |
网格布局 |
Grid |
display: grid; |
定位方式 |
Aligin、Stack & Positioned、Slivers |
position: static、relative、absolute、sticky、fixed |
变换 ( 旋转 缩放 倾斜 平移等 ) |
Transform |
transform |
举个 🌰
1 2 3 4 5
| <div class="greybox"> Lorem ipsum </div>
.greybox { background-color: #e0e0e0; /* grey 300 */ width: 320px; height: 240px; font: 900 24px Georgia; display: flex; align-items: center; justify-content: center; } // Flutter Dart var container = Container( // grey box color: Colors.grey[300], width: 320, height: 240, child: Center( child: Text( "Lorem ipsum", style: TextStyle( fontWeight: FontWeight.w900, fontSize: 24, fontFamily: "Georgia", ), ), ), );
|
五、环境搭建
参考官网[1],有非常详细的教程。
关键步骤,安装 Flutter SDK。
IDE 推荐使用 Android Studio,当然 VS CODE 装上对应插件也 OK。
六、代码对比
入口文件
main.dart 作为入口文件主要有一个主函数 main,同时这个主函数也是作为整个应用的入口函数,其中 main 里面起到关键作用的就是 runApp 函数,这与 React 的 ReactDOM.render 作用类似。
1 2 3 4 5 6
| import 'package:flutter/material.dart'; import 'app.dart';
void main() { runApp(App()); }
|
对比的 React 代码
1 2 3 4 5 6 7 8 9 10 11
| import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
ReactDOM.render( <App />,
document.getElementById("root") );
|
Model 层设计
Todo List 应用有列表以及 todo 详情,因此我们这一块设计两个类,一个 TodoList 类对应列表,一个 Todo 类对应 todo 详情。
至于 React 项目那边,可能这种设计不是很常见,但是为了方便对比,设计和 Flutter 保持了一致。
Flutter Todo 类代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import 'package:uuid/uuid.dart';
class Todo { bool complete; final String id; final DateTime time; String task;
Todo({ this.task, this.complete = false, DateTime time, String id }) : this.time = time ?? DateTime.now(), this.id = id ?? Uuid().v4(); }
|
React 对比代码:
1 2 3 4 5 6 7 8 9 10 11 12
| import { v4 } from "uuid";
class Todo { constructor(task, id = v4(), complete = false, time = new Date().toLocaleString()) { this.id = id; this.task = task; this.complete = complete; this.time = time; } }
export default Todo;
|
页面路由
Flutter 的路由跳转主要用到 Navigator,React 那边对应的就是 history。
页面路由有几种方式,详细参考官网。这里为了与 React 对比主要介绍命名路由。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import 'package:flutter/material.dart'; import 'pages/detail/index.dart'; import 'pages/list/index.dart'; import 'models/todo_list.dart'; import 'package:provider/provider.dart';
class App extends StatelessWidget { const App({Key key}) : super(key: key);
@override Widget build(BuildContext context) { return MultiProvider( providers: [ ChangeNotifierProvider(create: (_) => TodoList()), ],
child: MaterialApp( title: 'flutter todo list', initialRoute: '/', routes: {
'/': (context) => ListPage(),
'/list': (context) => ListPage(),
'/detail': (context) => DetailPage(false),
'/edit': (context) => DetailPage(true),
}, ), ); } }
|
React 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import { BrowserRouter, Switch, Route } from "react-router-dom"; import TodoListContext, { todoList } from "./models/todoList"; import DetailPage from "./pages/detail"; import ListPage from "./pages/list"; import "./App.css"; import "antd-mobile/dist/antd-mobile.css";
function App() { return ( <TodoListContext.Provider value={todoList}> <BrowserRouter> <Switch> <Route exact path="/" component={ListPage} /> <Route exact path="/list" component={ListPage} /> <Route exact path="/detail" component={DetailPage} /> <Route exact path="/edit" component={DetailPage} /> </Switch> </BrowserRouter> </TodoListContext.Provider> ); }
export default App;
|
七、Flutter 为什么选择 Dart ?
- Flutter 选择开发语言时,使用 4 个主要维度进行评估,Dart 在所有评估维度上都取得高分
- 开发者的生产力
- 面向对象
- 稳定可期的高性能表现
- 快速内存分配
- Dart 的运行时和编译器支持 Flutter 的两个关键特性
- 基于 JIT ( 即时编译 ) 的快速开发周期,允许在带类型的语言中支持形变和有状态热重载
- 一个能产出高效率 ARM 代码的 AOT (Ahead of time 提前编译) 编译器,从而确保快速启动的能力和可预期的生产版本运行性能
- Dart 团队就在你身边:与 Dart 社区展开了密切合作,Dart 社区积极投入资源改进 Dart,以便在 Flutter 中更易使用
八、Flutter 性能为何能够媲美原生应用?

九、Flutter 与原生交互
适用于不带 UI 的功能,Flutter 与原生约定通道方法,原生通过 API 的形式提供定位、蓝牙、传感器等系统功能,或者复用客户端 SDK,提供请求、上传、美颜、人脸识别、推送、 IM 等基础功能

适用于带 UI 的功能,Flutter 内嵌原生视图,例如地图、WebView 等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| Widget build(BuildContext context) { if (defaultTargetPlatform == TargetPlatform.android) { return AndroidView( viewType: 'plugins.flutter.io/google_maps', onPlatformViewCreated: onPlatformViewCreated, gestureRecognizers: gestureRecognizers, creationParams: creationParams, creationParamsCodec: const StandardMessageCodec(), ); } else if (defaultTargetPlatform == TargetPlatform.iOS) { return UiKitView( viewType: 'plugins.flutter.io/google_maps', onPlatformViewCreated: onPlatformViewCreated, gestureRecognizers: gestureRecognizers, creationParams: creationParams, creationParamsCodec: const StandardMessageCodec(), ); } return Text( '$defaultTargetPlatform is not yet supported by the maps plugin'); } }
|
十、Flutter 开发体验:”UI as Code”
Flutter 的 UI 代码使用 Dart 语言,其优点如下:
- Flutter 的声明式 UI 编写方法能够直观地描述 UI 结构 ( 借鉴 React )
- 不需要为 UI 布局学习额外的语法
- 不需要维护代码之外的 UI 定义文件
但是,也存在几个问题:
问题一:复杂 UI 逻辑会使用命令式语法,打破代码结构和 UI 视觉结构的一致性 ( 代码看起来更像是命令式的而不是声明式的 )

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| Widget build(BuildContext context) { List<SegmentedTabBarItem> items = []; List genders = ["男生", "女生", "不限"]; for (int i = 0; i < genders.length; i++) { items.add(SegmentedTabBarItem( text: genders[i], width: 102, radius: 8, fontWeight: FontWeight.w500, selectedTextColor: Colors.white, duration: Duration(milliseconds: 0), )); } return SegmentedTabBar( tabItemSpacing: 6.5, tabBarRadius: $rem(12), tabIndex: genderIndex, padding: EdgeInsets.symmetric(horizontal: 0), selectedItemBackgroundColor: Colors.purple, duration: Duration(milliseconds: 0), children: items, onSelected: (int index) { setState(() { genderIndex = index; }); }, ); }
|
SegmentedTabBar 在概念和视觉上都应该先于 items 出现。但是由于语法局限,这个空间关系被反了过来。代码看起来更像是命令式而不是声明式。
解决方案:在 Dart 2.3 中加入了针对 UI 编程优化的新语法元素,即可以在集合数据类型的定义中使用 if 和 for 这样的流程控制元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| Widget build(BuildContext context) { return SegmentedTabBar( tabItemSpacing: 6.5, tabBarRadius: $rem(12), tabIndex: genderIndex, padding: EdgeInsets.symmetric(horizontal: 0), selectedItemBackgroundColor: Colors.purple, duration: Duration(milliseconds: 0), children: <SegmentedTabBarItem>[ for (String label in ["男生", "女生", "不限"]) SegmentedTabBarItem( text: label, width: 102, radius: 8, fontWeight: FontWeight.w500, selectedTextColor: Colors.white, duration: Duration(milliseconds: 0), ), ], onSelected: (int index) { setState(() { genderIndex = index; }); }, ); }
|
问题二:多层嵌套之后不容易对 UI 的构成做到一目了然
解决方案:IDE 中加入了 Editor UI Guides

参考资料
前端 Flutter 入门指南 https://mp.weixin.qq.com/s/mgSIu_xcHzU1-Ku218Pjmg
通过与React的简单对比来入门Flutter https://mp.weixin.qq.com/s/KIMqd-Re-XhpSfUf5sSfdQ