1.Flutter是什么?

官方介绍:Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面。 Flutter可以与现有的代码一起工作。在全世界,Flutter正在被越来越多的开发者和组织使用,并且Flutter是完全免费、开源的。

从官方介绍可以看到,Flutter有如下特点:

  • 跨平台:现在Flutter至少可以跨4种平台,甚至支持嵌入式开发。我们常用的有Linux、Android、IOS,甚至可以在谷歌最新的操作系统上Fuchsia进行运行,经过第三方扩展,甚至可以跑在MacOS和Windows上,到目前为止,Flutter算是支持平台最多的框架了,良好的跨平台性,直接带来的好处就是减少开发成本。
  • 原生用户界面: 它是原生的,让我们的体验更好,性能更好。用官方的话讲就是平滑而自然的滑动效果和平台感知,为您的用户带来全新的体验。
  • 开源免费:我们只要学会并使用,这些都是免费的。

现在越来越多的公司加入了Flutter阵容:阿里巴巴、京东、腾讯、头条....

这里,我们通过官方的一张图来看一下Flutter的架构:

  • Flutter Framework:这是一个纯 Dart实现的 SDK,它实现了一套基础库,自底向上, 用于处理动画、绘图和手势等。并且基于绘图封装了一套 UI组件库,细分为两种风格的组件(Material和Cupertino)。
    1. 底下两层(Foundation和Animation、Painting、Gestures)在Google的一些视频中被合并为一个dart UI层,对应的是Flutter中的dart:ui包,它是Flutter引擎暴露的底层UI库,提供动画、手势及绘制能力。
    2. Rendering层,这一层是一个抽象的布局层,它依赖于dart UI层,Rendering层会构建一个UI树,当UI树有变化时,会计算出有变化的部分,然后更新UI树,最终将UI树绘制到屏幕上,这个过程类似于React中的虚拟DOM。Rendering层可以说是Flutter UI框架最核心的部分,它除了确定每个UI元素的位置、大小之外还要进行坐标变换、绘制(调用底层dart:ui)。
    3. Widgets层是Flutter提供的的一套基础组件库,在基础组件库之上,Flutter还提供了 Material 和Cupertino两种视觉风格的组件库。而我们Flutter开发的大多数场景,只是和这两层打交道。
  • Flutter Engine:这是一个纯 C++实现的框架层,包含了 Skia引擎(高性能渲染引擎)、Dart运行环境、文字排版引擎等,在代码调用 dart:ui库时,调用最终会走到Engine层,然后实现真正的绘制逻辑。它可以以 JIT(即时编译)、JIT Snapshot 或者 AOT(预先编译)的模式运行 Dart代码。

更多Flutter的框架介绍,可以参考:https://book.flutterchina.club/chapter1/flutter_intro.html

2.和主流框架的对比

  • Cordova:Cordova基于网页技术进行包装,利用插件的形式开发移动应用,无论是性能还是体验,Flutter都可以完胜Cordova。
  • RN(React Native)/Weex:RN/Weex的效率由于是将View编译成了原生View,所以效率上要比基于Cordova的HTML5高很多,但是它也有效率问题,RN/Weex的渲染机制是基于前端框架的考虑,复杂的UI渲染是需要依赖多个view叠加。比如我们渲染一个复杂的ListView,每一个小的控件,都是一个native的view,然后相互组合叠加。想想此时如果我们的list再需要滑动刷新,会有多少个对象需要渲染。所以也就有了前面所说的RN/Weex的列表方案不友好。
  • Flutter:吸收了前两者的教训之后,在渲染技术上,选择了自己实现(GDI),由于有更好的可控性,使用了新的语言Dart,避免了RN的那种通过桥接器与Javascript通讯导致效率低下的问题,所以在性能方面比RN更高一筹;有经验的开发者可以打开Android手机开发者选项里面的显示边界布局,发现Flutter的布局是一个整体.说明Flutter的渲染没用使用原生控件进行渲染。

