Flutter简述
Flutter是一个UI SDK, 可以进行移动端(iOS, Android),Web端, 桌面,它是一个跨平台解决方法。
Flutter的特点:美观,快速,高效,开放。
美观:Flutter内置了美丽的Material Design和 Cupertino widget, 方便开发出美丽的页面。
快速:Flutter的UI渲染性能好,在生产环境下,Flutter将代码编译成机器码执行,并充分利用GPU的图形加速能力,可以实现60FPS。Debug环境下则使用JIM,提升了开发效率。
Flutter引擎使用C++编写,包含了高效的Skia 2D渲染引擎,Dart运行时和文本渲染库。
高效:Hot reload, 在前端不是新鲜的东西,在移动端却并不常见。
开放:Flutter是开放的,它是一个完全开源的项目。
Flutter有一统大前端的野心,并且它正在侵蚀iOS,Andriod这些原生开发。
 
跨平台解决方案历史
第一个阶段:通过webView
iOS端有UIWebView, Android端WebView
最早出现的跨平台框架是基于JavaScript和WebView的,代表框架有PhoneGap, Apache Cordova, Ionic等。
主要是通过Html, Css开发页面。对于调用的一些本地服务如相机,蓝牙等。需要通过JS进行桥接调用Native功能的一些功能代码,本身的性能和体验并不理想。
 
第二阶段:React Native
RN是FaceBook早先开源的JS框架React在原生移动平台的衍生产物,目前支持iOS和安卓两大平台。
RN是使用JS语言,使用类似于HTML的JSX, 以及CSS来做移动开发。
使用原生自带的UI组件实现核心的渲染引擎,从而保证了良好的渲染性能。
但是RN的本质是通过JavaScript VM调用原生接口,通信相对比较低效,并且框架本身不负责渲染,而是间接通过原生进行渲染的。
 
第三个阶段:Flutter
拥有自渲染闭环,是理想的跨平台框架。
安卓原生渲染流程:
1.通过Java语言,调用Android框架提供的framework的API 写出页面布局。
2.页面布局通过Android框架中framework进行翻译,将翻译的结果提交给Skia。
3.Skia给CPU/GPU 提供数据进行渲染。
Flutter渲染流程:
1.通过Dart语言,调用Flutter框架提供的framework的API 写出页面布局。
2.页面布局通过Flutter框架中framework进行翻译,将翻译的结果提交给Skia。
3.Skia给CPU/GPU 提供数据进行渲染。
从上面可以发现,Flutter和安卓的渲染流程是一样的。
RN的渲染流程
1.通过JS, JSX, CSS, Redux等调用React框架提供的API编写页面布局。
2.React框架通过JavaScript VM, Bridge将JS布局转换成原生布局。
3.原生页面布局通过Android框架中framework进行翻译,将翻译的结果提交给Skia。
4.Skia给CPU/GPU 提供数据进行渲染。
RN渲染增加了1,2步骤的转换,造成了性能消耗。所以RN的性能没有Flutter的高。
Flutter不需要依赖原生控件,利用Skia绘图引擎,直接通过CPU,GPU进行绘制。和安卓的原生绘制流程一样。
而像RN框架,必须先通过桥接的方式转成原生调用,然后再进行渲染。存在性能消耗。
 
Flutter绘制原理
1.GPU将VSync绘制信号同步到UI线程。
2.UI线程用Dart将Flutter代码构建图层树Layer Tree。
3.图层树Layer Tree在GPU线程内的Compositor进行合成。
4.Compositor合成的结果交给Skia进行渲染。
5.Skia渲染的结果通过OpenGL或Vulkan交给GPU进行图像绘制。
6.GPU绘制完成后把图像放入到双缓存的Back Buffer,等下一个VSync来时,系统从Back Buffer复制到Frame Buffer并产生新一轮的CPU/GPU绘制过程。
上面是Flutter完整的渲染闭环,这是它和ReactNative的本质区别。
ReactNative是没有自己的渲染闭环的,它是通过JS VM调用系统组件,使用的iOS、安卓的原生渲染。
 
图像的显示原理
在屏幕上看到的任何东西都是图像,包括图片,GIF图像,视频。
当图片连续播放的频率超过16帧时,人眼就会感到非常流畅。当小于16帧时就会感到卡顿。
帧率(fps): Frames Per Second, 每秒生成多少帧图像。
刷新率:显示屏的频率,比如iPhone的屏幕每秒刷新60下,表示为60Hz。
 
