官方介绍:Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面。 Flutter可以与现有的代码一起工作。在全世界,Flutter正在被越来越多的开发者和组织使用,并且Flutter是完全免费、开源的。
从官方介绍可以看到,Flutter有如下特点:
现在越来越多的公司加入了Flutter阵容:阿里巴巴、京东、腾讯、头条....
这里,我们通过官方的一张图来看一下Flutter的架构:
dart:ui
包,它是Flutter引擎暴露的底层UI库,提供动画、手势及绘制能力。dart:ui
库时,调用最终会走到Engine层,然后实现真正的绘制逻辑。它可以以 JIT(即时编译)、JIT Snapshot 或者 AOT(预先编译)的模式运行 Dart代码。更多Flutter的框架介绍,可以参考:https://book.flutterchina.club/chapter1/flutter_intro.html
【总结】:Flutter采用GPU渲染技术,所以性能极高。Flutter编写的应用可以达到120fps(每秒传输帧数),这也就是说,它完全可以胜任游戏的制作。而我们常说的RN的性能只能达到60fps,这也算是Flutter的一个超高竞争力。官方宣称Flutter甚至会超过原生性能。
经过上面的对比,我们来分析一下Flutter的优劣势。
weex
和react native,Flutter直接在两个平台上重写了各自的UIKit,对接到平台底层,减少UI层的多层转换,UI性能可以比肩原生。而Weex和RN,都是基于DOM树来渲染原生组件。
Widget
,例如Row
,Container
,ListView
等Widget
。环境搭建参考 Flutter安装。
方式一:使用命令。
flutter create myapp //创建Flutter工程
flutter devices //查看运行的设备
flutter run //运行应用程序
flutter build ios --debug //iOS debug模式打包
flutter build ios --release //iOS release模式打包(release包不能在模拟器上正常运行)
flutter channel //查看当前channel
flutter channel beta //切换到beta channel
flutter upgrade //升级
方式二:使用Visual Studio Code/Android Studio。这里使用Android Studio进行示例。
打开Android Studio,选择“Start a new Flutter project”:
接下来会进入一个工程类型选择页面:
这里选择“Flutter Application”,继续下一步:
后面直接Finish就可完成工程的创建。创建出来的工程结构如下:
打开main.dart,我们对这里的代码做一个分析:
//导入Material UI组件库,Material是一种标准的移动端和web端的视觉设计语言
import 'package:flutter/material.dart';
//应用入口
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
//build()方法用来描述如何构建UI界面
@override
Widget build(BuildContext context) {
//MaterialApp 是Material库中提供的Flutter APP框架,通过它可以设置应用的名称、主题、语言、首页及路由列表等
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
//MyHomePage 是应用的首页,它继承自StatefulWidget类,表示它是一个有状态的widget
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
//Scaffold 是 Material库中提供的一个widget, 它提供了默认的导航栏、标题和包含主屏幕widget树的body属性
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
使用“flutter run”命令运行之后,会有一段文字提示:
To hot reload changes while running, press "r". To hot restart (and rebuild state), press "R".
An Observatory debugger and profiler on iPhone XR is available at: http://127.0.0.1:53619/
For a more detailed help message, press "h". To detach, press "d"; to quit, press "q".
从上面可以看到,我们可以使用快捷键进行几个操作:
下面我们从几个核心概念,对示例代码做一个解析。
void main() => runApp(MyApp());
上面的代码是Dart语法中特有的简写形式,展开等价于如下代码:
void main() {
return runApp(MyApp());
}
上面的runApp函数,是Flutter框架的入口,可以将给定的组件(widget)显示在屏幕上。
这里,大家可能会问一个问题?如果在main函数中,不使用runApp函数,会怎么样?
不使用runApp函数的话,程序仍会正常运行,但屏幕上什么都不会显示,相当于就是一个Dart控制台程序。
从上面的示例代码可以看到,类MyApp继承自StatelessWidget,类MyHomePage继承自StatefulWidget。
class MyApp extends StatelessWidget {
//...
}
class MyHomePage extends StatefulWidget {
//...
}
class _MyHomePageState extends State<MyHomePage> {
//...
}
那么StatelessWidget和StatefulWidget是什么呢?
查看继承关系,这两者都继承自widget类。StatelessWidget由于不需要维护状态的场景,它通常在build
方法中通过嵌套其它Widget来构建UI,在构建过程中会递归的构建其嵌套的Widget。
从上面的代码可以看到,实现一个StatefulWidget,至少需要两个类:
State类的各个生命周期函数,对于我们使用StatefulWidget很重要,这里介绍一个各个生命周期的作用,具体大家可以写一个StatefulWidget,打印日志,来详细查看调用时机。
initState
:当Widget第一次插入到Widget树时会被调用,对于每一个State对象,Flutter framework只会调用一次该回调,所以,通常在该回调中做一些一次性的操作,如状态初始化、订阅子树的事件通知等。didChangeDependencies()
:当State对象的依赖发生变化时会被调用;例如:在之前build()
中包含了一个InheritedWidget
,然后在之后的build()
中InheritedWidget
发生了变化,那么此时InheritedWidget
的子widget的didChangeDependencies()
回调都会被调用。典型的场景是当系统语言Locale或应用主题改变时,Flutter framework会通知widget调用此回调。build()
:主要是用于构建Widget子树的,会在如下场景被调用:initState()
之后。didUpdateWidget()
之后。setState()
之后。didChangeDependencies()
之后。reassemble()
:此回调是专门为了开发调试而提供的,在热重载(hot reload)时会被调用,此回调在Release模式下永远不会被调用。didUpdateWidget()
:在widget重新构建时,Flutter framework会调用Widget.canUpdate
来检测Widget树中同一位置的新旧节点,然后决定是否需要更新,如果Widget.canUpdate
返回true
则会调用此回调。deactivate()
:当State对象从树中被移除时,会调用此回调。在一些场景下,Flutter framework会将State对象重新插到树中,如包含此State对象的子树在树的一个位置移动到另一个位置时(可以通过GlobalKey来实现)。如果移除后没有重新插入到树中则紧接着会调用dispose()
方法。dispose()
:当State对象从树中被永久移除时调用;通常在此回调中释放资源。实际开发中,我们主要是在initState和build方法中做一些事情。
从上面也可以看到,使用StatefulWidget相对来说,比较复杂,那么有没有其他方式来管理状态呢?这里先留一个悬念,后面在实战系列里做介绍。
在MyApp的build方法中,直接返回了一个MyApp对象:
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
这个MaterialApp是什么呢?
它属于flutter/material.dart包,因此基本上每个flutter程序的代码,第一行代码都会引入这个包。这个包是 Flutter 实现 Material Design设计风格(谷歌推出的一套视觉设计语言)的基础包, 里面有文本输入框( Text)、图标( Icon)、图 片( Image)、行排列布局( Row)、 列排列布局( Column)、 Decoration (装饰器)、动画等组件。
MaterialApp代表使用Material Design设计风格的应用,里面包含了其所需要的基本控件。 一个完整的 Flutter项目就是从 Materia!App这个主组件开始的。该类的常见属性如下所示:
这里先介绍代码中出现的两个重要的属性。
为了在整个应用中使用同一套颜色和字体样式,可以使用“主题”这种方式 。 定义主题有两种方式 : 使用全局主题或使用 Theme来定义应用程序局部的颜色和字体样式。
上面示例代码中,是直接初始化了一个ThemeData对象,并配置了primarySwatch属性。实际上,ThemeData具有的属性很多:
home用于设置应用的主页,也就是整个应用的主组件。这里设置为MyHomePage。
Scaffold 实现了基本的 Material Dsign布局。 只要是在 Material Design中定义过的单个界面显示的布局组件元素,都可以使用 Scaffold 来绘制。 上面实例中,MyHomePage对应状态类的build中,就是用Scaffold来进行页面的布局的:
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
Scaffold的常见属性如下:
在我们实际开发过程中,经常会使用到一些第三方库等,在iOS中,我们通过使用CocoaPods来进行第三方库的管理;安卓中,一般使用Gradle。Flutter使用pubspec.yaml来配置第三方文件的使用,这样可以使得我们快速的应用第三方提供的功能,而不用重复造轮子。
【提醒】:Dart的包仓库地址(https://pub.dartlang.org/)
怎么使用第三方的包呢?
第一步:添加需要的包到pubspec.yaml文件,如下图所示:
第二步:运行指令 “flutter packages get”指令,获取所需要的库到工程中。
第三步:使用。
怎么将Flutter集成到现有App中呢?这个Flutter官方提供了一个解决方案:https://github.com/flutter/flutter/wiki/Add-Flutter-to-existing-apps
这种方式的缺点是,过于依赖本地环境和侵入Native工程,这样会影响到Native的开发,那么该怎么改进呢?这里可以思考两种方案,不过本人还没有在具体的工程中进行实践。
方案一:闲鱼的 FlutterBoost
方案二:组件化架构方案
无善无恶心之体, 有善有恶意之动, 知善知恶是良知, 为善去恶是格物。