【总结】:Flutter采用GPU渲染技术,所以性能极高。Flutter编写的应用可以达到120fps(每秒传输帧数),这也就是说,它完全可以胜任游戏的制作。而我们常说的RN的性能只能达到60fps,这也算是Flutter的一个超高竞争力。官方宣称Flutter甚至会超过原生性能。

经过上面的对比,我们来分析一下Flutter的优劣势。

2.1优势

  • 性能强大,流畅。对比weexreact native,Flutter直接在两个平台上重写了各自的UIKit,对接到平台底层,减少UI层的多层转换,UI性能可以比肩原生。而Weex和RN,都是基于DOM树来渲染原生组件。
  • 灵活、组件库易维护、UI外观保真度和一致性高。由于UI渲染不依赖原生控件,也就不需要根据不同平台的控件单独维护一套组件库,所以代码容易维护。由于组件库是同一套代码、同一个渲染引擎,所以在不同平台,组件显示外观可以做到高保真和高一致性;另外,由于不依赖原生控件,也就不会受原生布局系统的限制,这样布局系统会非常灵活。

2.2不足

  • 不支持热更新。Weex和RN支持动态下发JS来支持热更新。
  • 对原生的基本技能要求。虽然Flutter是跨平台的,但大部分我们的开发,是需要集成到原生中的。全新的Flutter,也需要有原生的基础知识。
  • 开发思维的变换。原生开发中,我们主要基于继承的思路来进行视图的开发,比如说继承UIView,重写UIView的某个生命周期函数,再添加一些方法和属性,来完成一个自定义的View。在Flutter中,我们不能在它的生命周期中修改属性,二是需要嵌套组合几种Widget,例如RowContainerListViewWidget
  • 资源的添加和使用,相对来说比较麻烦(现在可以添加文件夹了:https://flutter.dev/docs/development/ui/assets-and-images)。
  • Apple生态圈。
  • 安装包大小(iOS大了12M左右;安卓大了5M左右)。

3.Flutter生态

4.认识Flutter

环境搭建参考 Flutter安装

4.1创建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:标准的Flutter App工程,包含标准的Dart层与Native平台层;
  • Flutter Module:Flutter组件工程,仅包含Dart层实现,Native平台层子工程为通过Flutter自动生成的隐藏工程;
  • Flutter Plugin:Flutter平台插件工程,包含Dart层与Native平台层的实现;
  • Flutter Package:Flutter纯Dart插件工程,仅包含Dart层的实现,往往定义一些公共Widget。

这里选择“Flutter Application”,继续下一步:

后面直接Finish就可完成工程的创建。创建出来的工程结构如下:

4.2示例代码解析

打开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".

从上面可以看到,我们可以使用快捷键进行几个操作:

  • r 键:点击后热加载,也就是重新加载。
  • p 键:显示网格,这个可以很好的掌握布局情况,工作中很有用。
  • o 键:切换android和ios的预览模式。
  • q 键:退出调试预览模式。

下面我们从几个核心概念,对示例代码做一个解析。

4.2.1程序入口

void main() => runApp(MyApp());

上面的代码是Dart语法中特有的简写形式,展开等价于如下代码:

void main() {
return runApp(MyApp());
}

上面的runApp函数,是Flutter框架的入口,可以将给定的组件(widget)显示在屏幕上。

这里,大家可能会问一个问题?如果在main函数中,不使用runApp函数,会怎么样?

不使用runApp函数的话,程序仍会正常运行,但屏幕上什么都不会显示,相当于就是一个Dart控制台程序。

4.2.2StatelessWidget和StatefulWidget

从上面的示例代码可以看到,类MyApp继承自StatelessWidget,类MyHomePage继承自StatefulWidget。

class MyApp extends StatelessWidget {
//...
} class MyHomePage extends StatefulWidget {
//...
} class _MyHomePageState extends State<MyHomePage> {
//...
}

那么StatelessWidget和StatefulWidget是什么呢?

  • StatefulWidget:有状态组件,持有的状态可能在Widget生命周期中发生变化。例如 CheckboxRadioSliderInkWellForm, and TextField等;
  • StatelessWidget:无状态组件,是不可变的,它的属性不能改变,所有的值都是最终的。 例如Icon、 IconButton, 和Text等。

查看继承关系,这两者都继承自widget类。StatelessWidget由于不需要维护状态的场景,它通常在build方法中通过嵌套其它Widget来构建UI,在构建过程中会递归的构建其嵌套的Widget。

从上面的代码可以看到,实现一个StatefulWidget,至少需要两个类:

  • 一个是StatefulWidget类,这个类里有一个方法createState(),这个方法直接调用了State类,用于创建和Statefulwidget相关的状态。
  • 一个State类,StatefulWidget类本身是不变的,但是State类在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子树的,会在如下场景被调用:
    1. 在调用initState()之后。
    2. 在调用didUpdateWidget()之后。
    3. 在调用setState()之后。
    4. 在调用didChangeDependencies()之后。
    5. 在State对象从树中一个位置移除后(会调用deactivate)又重新插入到树的其它位置之后。
  • 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相对来说,比较复杂,那么有没有其他方式来管理状态呢?这里先留一个悬念,后面在实战系列里做介绍。

4.2.3MaterialApp

在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(主题)

为了在整个应用中使用同一套颜色和字体样式,可以使用“主题”这种方式 。 定义主题有两种方式 : 使用全局主题或使用 Theme来定义应用程序局部的颜色和字体样式。

上面示例代码中,是直接初始化了一个ThemeData对象,并配置了primarySwatch属性。实际上,ThemeData具有的属性很多:

home(主页)

home用于设置应用的主页,也就是整个应用的主组件。这里设置为MyHomePage

4.2.4Scaffold(脚手架组件)

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的常见属性如下:

4.3配置文件

在我们实际开发过程中,经常会使用到一些第三方库等,在iOS中,我们通过使用CocoaPods来进行第三方库的管理;安卓中,一般使用Gradle。Flutter使用pubspec.yaml来配置第三方文件的使用,这样可以使得我们快速的应用第三方提供的功能,而不用重复造轮子。

【提醒】:Dart的包仓库地址(https://pub.dartlang.org/)

怎么使用第三方的包呢?

第一步:添加需要的包到pubspec.yaml文件,如下图所示:

第二步:运行指令 “flutter packages get”指令,获取所需要的库到工程中。

第三步:使用。

5.延伸:现有工程怎么集成Flutter?

怎么将Flutter集成到现有App中呢?这个Flutter官方提供了一个解决方案:https://github.com/flutter/flutter/wiki/Add-Flutter-to-existing-apps

这种方式的缺点是,过于依赖本地环境和侵入Native工程,这样会影响到Native的开发,那么该怎么改进呢?这里可以思考两种方案,不过本人还没有在具体的工程中进行实践。

方案一:闲鱼的 FlutterBoost

方案二:组件化架构方案

6.怎么学习?

【基础篇】:

【实战篇】:

【公司篇】:

7.参考资料

Flutter基础系列之入门(一)的更多相关文章

  1. 2.Perl基础系列之入门

    官网提供的入门链接:http://perldoc.perl.org/perlintro.html 语法概述 Perl的安装步骤省略,直接去官网下载并按照提示安装即可. 如果Perl安装没问题,那么运行 ...

  2. java基础系列--SecurityManager入门(转)

    转载作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/yiwangzhibujian/p/6207212.html 一.文章的目的 这是一篇对Java安全管理器入门的文 ...

  3. Flutter基础系列之混合开发(二)

    1.混合开发的场景 1.1作为独立页面加入 这是以页面级作为独立的模块加入,而不是页面的某个元素. 原生页面可以打开Flutter页面 Flutter页面可以打开原生页面 1.2作为页面的一部分嵌入 ...

  4. Python3基础系列-基本入门语法

    本文简单地介绍了python的一些基本入门知识,通过对这些知识的了解,大家可以写一些简单的代码,同时也为后面深入理解打下基础.本文的主要内容如下: 值和类型 值,即value,通常有:1,2,3.14 ...

  5. javascript基础系列(入门前须知)

    -----------------------小历史---------------------------- javascript与java是两种语言,他们的创作公司不同,JavaScript当时是借 ...

  6. 大数据入门基础系列之Hadoop1.X、Hadoop2.X和Hadoop3.X的多维度区别详解(博主推荐)

    不多说,直接上干货! 在前面的博文里,我已经介绍了 大数据入门基础系列之Linux操作系统简介与选择 大数据入门基础系列之虚拟机的下载.安装详解 大数据入门基础系列之Linux的安装详解 大数据入门基 ...

  7. mybatis基础系列(一)——mybatis入门

    好久不发博客了,写博文的一个好处是能让心静下来,整理下之前学习过的一些知识一起分享,大神路过~ mybatis简介 MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射. ...

  8. .NET 4 并行(多核)编程系列之一入门介绍

    .NET 4 并行(多核)编程系列之一入门介绍 本系列文章将会对.NET 4中的并行编程技术(也称之为多核编程技术)以及应用作全面的介绍. 本篇文章的议题如下:  1. 并行编程和多线程编程的区别.  ...

  9. Google C++测试框架系列:入门

    Google C++测试框架系列:入门 原始链接:V1_6_Primer 注 GTest或者Google Test: Google的C++测试框架. Test Fixtures: 这个词实在找不到对应 ...

随机推荐

  1. 转载-ThreadPoolExecutor里面4种拒绝策略(详细)

    原文链接:https://blog.csdn.net/wjs19930820/article/details/79849050 1 /** * 定义异步任务执行线程池 */ @Configuratio ...

  2. pytest执行用例时从conftest.py抛出ModuleNotFoundError:No module named 'XXX'异常的解决办法

    一.问题描述 在项目根目录下执行整个测试用例,直接从conftest.py模块中抛出了ModuleNotFoundError:No module named 'TestDatas'的异常: 二.解决方 ...

  3. PHP 源码学习 | 变量类型数据结构

    前段时间因为项目需要,研究了一下在 Windows 系统下进行 PHP 扩展的开发,对于 PHP 扩展的开发并不是一件容易的事情(话又说回来了,会者不难,难者不会,关键是自己不会).我当时的需求,主要 ...

  4. PHP JWT token实现

      原文链接:https://www.jb51.net/article/146790.htm   机制:   代码如下:   <?php /**  * PHP实现jwt  */ class Jw ...

  5. Percona XtraDB Cluster简易入门 - 安装篇

    说明 Percona XtraDB Cluster(简称PXC),是由percona公司推出的mysql集群解决方案.特点是每个节点都能进行读写,且都保存全量的数据.也就是说在任何一个节点进行写入操作 ...

  6. java war包 路径--解决war包中文件路径问题

    https://blog.csdn.net/u013409283/article/details/51480948 转自:http://free-chenwei.iteye.com/blog/1507 ...

  7. iota: Golang 中优雅的常量

    阅读约 11 分钟 注:该文作者是 Katrina Owen,原文地址是 iota: Elegant Constants in Golang 有些概念有名字,并且有时候我们关注这些名字,甚至(特别)是 ...

  8. File获取当前目录下的所有子项 listFiles()

    package seday03; import java.io.File; /** * 获取一个目录中的所有子项 * @author xingsir */public class ListFilesD ...

  9. media适配css

    /*引入适配的less*/ html { font-size: 16px; } @media only screen and (min-width: 320px) { html { font-size ...

  10. iOS音频与视频的开发(一)-使用AVAudioPlayer播放音乐、使用AVPlayerViewController播放视频

    iOS的多媒体支持非常强大,它提供了多套支持多媒体的API,无论是音频.视频的播放,还是录制,iOS都提供了多种API支持.借助于这些API的支持,iOS应用既可以查看.播放手机相册中的照片.视频,也 ...