帧率和刷新率的关系
GPU/CPU生成图像(每秒生成多少张图片是帧率)放入Buffer中,屏幕从Buffer中取图像,刷新(每秒刷新多少次是刷新率)后显示。这是一个生产者-消费者模型。
很容易产生的问题是:GPU在新的一帧图片写入一半时,屏幕从中取出图像展示。此时会取出一张上半部分和下半部分不一致的图像。
显示出来的图像出现上半部分和下半部分明显偏差的现象,我们称为“tearing”(撕裂)。
 
 
双重缓存和VSync
为了解决“tearing”(撕裂)问题,就出现了双重缓存和VSync。
两个缓存分别为Back Buffer和Frame Buffer, GPU向Back Buffer写数据,屏幕从Frame Buffer读数据。VSync信号负责从Back Buffer到Frame Buffer的复制操作。底层的复制是用“指针交换”的假复制,效率高。
工作流程:
某个时间点,一个屏幕刷新周期完成,VSync信号产生,先完成复制操作,然后通知CPU/GPU绘制一帧图像。
复制操作完成后,开始下一个刷新周期,将刚复制到Frame Buffer的数据显示到屏幕上。
在这种模型下,只有当VSync信号产生时,CPU/GPU才开始绘制。
 
双重缓存存在的问题
双重缓存的缺陷:当CPU/GPU绘制一帧的时间过长(比如超过16ms一个刷新周期时),会产生Jank(画面停顿,甚至空白),VSync信号是在一个刷新周期结束后产生的。
三重缓存
在每次VSync信号来时,多缓存一个Buffer作为备用。
 
渲染引擎skia
skia是Flutter向GPU提供数据的途径。
skia是一个C++编写的开源形库。
目前skia是安卓的官方图像引擎,所以Flutter的安卓应用SDK无需内嵌Skia引擎。
而对于iOS来说,Skia引擎需要嵌入到iOS SDK中,替代了iOS必源的Core Graphics / Core Animation / Core Text, 所以Flutter iOS SDK打包的APP包体积比安卓的大。
因为底层渲染能力的统一,上层开发接口和功能也就是统一的。skia保证了同一套代码调用在iOS和Android上渲染效果是完全一致的。
 
创建一个Flutter项目
命令行创建flutter项目
项目名称不支持中文,不支持大小,可以使用_进行链接
flutter create flutter_demo

VSCode环境安装插件

Flutter,
Dart,
Code Runner

Flutter项目启动方式有三种:冷启动,热启动(hotReload),热重载(hotRestart)。

冷启动:代码和Flutter框架都没有加载和运行,需要从磁盘加载到内存进行运行,过程比较久,通常需要1min-5min。
热启动 hotReload:重新运行widget中的build方法。
热重载 hotRestart:重新运行APP的main入口函数,重新运行一遍程序。
Material是什么
Material是google推出的套设计风格,或者叫设计规范。里面包含了很多设计规范,如:颜色,文字排版,响应动画与过度等。
在Flutter中高度集成Material风格的Widget。
Widget是什么
Flutter中万物皆Widget。在iOS或安卓中,我们的页面有很多种类:应用Application, 视图控制器ViewController, 视图View, Button按钮等。
但是在Flutter中,这些东西都是不同的Widget。
而在我们的APP中,所有能看到的内容几乎都是Widget, 甚至内边距设置都是使用Padding的Widget来做的。
Flutter项目的入口
Flutter项目的入口是lib/main.dart下的main函数。
在main函数内部,需要运行函数runApp(widget app);, runApp函数是Flutter提供的一个全局APP运行函数入口。
runApp(widget app);

最简单的Flutter项目Demo

import 'package:flutter/material.dart';
void main(List<String> args) {
runApp(Text('Hello Flutter'));
}

此时报错:没有找到排版方向

原因是Flutter是面向全世界很多国家的,有的国家排版是从左往右,有的是从右往左。所以需要用户自己设置。
这里需要明确指定排版方向:TextDirection.ltr。
在Flutter中万物都是widget,所以如果要设置center, padding ,margin等都是写对应的widget。
修改报错后,如下:
void main(List<String> args) {
runApp(
Center(
child:Text('Hello Flutter',
textDirection: TextDirection.ltr,
style: TextStyle(
color: Colors.red,
fontSize: 30,
),
)
)
);
}
MaterialApp:采用了Google的Material设计设计规范的Widget,里面默认设置了文字排版方向等设置。
Scaffold:脚手架Widget, 用于快速搭建页面机构,提供了不同位置的命名可选参数。
import 'package:flutter/material.dart';
/*
MaterialApp:采用了Google的Material设计设计规范的Widget,里面默认设置了文字排版方向等设置。
Scaffold:脚手架Widget, 用于快速搭建页面机构,提供了不同位置的命名可选参数。
debugShowCheckedModeBanner: 去掉右上角的debug条
*/
void main(List<String> args) {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
home:Scaffold(
appBar: AppBar(title: Text('第一个Flutter程序'),),
body: Center(
child:Text('Hello Flutter',
style: TextStyle(
color: Colors.blue,
fontSize: 30,
),
)
),
)
)
);
}
StatelessWidget
StatelessWidget:在运行过程中,组件内容是固定的,没有状态修改的。
Widget中没有数据改动,只使用固定的数据展示或者只使用从父Widget继承过来的Widget时,使用StatelessWidget。
继承StatelessWidget产生的子Widget需要重新build方法,并在build方法里返回要展示的widget。
build方法是无法主动调用的。只能在数据改动时系统来调用。
build方法调用时机:
1.当StatelessWidget第一次插入到Widget树时(第一次被创建时)
2.当父Widget发生改变时,子Widget需要被重新构建
3.当依赖的InheritedWidget的数据发送改变时,被重新调用。
StatefulWidget
在运行过程中,状态(data)会产生改变,导致页面展示内容发生改变。
如果想使用StatefulWidget创建有状态变化的Widget, 需要一个State对象一起来实现。
StatefulWidget内部无法写var属性, 因为它继承自Widget,Widget是被@immutable修饰,不可改变。所以它的状态改变要在别的类(State)中实现。
State:在创建的State子类中添加var属性,并将其与Widget状态绑定,当有新的状态改变时,需要调用setState((){})进行更新状态
Flutter的状态更新和React的机制一样,需要调用setState通知框架进行页面更新。
与Vue不同的是Vue实例使用的是双向绑定,内部对属性做了监听,无需手动调用setState进行通知更新。
/*
StatefulWidget内部无法写var属性, 因为它继承自Widget,Widget是被@immutable修饰,不可改变。所以它的状态改变要在别的类(State)中实现。
State:在创建的State子类中添加var属性,并将其与Widget状态绑定,当有新的状态改变时,需要调用setState((){})进行更新状态
Flutter的状态更新和React的机制一样,需要调用setState通知框架进行页面更新。
与Vue不同的是Vue实例使用的是双向绑定,内部对属性做了监听,无需手动调用setState进行通知更新。
*/
class PageContent extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return PageContentState();
}
}
class PageContentState extends State<PageContent> {
var flag = true;
@override
Widget build(BuildContext context) {
return Center(
child:Row(
mainAxisAlignment: MainAxisAlignment.center,
children:[
Checkbox(
value: flag,
onChanged: (value) {
setState(() {
flag = value;
});
},),
Text('Hello World')
]
)
);
} }
声明式编程和命令式编程
iOS,安卓使用的是命令式编程,平时涉及到的是属性,成员变量。
vue, react, flutter是声明式编程,平时涉及到的是State状态,平时开发是只需要管好状态,显示内容有框架自动帮忙更新上去。
Flutter修饰符
@immutable修饰符表示Widget类是不可改变的,里面的属性都是final类型的。
required可选变量 必传修饰符, 用于表示命名可选变量为必传参数。
@immutable
abstract class Widget extends DiagnosticableTree const Checkbox({
Key? key,
required this.value,
this.tristate = false,
required this.onChanged,

Flutter框架渲染流程与使用的更多相关文章

  1. 深入解析Flutter下一代渲染引擎Impeller

    作者 魏国梁:字节 Flutter Infra 工程师, Flutter Member,长期专注 Flutter 引擎技术 袁    欣:字节 Flutter Infra 工程师, 长期关注渲染技术发 ...

  2. cocos2d-x渲染流程

    Cocos2Dx之渲染流程 发表于8个月前(2014-08-08 22:46)   阅读(3762) | 评论(2) 17人收藏此文章, 我要收藏 赞2 如何快速提高你的薪资?-实力拍“跳槽吧兄弟”梦 ...

  3. 【Stage3D学习笔记续】山寨Starling(三):Starling核心渲染流程

    这篇文章我们剔除Starling的Touch事件体系和动画体系,专门来看看Starling中的渲染流程实现,以及其搭建的显示列表结构. 由于Starling是模仿Flash的原生显示列表,所以我们可以 ...

  4. Flutter框架概览

    前言:进入新框架的开发前,有必要整体了解框架设计及特点,对该框架初步认识,此文对Flutter框架进行浅显梳理,以备查阅: Flutter框架   从该架构图可知,Flutter框架可分为Framew ...

  5. WebGL树形结构的模型渲染流程

    今天和大家分享的是webgl渲染树形结构的流程.用过threejs,babylonjs的同学都知道,一个大模型都是由n个子模型拼装而成的,那么如何依次渲染子模型,以及渲染每个子模型在原生webgl中的 ...

  6. vue2源码框架和流程分析

    vue整体框架和主要流程分析 之前对看过比较多关于vue源码的文章,但是对于整体框架和流程还是有些模糊,最后用chrome debug对vue的源码进行查看整理出这篇文章.... 本文对vue的整体框 ...

  7. struts2 框架处理流程

    struts2 框架处理流程 流程图如下: 注意:StrutsPrepareAndExecuteFilter替代了2.1.3以前的FilterDispatcher过滤器,使得在执行Action之前可以 ...

  8. SSH(Struts2+Spring+Hibernate)框架搭建流程<注解的方式创建Bean>

    此篇讲的是MyEclipse9工具提供的支持搭建自加包有代码也是相同:用户登录与注册的例子,表字段只有name,password. SSH,xml方式搭建文章链接地址:http://www.cnblo ...

  9. NGUI渲染流程

    1 渲染流程 NGUI的渲染流程其实就是把Widget组件生成Mesh所需要的缓存数据,然后生成对应的DrallCall组合对应数据,生成渲染需要的Mesh数据,提交渲染. Widget(数据) UI ...

  10. NGUI 渲染流程深入研究 (UIDrawCall UIGeometry UIPanel UIWidget)

    上图是一个简要的NGUI的图形工作流程,UIGeometry被UIWidget实例化之后,通过UIWidget的子类,也就是UISprit,UILabel等,在OnFill()函数里算出所需的Geom ...

随机推荐

  1. 【MySQL】02_子查询与多表查询

    子查询 指一个查询语句嵌套在另一个查询语句内部的查询,这个特性从MySQL 4.1开始引入. SQL 中子查询的使用大大增强了 SELECT 查询的能力,因为很多时候查询需要从结果集中获取数据,或者 ...

  2. 「MySQL高级篇」MySQL之MVCC实现原理&&事务隔离级别的实现

    大家好,我是melo,一名大三后台练习生,死去的MVCC突然开始拷打我! 引言 MVCC,非常顺口的一个词,翻译起来却不是特别顺口:多版本并发控制. 其中多版本是指什么呢?一条记录的多个版本. 并发控 ...

  3. 创建base公共组件

    公共模块 基础模块参照了vant的思路,使用bem命名规范.先创建一个命名空间,这个命名空间返回创建组件函数与生成命名方法.在创建组件函数中创建name与install属性用于注册vue组件 创建组件 ...

  4. 重新整理 .net core 实践篇 ———— linux上排查问题实用工具 [外篇]

    前言 介绍下面几个工具: Lldb createdump dotnet-dump dotnet-gcdump dotnet-symbol Procdump 该文的前置篇为: https://www.c ...

  5. 【炫丽】从0开始做一个WPF+Blazor对话小程序

    大家好,我是沙漠尽头的狼. .NET是免费,跨平台,开源,用于构建所有应用的开发人员平台. 本文演示如何在WPF中使用Blazor开发漂亮的UI,为客户端开发注入新活力. 注 要使WPF支持Blazo ...

  6. Ajax基础(中)

    这节主要在上节的基础上学会如何使用Ajax 源码下载: 链接:https://pan.baidu.com/s/1kG-vACFxneAZqONdo97XrQ 提取码:k21y 在WebStorm中打开 ...

  7. 2022-11-07 Acwing每日一题

    本系列所有题目均为Acwing课的内容,发表博客既是为了学习总结,加深自己的印象,同时也是为了以后回过头来看时,不会感叹虚度光阴罢了,因此如果出现错误,欢迎大家能够指出错误,我会认真改正的.同时也希望 ...

  8. HCIE Routing&Switching之MPLS基础理论

    技术背景 90年代初期,互联网流量快速增长,而由于当时硬件技术的限制,路由器采用最长匹配算法逐跳转发数据包,成为网络数据转发的瓶颈:于是快速路由技术成为当时研究的一个热点:在各种方案中,IETF确定了 ...

  9. MathNet用到的一些功能

    1.计算一元线性函数 Tuple<double, double> myLineTuple = MathNet.Numerics.Fit.Line(myXArray, myYArray); ...

  10. Scanner例题讲解

    Scanner例题讲解 题:输入多个平均数,求其总和与平均数;每输入一个数用回车确认,通过输入非数字来结束输入并输出执行结果  public class Demo05 {     //输入多个平均数, ...