barriers / 阅读 / 详情

Flutter 可滚动组件 之 GridView (十七)

2023-07-23 11:14:11
共1条回复
牛云

GridView可以构建一个二维网格列表

默认构造函数如下:

我们可以看到,GridView和ListView的大多数参数都是相同的,它们的含义也都相同的。我们唯一需要关注的是gridDelegate参数,类型是SliverGridDelegate,它的作用是控制GridView子组件如何排列(layout)。

SliverGridDelegate 是一个抽象类,定义了GridView Layout相关接口,子类需要通过实现它们来实现具体的布局算法。Flutter中提供了两个 SliverGridDelegate 的子类 SliverGridDelegateWithFixedCrossAxisCount 和 SliverGridDelegateWithMaxCrossAxisExtent

SliverGridDelegateWithFixedCrossAxisCount

该子类实现了一个横轴为固定数量子元素的layout算法,其构造函数为:

可以发现,子元素的大小是通过crossAxisCount和childAspectRatio两个参数共同决定的。注意,这里的子元素指的是子组件的最大显示空间,注意确保子组件的实际大小不要超出子元素的空间。

示例

SliverGridDelegateWithMaxCrossAxisExtent

该子类实现了一个横轴子元素为固定最大长度的layout算法,其构造函数为

maxCrossAxisExtent为子元素在横轴上的最大长度,之所以是“最大”长度,是因为横轴方向每个子元素的长度仍然是等分的,举个例子,如果ViewPort的横轴长度是450,那么当maxCrossAxisExtent的值在区间[450/4,450/3)内的话,子元素最终实际长度都为112.5,而childAspectRatio所指的子元素横轴和主轴的长度比为最终的长度比。其它参数和SliverGridDelegateWithFixedCrossAxisCount相同。

示例

GridView.count构造函数内部使用了SliverGridDelegateWithFixedCrossAxisCount,我们通过它可以快速的创建横轴固定数量子元素的GridView

示例

GridView.extent构造函数内部使用了SliverGridDelegateWithMaxCrossAxisExtent,我们通过它可以快速的创建横轴子元素为固定最大长度的的GridView

示例

上面我们介绍的GridView都需要一个widget数组作为其子元素,这些方式都会提前将所有子widget都构建好,所以只适用于子widget数量比较少时,当子widget比较多时,我们可以通过GridView.builder来动态创建子widget。GridView.builder 必须指定的参数有两个:

示例

假设我们需要从一个异步数据源(如网络)分批获取一些Icon,然后用GridView来展示:

_retrieveIcons():在此方法中我们通过Future.delayed来模拟从异步数据源获取数据,每次获取数据需要200毫秒,获取成功后将新数据添加到_icons,然后调用setState重新构建。

在 itemBuilder 中,如果显示到最后一个时,判断是否需要继续获取数据,然后返回一个Icon。

GridView.builder 源码定义如下:

它主要要传两个参数 gridDelegate 和 childrenDelegate ,gridDelegate是SliverGridDelegate类型,SliverGridDelegate它有两个子类,就是我们上文中说的 SliverGridDelegateWithFixedCrossAxisCount 和 SliverGridDelegateWithMaxCrossAxisExtent ,childrenDelegate 是SliverChildDelegate类型,SliverChildDelegate也有两个子类 SliverChildBuilderDelegate 和 SliverChildListDelegate ,一个是通过Builder创建Item,一个是指定所有item。和ListView 很类似

示例

补充知识点:

GridView中的Sliver是SliverGrid

ListView 和 GridView 都是继承于BoxScrollView,BoxScrollView中存在一个抽象方法buildChildLayout,这个buildChildLayout方法是在提供Sliver,GridView中关于buildChildLayout实现如下:

相关推荐

flutter是什么意思,flutter的解释

飘动,拍翅膀
2023-07-23 10:23:302

Flutter开发性能提升之:如何避免Widget重复Build

问题描述: 在Flutter开发的过程中,当我们获取到新的数据或者数据发生变化,需要去执行setState进行页面刷新的时候,经常会出现不必要的子节点Widget也进行了build,但实际上我们是不想让它再次build,出现这些问题的典型情况是在使用FutureBuilder的时候,例如: 在上面这个示例中,如果再次调用Build方法,则会触发httpCall()的方法。 那么怎样才能避免不必要的部件构建呢? 分析: 在Flutter中,Build方法的设计方式是pure/without side effects,书面意思是无副作用的/纯粹的,简单点理解我们可以将其含义看作不会对外部的方法或者变量产生影响的。这是因为许多外部因素能够触发新的小部件的构建,例如这些情况: 但是,这也意味着Build方法可以不去触发httpCall()的方法或者不修改任何状态。 解决 回归问题,当前我们面临的问题是Build方法造成了副作用,也就是造成了无关的Build调用麻烦。 所以,只要我们使Build方法保持纯粹/无副作用,这样就算多少次调用它,也不会对其他Widget的Build方法产生影响。 在上面的示例中,我们将Widget转换为StatefulWidget,然后提取httpCall()到initState中,这样问题就解决了 另外,还可以使一个Widget能够在不强迫其子部件也构建的情况下进行重新构建。 在Widget的实例保持不变时;Flutter会有意识的不去重建子部件。这意味着我们可以缓存Widget树的某些部分,以防止不必要的重新构建。 最简单的方法是使用const修饰构造函数: 由于const的修饰,即使调用了数百次build,DecoratedBox的实例也将保持不变。 或者你可以这样使用以达到相同的结果: 在这个例子中,当StreamBuilder收到新值的通知时,即使StreamBuilder的Column进行了重构,subtree也不会进行重构。这是因为由于闭包,MyWidget的实例没有改变。 这种模式在动画中经常使用。典型的是使用AnimatedBuilder和所有的*Transition时,例如AlignTransition。 我们还可以将subtree存储到类的一个字段中,但是并不推荐你这样做,因为它会破坏Flutter的热重载。
2023-07-23 10:23:501

Flutter浪潮下的音视频研发探索

文/陈炉军 整理/LiveVideoStack大家好,我是阿里巴巴闲鱼事业部的陈炉军,本次分享的主题是Flutter浪潮下的音视频研发探索,主要内容是针对闲鱼APP在当下流行的跨平台框架Flutter的大规模实践,介绍其在音视频领域碰到的一些困难以及解决方案。分享内容主要分为四个方面,首先会对Flutter有一个简单介绍以及选择Flutter作为跨平台框架的原因,其次会介绍Flutter中与音视频关系非常大的外接纹理概念,以及对它做出的一些优化。之后会对闲鱼在音视频实践过程中碰到的一些Flutter问题提出了一些解决方案——TPM音视频框架。最后是闲鱼Flutter多媒体开源组件的介绍。 FlutterFlutter是一个跨平台框架,以往的做法是将音频、视频和网络这些模块都下沉到C++层或者ARM层,在其上封装成一个音视频的SDK,供UI层的PC、iOS和Android调用。 而Flutter做为一个UI层的跨平台框架,顾名思义就是在UI层也实现了一个跨平台开发。可以预想的是未Flutter发展的好的话,会逐渐变为一个从底层到UI层的一个全链路的跨平台开发,技术人员分别负责SDK和UI层的开发。在Flutter之前已经有很多跨平台UI解决方案,那为什么选择Flutter呢? 我们主要考虑性能和跨平台的能力。 以往的跨平台方案比如Weex,ReactNative,Cordova等等因为架构的原因无法满足性能要求,尤其是在音视频这种性能要求几乎苛刻的场景。 而诸如Xamarin等,虽然性能可以和原生App一致,但是大部分逻辑还是需要分平台实现。我们可以看一下,为什么Flutter可以实现高性能: 原生的native组件渲染以IOS为例,苹果的UIKit通过调用平台自己的绘制框架QuaztCore来实现UI的绘制,图形绘制也是调用底层的API,比如OpenGL、Metal等。 而Flutter也是和原生API逻辑一致,也是通过调用底层的绘制框架层SKIA实现UI层。这样相当于Flutter他自己实现了一套UI框架,提供了一种性能超越原生API的跨平台可能性。但是我们说一个框架最终性能怎样,其实取决于设计者和开发者。至于现在到底是一个什么状况: 在闲鱼的实践中,我们发现在正常的开发没有特意的去优化UI代码的情况下,在一些低端机上,Flutter界面的流畅性是比Native界面要好的。 虽然现在闲鱼某些场景下会有卡顿闪退等情况,但是这是一个新事物发展过程中的必然问题,我们相信未来性能肯定不会成为限制Flutter发展的瓶颈的。在闲鱼实践Flutter的过程中,混合栈和音视频是其中比较难解决的两个问题,混合栈是指一个APP在Flutter过程中不可能一口气将所有业务全部重写为Flutter,所以这是一个逐步迭代的过程,这期间原生native界面与Flutter界面共存的状态就称之为混合栈。闲鱼在混合栈上也有一些比较好的输出,例如FlutterBoost。 外接纹理在讲音视频之前需要简要介绍一下外接纹理的概念,我们将它称之为是Flutter和Frame之间的桥梁。Flutter渲染一帧屏幕数据首先要做的是,GPU发出的VC信号在Flutter的UI线程,通过AOT编译的机器码结合当前Dart Runtime,生成Layer Tree UI树,Layer Tree上每一个叶子节点都代表了当前屏幕上所需要渲染的每一个元素,包含了这些元素渲染所需要的内容。将Layer Tree抛给GPU线程,在GPU线程内调用Skia去完成整个UI的渲染过程。Layer Tree中有PictureLayer和TextureLayer两个比较重要的节点。PictureLayer主要负责屏幕图片的渲染,Flutter内部实现了一套图片解码逻辑,在IO线程将图片读取或者从网络上拉取之后,通过解码能够在IO线程上加载出纹理,交给GPU线程将图片渲染到屏幕上。但是由于音视频场景下系统API太过繁多,业务场景过于复杂。Flutter没有一套逻辑去实现跨平台的音视频组件,所以说Flutter提出了一种让第三方开发者来实现音视频组件的方式,而这些音视频组件的视频渲染出口,就是TextureLayer。 在整个Layer Tree渲染的过程中,TextureLayer的数据纹理需要由外部第三方开发者来指定,可以把视频数据和播放器数据送到TextureLayer里,由Flutter将这些数据渲染出来。TextureLayer渲染过程:首先判断Layer是否已经初始化,如果没有就创建一个Texture,然后将Texture Attach到一个SufaceTexture上。 这个SufaceTexture是音视频的native代码可以获取到的对象,通过这个对象创建的Suface,我们可以将视频数据、摄像头数据解码放到Suface中,然后Flutter端通过监听SufaceTexture的数据更新就可以顺利把刚才创建的数据更新到它的纹理中,然后再将纹理交给SKIA渲染到屏幕上。然而我们如果需要用Flutter实现美颜,滤镜,人脸贴图等等功能,就需要将视频数据读取出来,更新到纹理中,再将GPU纹理经过美颜滤镜处理后生成一个处理后的纹理。按Flutter提供的现有能力,必须先将纹理中的数据从GPU读出到CPU中,生成Bitmap后再写入Surface中,这样在Flutter中才能顺利的更新到视频数据,这样做对系统性能的消耗很大。通过对Flutter渲染过程分析,我们知道Flutter底层需要渲染的数据就是GPU纹理,而我们经过美颜滤镜处理完成以后的结果也是GPU纹理,如果可以将它直接交给Flutter渲染,那就可以避免GPU->CPU->GPU这样的无用循环。这样的方法是可行的,但是需要一个条件,就是OpenGL上下文共享。 OpenGL在说上下文之前,得提到一个和上线文息息相关的概念:线程。 Flutter引擎启动后会启动四个线程: 第一个线程是UI线程,这是Flutter自己定义的UI线程,主要负责GPU发出的VSync信号时候用当前Dart编译的机器码和当前运行环境创建出Layer Tree。 还有就是IO线程和GPU线程。和大部分OpenGL处理解决方案中一样,Flutter也采取一个线程责资源加载,一部分负责资源渲染这种思路。 两个线程之间纹理共享有两种方式。一种是EGLImage(IOS是 CVOpenGLESTextureCache)。一种是OpenGL Share Context。Flutter通过Share Context来实现纹理共享,将IO线程的Context和GPU线程的Context进行Share,放到同一个Share Group下面,这样两个线程下资源是互相可见可以共享的。 Platform线程是主线程,Flutter中有一个很奇怪的设定,GPU线程和主线程共用一个Context。并且在主线程也有很多OpenGL 操作。 这样的设计会给音视频开发带来很多问题,后面会详细说。音视频端美颜处理完成的OpenGL纹理能够让Flutter直接使用的条件就是Flutter的上下文需要和平台音视频相关的OpenGL上下文处在一个Share Group下面。 由于Flutter主线程的Context就是GPU的Context,所以在音视频端主线程中有一些OpenGL操作的话,很有可能使Flutter整个OpenGL被破坏掉。所以需要将所有的OpenGL操作都限制在子线程中。 通过上述这两个条件的处理,我们就可以在没有增加GPU消耗的前提下实现美颜和滤镜等等功能。 TPM在经过demo验证之后,我们将这个方案应用到闲鱼音视频组件中,但改造过程中发现了一些问题。 上图是摄像头采集数据转换为纹理的一段代码,其中有两个操作:首先是切进程,将后面的OpenGL操作都切到cameraQueue中。然后是设置一次上下文。然后这种限制条件或者说是潜规则往往在开发过程中容易被忽略的。而这个条件一旦忽略后果就是出现一些莫名其妙的诡异问题极难排查。因此我们就希望能抽象出一套框架,由框架本身实现线程的切换、上下文和模块生命周期等的管理,开发者接入框架以后只需要安心实现自己的算法,而不需要关心这些潜规则还有其他一些重复的逻辑操作。在引入Flutter之前闲鱼的音视频架构与大部分音视频逻辑一样采用分层架构: 1:底层是一些独立模块 2:SDK层是对底层模块的封装 3:最上层是UI层。 引入Flutter之后,通过分析各个模块的使用场景,我们可以得出一个假设或者说是抽象:音视频应用在终端上可以归纳为视频帧解码之后视频数据帧在各个模块之间流动的过程,基于这种假设去做Flutter音视频框架的抽象。 咸鱼Flutter多媒体开源组件整个Flutter音视频框架抽象分为管线和数据的抽象、模块的抽象、线程统一管理和上下文同一管理四部分。管线,其实就是视频帧流动的管道。数据,音视频中涉及到的数据包括纹理、Bit Map以及时间戳等。结合现有的应用场景我们定义了管线流通数据以Texture为主数据,同时可以选择性的添加Bit Map等作为辅助数据。这样的数据定义方式,避免重复的创建和销毁纹理带来的性能开销以及多线程访问纹理带来的一些问题。也满足一些特殊模块对特殊数据的需求。同时也设计了纹理池来管理管线中的纹理数据。模块:如果把管线和数据比喻成血管和血液,那框架音视频的场景就可以比喻成器官,我们根据模块所在管线的位置抽象出采集、处理和输出三个基类。这三个基类里实现了刚才说的线程切换,上下文切换,格式转换等等共同逻辑,各个功能模块通过集成自这些基类,可以避免很多重复劳动。线程:每一个模块初始化的时候,初始化函数就会去线程管理的模块去获取自己的线程,线程管理模块可以决定给初始化函数分配新的线程或者已经分配过其他模块的线程。 这样有三个好处: 一是可以根据需要去决定一个线程可以挂载多少模块,做到线程间的负载均衡。第二,多线程并发式能够保证模块内的OpenGL操作是在当前线程内而不会跑到主线程去,彻底避免Flutter的OpenGL 环境被破坏。第三,多线程并行可以充分利用CPU多核架构,提升处理速度。从Flutter端修改Flutter引擎将Context取出后,根据Context创建上下文的统一管理模块,每一个模块在初始化的时候会获取它的线程,获取之后会调用上下文管理模块获取自己的上下文。这样可以保证每一个模块的上下文都是与Flutter的上下文进行Share的,每个模块之间资源都是共享可见的,Flutter和音视频native之间也是互相共享可见的。基于上述框架如果要实现一个简单的场景,比如画面实时预览和滤镜处理功能, 1:需要选择功能模块,功能模块包括摄像头模块、滤镜处理模块和Flutter画面渲染模块, 2:需要配置模块参数,比如采集分辨率、滤镜参数和前后摄像头设置等, 3:在创建视频管线后使用已配置的参数创建模块 4:最后管线搭载模块,开启管线就可以实现这样简单的功能。上图为整个功能实现的代码和结构图。结合上述音视频框架,闲鱼实现了Flutter多媒体开源组件。 组要包含四个基本组件分别是: 1:视频图像拍摄组件 2:播放器组件 3:视频图像编辑组件 4:相册选择组件 现在这些组件正在走内部开源流程。预计9月份,相册和播放器会实现开源。 后续展望和规划1:实现开头所说的从底层SDK到UI的全链路的跨端开发。目前底层框架层和模块层都是各个平台各自实现,反而是Flutter的UI端进行了跨平台的统一,所以后续会将底层也按照音视频常用做法把逻辑下沉到C++层,尽可能的实现全链路跨平台。 2:第二部分内容为开源共建,闲鱼开源的内容不仅包括拍摄、编辑组件,还包括了很多底层模块,希望有开发者在基于Flutter开发音视频应用时可以充分利用闲鱼开源出的音视频模块能力,搭建APP框架,开发者只要去负责实现特殊需求模块就可以,尽可能的减少重复劳动。
2023-07-23 10:24:261

为什么Flutter开发APP性能最接近原生,前端程序员请关注

Flutter是谷歌公司推出的跨终端的开发框架,支持Android、iOS和WEB终端。1.0版在2018年12月5日发布,目前的最新版本是1.5,它采用的开发语言是Dart,Dart也是谷歌开发的计算机编程语言,语法类似C,是编译型语言: hello world例子,打印字符串“Hello World!”: 1、没有桥接层 React Native、Weex等技术都是跨终端的框架,然而性能跟原生App存在很大差距。这是由于它们的工作原理决定的: React Native、Weex等技术多了一个桥接层,所以界面渲染会慢一些,由于UI渲染非常频繁,想要不卡顿,基本上比较难,性能和用户体验跟原生代码有差距。而这恰恰是Flutter的优势所在: Dart可以被编译成不同平台的本地代码,让Flutter不通过桥接层直接跟平台通信,自然性能会快一些。 2、编译执行 JavaScript是解释执行的,Dart是编译执行的,性能谁好一目了然。 3、Flutter Engine虚拟机 Flutter是依靠Flutter Engine虚拟机在iOS和Android上运行的,Flutter Engine使用C/C++编写,开发人员通过Flutter框架直接和API在内部进行交互,所以具有输入低延迟和UI渲染高帧速率的特点。除了这特点之外,Flutter还提供了自己的小部件,Flutter小部件是使用从React获取灵感的现代框架构建的。 中心思想是您使用小部件构建UI。 窗口小部件根据其当前配置和状态描述了它们的视图。 当窗口小部件的状态发生更改时,窗口小部件会重建其描述,框架将根据前面的描述进行区分,以确定底层呈现树从一个状态转换到下一个状态所需的最小更改。可以直接在OS平台提供的画布上进行描绘,也就是一些核心类库直接放到虚拟机里面,调用起来更快。 从它的系统结构可以看出,类似安卓的ART(Android Run Time)虚拟机,同样采用AOT(Ahead of TIme)技术,会在APP安装时就编译成机器语言,不再解释执行,从而优化了APP运行的性能。 4、自带渲染引擎 Flutter使用谷歌自己的Skia渲染引擎,而Android系统自带Skia引擎,iOS平台上Flutter也会把Skia引擎打包到APP中,从而实现了高效渲染。而React Native通过桥接层访问原生UI,操作频繁就容易出性能问题。 综合所述,Flutter 是性能最接近原生代码 的一种开发框架,未来也会是构建谷歌Fuchsia应用的主要方式,前途不可限量,唯一的问题就是需要学习一门新的语言:Dart,而有Java或者C#语言基础的程序员会比较容易学习。
2023-07-23 10:24:331

Flutter混合开发实战

之前开发了一个纯Flutter的项目,结果接到个新的需求需要使用Flutter单独开一个模块集成到原有的android项目中 下面分享一下如何集成现有的项目和如何继承以及碰到的问题 1.首先第一步 修改gradle 因为 Flutter 当前仅支持为 x86_64,armeabi-v7a 和 arm64-v8a 构建预编(AOT)的库 所以我们需要修改gradle的文件限制 APK 中支持的架构,从而避免 libflutter.so找不到引起的崩溃 2.新建一个FlutterModel的工程2.使用aar文件 因为所有工程统一使用jenkins打包所以我们放在本地肯定是不合适的 说以我们需要 打包aar并上传服务器 上传完成后在android中引用 在开发中遇到的问题 1.关于android和Ios中的跳转传参问题 这个问题在android端还是比较方便的 但是的在Ios端并不怎么好实现 最终决定使用flutter_boost来完成android和Ios与Flutter的通信操作 flutter_boost github地址: https://github.com/alibaba/flutter_boost 集成文档: https://github.com/alibaba/flutter_boost/blob/master/INTEGRATION.md 集成文档给出了 但是没有android的 尴尬 下满分享下android的集成 (1)在flutter的 pubspec.yaml工程中添加 (2)修改android工程 使用本地工程的时候需要在工程共添加 使用aar的时候不需要添加 (3)在android工程中添加对应的条状路由配置 (4)在使用默认的flutter_boost启动界面的时候可能碰到状态栏丢失的情况 所以最好集成BoostFlutterActivity写一个新的activity方便处理状态栏和activity进出动画 (5)跳转并传参 //params 传多个参数可以使用json的形式 2.在flutter中的网络框架使用的dio结果在ios的弹出loading的时候出现卡顿现象 解决方式:1.服务换证书 (但是后台太忙暂时没有支持的人员) 2.ios使用原生的loading解决 3.在使用dio的时候出现ios部分手机 网络请求缓慢问题 解决方法:请求的时候使用http 2.0协议 插件地址: https://github.com/flutterchina/dio/tree/master/plugins/http2_adapter
2023-07-23 10:24:411

Flutter简介

为什么我们要选择flutter语言呢?它有哪些优点呢? *1.flutter将会帮你更容易,更快速的开发出界面美观的移动应用。 *2.是谷歌的亲儿子 *3.支持热重载 :android原生开发会遇到编译-打包-安装三个步骤。开发效率迟迟得不到提升。热重载技术在flutter内完美体现。 *4.支持垮平台:flutter基于图像回执引擎进行渲染,在不同平台下绘制效果绝对是一致的,能做到真正的跨平台,一处写,处处运行。 *5.性能优异性:不同于H5通过DOM渲染和RN映射组件,flutter直接基于native进行绘制。性能上完全超过原生。 *1.Dart语法编译:Dart是一种强类型、跨平台的客户端开发语言。具有专门为客户端优化、高生产力、快速高效、可移植易学的风格。Dart主要由谷歌负责开发和维护。 *2.Flutter插件:Flutter使用的Dart语言无法直接调用iOS系统提供的OC或swift接口,这时就需要使用插件来实现中转。Flutter官方提供了丰富的原生接口封装 Flutter分为三大部分 *1.由Dart语言负责的Framwork层。 *2.Dart语法执行器。 *3.Skia图像处理引擎。05年就被研发成功了(谷歌的全家桶都是由谷歌的Skia图像处理引擎绘制的,iOS目前的图像处理引擎是JPEG,其中Skia是对JPEG的二次封装。) *1.2005年Skia图像处理引擎成立,用来展示Chrome,火狐和其他谷歌自己的产品使用。 *2.2007年第一个安卓系统问世,于是谷歌开发者将Skia移植到安卓平台。 *3.Skia作为一个2D的图像系统,包含绘制,渲染,显示图片都是Skia完成。安卓中的3D部分是由OpenGLES来实现的,其中OpenGL ES是OpenGL的嵌入式版本。
2023-07-23 10:25:001

Flutter面试:渲染原理

页面中的各界面元素(Widget)以树的形式组织,即控件树。Flutter通过控件树中的每个控件创建不同类型的渲染对象,组成渲染对象树。而渲染对象树在Flutter的展示过程分为三个阶段:布局、绘制、合成和渲染。 (一)布局 Flutter采用深度优先机制遍历渲染对象树,决定渲染对象树中各渲染对象在屏幕上的位置和尺寸。在布局过程中,渲染对象树中的每个渲染对象都会接收父对象的布局约束参数,决定自己的大小,然后父对象按照控件逻辑决定各个子对象的位置,完成布局过程。 为了防止因子节点发生变化而导致整个控件树重新布局,Flutter加入了一个机制——布局边界(Relayout Boundary),可以在某些节点自动或手动地设置布局边界,当边界内的任何对象发生重新布局时,不会影响边界外的对象,反之亦然。 二)绘制 布局完成后,渲染对象树中的每个节点都有了明确的尺寸和位置。Flutter会把所有的渲染对象绘制到不同的图层上。与布局过程一样,绘制过程也是深度优先遍历,而且总是先绘制自身,再绘制子节点。 以下图为例:节点1在绘制完自身后,会再绘制节点2,然后绘制它的子节点3、4和5,最后绘制节点6。 可以看到,由于一些其他原因(比如,视图手动合并)导致2的子节点5与它的兄弟节点6处于了同一层,这样会导致当节点2需要重绘的时候,与其无关的节点6也会被重绘,带来性能损耗。 为了解决这一问题,Flutter提出了与布局边界对应的机制——重绘边界(Repaint Boundary)。在重绘边界内,Flutter会强制切换新的图层,这样就可以避免边界内外的互相影响,避免无关内容置于同一图层引起不必要的重绘。 重绘边界的一个典型场景是Scrollview。ScrollView滚动的时候需要刷新视图内容,从而触发内容重绘。而当滚动内容重绘时,一般情况下其他内容是不需要重绘的,这时候重绘边界就派上用场了。 (三)合成和渲染 终端设备的页面越来越复杂,因此Flutter的渲染树层级通常很多,直接交付给渲染引擎进行多图层渲染,可能会出现大量渲染内容的重复绘制,所以还需要先进行一次图层合成,即将所有的图层根据大小、层级、透明度等规则计算出最终的显示效果,将相同的图层归类合并,简化渲染树,提高渲染效率。 合并完成后,Flutter会将几何图层数据交由Skia引擎加工成二维图像数据,最终交由GPU进行渲染,完成界面的展示。 四、总结 咱们从各种业界主流跨端方案与Flutter的对比开始,到Flutter的简要介绍以及Flutter的运行机制,并以界面渲染过程为例,从布局、绘制、合成和渲染三个阶段讲述了Flutter的实现原理。相信大家对Flutter已经有一个整体认知,赶快一起上手操作起来吧!
2023-07-23 10:25:081

Flutter是一个什么框架

Flutter是一个移动应用程序的软件开发工具包(SDK),具有以下特征:跨平台应用的框架,没有使用WebView或者系统平台自带的控件,使用自身的高性能渲染引擎自绘简化版的浏览器,最大限度在android和ios上统一UI,包括业务逻辑和用户体验开发语言使用dart,结合C, C++, 和Skia(2D渲染引擎)构建支持hot reload,包含着完整的控件和工具链一切皆控件,控件是每个Flutter应用程序的基本构建块,与分离视图、控制器、布局和其他属性的框架不同,Flutter具有一致的统一对象模型:控件。一个控件可以定义:结构元素(比如按钮或菜单)、风格元素(比如字体或颜色方案)、布局的方面(比如填充)、一些业务逻辑等组合大于继承,控件本身通常由许多小型、单用途的控件组成,结合起来产生强大的效果,类的层次结构是扁平的,以最大化可能的组合数量强化版的WebView,框架仅提供一个View层,大部分功能要依赖原生目前只能够运行大部分Dart代码(不能引入dart:mirrors或dart:html库)
2023-07-23 10:25:151

flutter框架什么语言?

Flutter是Google使用Dart语言开发的移动应用开发框架,使用一套Dart代码就能快速构建高性能、高保真的ios和Android应用程序,并使用Dart编写了应用程序的所有外观和业务逻辑。Dart具有静态类型检查,而且即将推出安全性,因此应用程序中的每一行代码,无论是描述应用的外观,提供样式,还是控制业务逻辑,都是类型安全的。
2023-07-23 10:25:281

Flutter性能优化

1.圆角对性能的影响 尽量避免用Clipxxx组件,建议用BoxDecoration的image属性实现,如果用Clipxxx组件,圆角取整后性能会提升。 2.减少重绘 根据场景合理使用RePaintBoundary,使绘制独立于父布局,避免重绘,提升性能,但过度使用增加的图层会带来Raster合成的耗时。例如scrollview是滑动过程会导致所有的节点都重绘,可以在scrollview下一层使用RePaintBoundary。 3.滚动步长插值器优化(了解) 官方的滚动差值器在出现小卡顿时,滚动步长会出现大的跳跃,导致体感上出现很明显的抖动,优化步长偏移量算法与原生效果对齐。 4.开启SurfaceView 官方推荐Flutter用SurfaceView ,因为SurfaceView与应用窗口内容分隔开,在专有硬件中合成,产生的中间副本少于TextureView,所以性能高,占用内存少,但是在混合栈遇到的问题需要突破 5.使用RepaintBoundary 提升频繁重绘控件的性能。使用RelayoutBoundary提升频繁修改大小,增删的布局中也可以提升性能。 6.build中不要去写大量的耗时逻辑,因为数据更新会触发build的多次调用,在里面做耗时逻辑会降低性能。 7.尽量使用statelessWidget代替statefulWidget,因为statefulWidget的销毁重建会引起子widget的销毁与重建。 8.解析json可以放到子线程线程中,开Isolate去解析,这样,当返回数据特别大的时候也不会阻塞界面。 9.使用不变的组件的时候可以添加const,const组件不会进行build更新 10.由于flutter通过widget.runtimeType和key来判断是否需要跟新组建,所以我们写组件的时候尽量保持key不变,或者不写key。对于一些需要频繁改变,例如新增、删除、排序的最好加上key。如果type一直,如果不写key容易导致,element无法区分新旧widget,导致无法更新。
2023-07-23 10:25:371

Flutter进阶篇(4)-- Flutter的Future异步详解

本文首发在公众号 Flutter那些事 ,欢迎大家多多关注。 工具安装: Flutter基础篇: Flutter进阶篇: Dart语法基础篇: Dart语法进阶篇: 说明:本文中的所有函数的引用在 main 函数中: 这里的执行结果是: Futue直接new就可以了。我这里没有具体的返回数据,所以就用匿名函数代替了, Future future = new Future(() => null); 相当于 Future<Null> future = new Future(() => null); 泛型如果为null可以省略不写,为了便于维护和管理,开发中建议加上泛型。 输出结果是: future里面有几个函数: then :异步操作逻辑在这里写。 whenComplete :异步完成时的回调。 catchError :捕获异常或者异步出错时的回调。 因为这里面的异步操作过程中没有遇到什么错误,所以catchError回调不会调用。 我们可以看到执行结果是: 我们可以看到输出结果是: 2 1 3 和我们创建Future对象的先后顺序完全一致。 我们可以看到结果为 1 2 3 ,和我们调用then的先后顺序无关。: 当then回调函数里面还有then回调的时候,这时候的流程跟前面就不太一样了,也是一个大坑,也是面试经常会被问到的一个知识点。 我们可以看到执行结果如下: 结果还是一样的: 运行结果是: 这里再次证明了上面我的猜想: 执行顺序和和创建Future的先后顺序有关,如果有多个then嵌套执行,先执行外面的then,然后执行里面的then。 执行结果如下,我们可以看到then内部创建的Future要等到then执行完了,最后再去执行的: 根据上文总结的特点,我们可以不用运行也能推断出输出结果: 为了验证我们的猜想,我们打印一下输出结果,果然我们的证明是正确的。 我们重点看看 then函数的文档说明: then 注册在 Future 完成时调用的回调。 当这个 Future 用一个 value 完成时,将使用该值调用 onValue 回调。 如果 Future 已经完成,则不会立即调用回调,而是将在稍后的 microtask(微任务) 中调度。 如果回调返回 Future ,那么 then 返回的 future 将与 callback 返回的 future 结果相同。 onError 回调必须接受一个参数或两个参数,后者是[StackTrace]。 如果 onError 接受两个参数,则使用错误和堆栈跟踪时调用它,否则仅使用错误对象时候调用它。 onError 回调必须返回一个可用于完成返回的future的值或future,因此它必须是可赋值给 FutureOr <R> 的东西。 返回一个新的 Future ,该 Future 是通过调用 onValue (如果这个Future是通过一个value完成的)或" onError (如果这个Future是通过一个error完成的)的结果完成的。 如果调用的回调抛出异常,返回的 future 将使用抛出的错误和错误的堆栈跟踪完成。在 onError 的情况下,如果抛出的异常与 onError 的错误参数“相同(identical)”,则视为重新抛出,并使用原始堆栈跟踪替代 如果回调返回 Future ,则 then 返回的 Future 将以与回调返回的 Future 相同的结果完成。 如果未给出 onError ,并且后续程序走了刚出现了错误,则错误将直接转发给返回的 Future 。 在大多数情况下,单独使用 catchError 更可读,可能使用 test 参数,而不是在单个 then 调用中同时处理 value 和 error 。 请注意,在添加监听器(listener)之前, future 不会延迟报告错误。如果第一个 then 或 catchError 调用在 future 完成后发生 error ,那么 error 将报告为未处理的错误。
2023-07-23 10:25:431

Flutter基础篇——常用Widget

对于初学flutter的朋友来说,要知道,flutter的UI万物皆Widget。 flutter所写的页面的结构可以被看成套娃,一层套一层,一层套一层,一层套一层。。。。。。 Flutter Widget采用现代响应式框架构建,这是从 React 中获得的灵感,中心思想是用widget构建你的UI。 Widget描述了他们的视图在给定其当前配置和状态时应该看起来像什么。当widget的状态发生变化时,widget会重新构建UI,Flutter会对比前后变化的不同, 以确定底层渲染树从一个状态转换到下一个状态所需的最小更改。 Text : 该 widget 可让创建一个带格式的文本。 Row 、 Column : 这些具有弹性空间的布局类Widget可让您在水平( Row )和垂直( Column )方向上创建灵活的布局。 Stack :取代线性布局 (和Android中的LinearLayout相似),Stack允许子 widget 堆叠, 你可以使用 Positioned 来定位他们相对于 Stack 的上下左右四条边的位置。 Container : Container 可让您创建矩形视觉元素。 您可以为 Container 装饰一个 BoxDecoration , 如 background、一个边框、或者一个阴影。 Container 也可以具有边距(margins)、填充(padding)和应用于其大小的约束(constraints)。另外, Container 可以使用矩阵在三维空间中对其进行变换。 具体的演示见我另外的博客 有一部分Widget都有一个 child 属性,用于容纳唯一的子Widget。 例如:Container、Center、Padding、Align等Widget。 还有一部分Widget允许存在多个子Widget,用 children 作为属性。 例如:Row、Column、Stack等Widget。 在StatefulWidget调用createState之后,框架将新的状态插入树种,然后调用状态对象的initState。子类化State可以重写initState,以完成仅需要一次执行的工作。当然在initState的实现中需要调用super.initState 当一个状态对象不再需要时,框架调用状态对象的dispose。也可以通过覆盖dispose方法来执行清理工作。 OVER~
2023-07-23 10:25:511

flutter如何进行icloud

flutter用一个插件进行icloud。拓展资料:为何flutter构建的App体积较大?细心的开发者会发现flutter构建的App体积比native的大一些,是什么原因造成App体积大呢?其实flutter 在release时App体积和native的大小差不多,而debug时体积通常会大。debug版本体积较大是为了Hot reload和快速编译。如果有flutter开发经验的朋友都体验过,如果您修改一下App的背景颜色,只需save一下就可以立刻看到修改后效果。我称之为“像艺术家一样在创造App”,因此为了实现这些目标,提高开发的效率,debug将占用全部资源。而当我们构建release版时,flutter又会采用AOT策略,提高App运行效率,release版只打包必需的资源,因而体积又会减少。另外,flutter团队也一直在寻找减小程序大小的方法。
2023-07-23 10:26:001

Flutter入门这一篇效率文章就够了

本文面向 Flutter 初学者,旨在用易懂的方式带大家入门。除了 Flutter 代码,还会介绍到语法、原理、特性等基础知识。相信本文能帮助你学习和理解 Flutter。 我们先看一下目前的一些跨平台方案,从前端渲染的角度来分类的话,大致可以分为以下几种方案。 WebView 渲染 这种方案就很好理解,现在很多项目都会嵌入 H5 的页面。就是用 JavaScript 等前端技术进行开发,在客户端上用 WebView 来进行渲染。微信小程序目前使用的就是这种方案。 它的优点很明显,使用成熟的前端技术进行开发,学习成本低,开发效率高,并且支持动态发布代码。 但缺点也很明显,在性能体验上,和原生还是存在较大差距的。 原生控件渲染 既然 WebView 的性能不够好,于是就有了使用原生控件进行渲染的方案。这种方案,同样也是使用 JavaScript 开发,区别是它最终是调用原生控件进行渲染的。这种方案的代表是 Facebook 的 React Native。 由于使用原生控件进行渲染,性能体验也会更接近原生。但也只是更接近,和原生还是有差距的,因为它需要频繁的进行 JavaScript 和原生之间的通信,这个通信效率是比较低的。 另外,由于需要适配各个平台的控件,那就有可能出现,系统控件更新了,而框架本身还没有更新,由此产生了一些问题。换句话说,这种方案是受到原生控件限制的。 绘图引擎渲染 接下来就是主角了。 在前端,如果完全不使用原生控件,我们可以通过系统的绘图 API 绘制出一个用户界面。从这个角度出发,可以在各个平台使用一个统一接口的绘图引擎来进行界面绘制,这个引擎最终调用的是系统的 API 绘制的。这样的话,它的性能可以做到接近原生,并且又不受原生控件的限制,在不同平台上能够做到 UI 统一。 Flutter 就是这样的一个开发框架。 一个跨平台 UI 解决方案 Flutter 是由 Google 开发的,一个跨平台 UI 解决方案。换句话说,它原则上只管 UI 的问题,如果涉及到平台本身的一些功能,比如调用蓝牙、摄像头,一般还是需要原生代码去操作。但现在也会有一些第三方库帮我们解决这些问题。 绘图引擎 Skia Flutter 使用 Skia 作为它的绘图引擎。Skia 已经被 Google 收购,目前很多 Google 旗下的产品都是用 Skia 绘制的,包括 Android。 Android 内置了 Skia,但 iOS 没有,所以在打 iOS 安装包的时候,会把 Skia 一起打进去。这就导致了,用同一份 Flutter 代码打包之后,iOS 的包要比 Android 的包大一些。 开发语言 Dart Flutter 使用的开发语言,叫 Dart。Dart 也是 Google 自家的,它是一门面向对象的语言,从它身上会看到一些其他开发语言的影子。学习起来难度不大的。 前面讲跨平台方案的时候,可以发现别的方案基本都是用 JavaScript 作为开发语言的,但为什么 Flutter 不用?就因为 Dart 是谷歌自家的吗?这个问题先留着,我们后面会提到。 这里部分就简单点带过了,具体的搭建流程可以在官网查看: https://flutter-io.cn/docs/get-started/install 主要的搭建步骤如下: 下载 Flutter SDK 官网下载地址: https://flutter.dev/docs/development/tools/sdk/releases 由于在国内访问可能受限,官方为中国开发者搭建了镜像: https://flutter.dev/community/china 更新环境变量 解压后,将 flutterin 的全路径添加到环境变量 PATH 中。 安装开发工具 理论上,任何文本编辑器都可以用来开发 Flutter 应用,但推荐的开发工具是 Android Studio、IntelliJ 以及 VS Code。因为在这些开发工具上,可以安装官方的 Flutter 和 Dart 插件,得到更好的开发体验。文章里使用 Android Studio 来演示。 如果你打算开发 iOS 应用,则还需要安装 Xcode。 安装插件 在开发工具的插件设置中,安装上面说到的 Flutter 和 Dart 插件。Flutter 插件用于支持 Flutter 的运行、调试、热重载等功能,而 Dart 插件则提供了代码的输入校验、代码补全等功能。 万物始于 Hello World,我们先来创建一个显示 Hello World 的 Flutter 项目。 在 Android Studio 的欢迎页面选择 Start a new Flutter project ,或者通过菜单栏的 File > New > New Flutter Project ,创建一个新的 Flutter 项目。 创建好的项目里面包含了 android 和 ios 两个文件夹,它们是标准的 Android 和 iOS 项目。我们的 Flutter 代码,存放在 lib 文件夹里。项目创建好后,会默认带一个计数器的示例,我们不管它,把 main.dart 的代码改成 Hello World: 启动一个模拟器,或者连上真机,点击 Run 运行一下,就能看这样一个界面了: 具体代码先混个眼熟就好,具体的后面会再讲到。 在写 Flutter 之前,还要先跟大家简单介绍一下 Dart 的语法。如果你有 Java 或 JavaScript 的开发经验,以及面向对象的编程思想,学起来是很快的。 我们可以在 test 文件夹下新建一个 dart 文件,用来写测试代码。 指定类型 var 但和 JavaScript 不同的是,以下代码在 JavaScript 是不会报错的,但在 Dart 里会报错: Object 如果非要上面这样写,那也可以。把 var 换成 Object 就不报错了: 和 Java 类似,Object 是所有对象的根基类。但是这样的话,如果想打印一下 num 的字符串长度,是会报错的: 因为 length 是属于 String 的,但系统只知道 num 是一个对象,并不知道它是一个 String。 dynamic 如果还是非要这样写,那也可以。Dart 有一个特有的关键字 dynamic,把 Object 改成 dynamic 就不报错了: 我们运行一下这个文件,可以在控制台看到正确打印出了字符串长度。 函数 dynamic 在 Dart 里,函数也是可以不写返回类型的,不写的话会被当做 dynamic 来处理。这样的话,函数的类型就是 return 的类型,如果没有 return 则是 void 类型。比如可以这样: 运行之后是能正确打印出字符串长度的。 用于传参 Dart 里的函数也是一个对象,所以可以把函数作为参数来传递,比如: 可选参数 在 Dart 的函数传参里,有一个叫可选参数的概念,我们以文字控件 Text 为例,在源码里可以看到 Text 的构造函数是这样的: 首先,在参数里有一个 data,它是要显示的文字内容,是一个必填项。而 data 后面的一堆参数,是用一个大括号括起来的,这些参数就叫做可选参数,意思是这些参数可传可不传。 假如我们要显示一个比较长的文字,又想限制它最多显示两行,就可以这样来创建一个 Text: 可选参数,在 Flutter 里面用的非常多。 异步 Future 在 Dart 里使用 Future 来处理异步任务,比如我们现在延时一秒打印 666,代码如下: Future 的语法和 Promise 非常像。任务执行成功会调用 then,执行失败会调用 catchError,而无论成功还是失败,都会调用 whenComplete。 async/await 如果你不喜欢上面那种写法,或者是想把异步转成同步,就可以用 async 和 await 这两个关键字来转换。 我们把上面的代码转换一下,写一个 getString 方法,返回的类型是 Future,它会延时返回一个字符串。在 main 函数后面加上 async 关键字,在 getString() 前面加上 await,代码如下: 运行之后可以看到,能正常延时一秒后,把字符串打印出来。这里 getString() 返回的类型是 Future,而 await getString() 则是返回了延时之后返回的字符串。await 要在 async 的函数里面才能使用。 async 和 await 其实是一个语法糖,它最终也是转换成 Future 调用链的形式执行的。 接下来回到 Flutter,Flutter 里最重要的一个概念是 Widget(下面翻译作控件)。 在原生开发里面,我们可能会在界面上区分,这是一个 View,这是一个 Layout,这是一个 View Controller。但在 Flutter 里面,它们全都属于一个统一的模型 Widget。可以说,在 Flutter 界面里,所有东西都是 Widget。 以前学面向对象的时候,我们都听过一句话,叫万物皆对象。我这里套用一下,在 Flutter 里, 万物皆控件 。 具体有哪些控件,我做了一下简单的分类。 根控件 所有的控件都属于 StatefulWidget 或 StatelessWidget 。它们的区别是,StatefulWidget 拥有状态 State ,而 StatelessWidget 没有。 StatefulWidget 当一个控件是可变的时候,就要使用 StatefulWidget 来构建。StatefulWidget 本身不可变,但它持有的状态 State 是可变的。 StatelessWidget 当一个控件状态是固定不可变的时候,就可以使用 StatelessWidget。前面我们写的 Hello World 就是使用 StatelessWidget。 容器控件 容器类控件一般是将某些属性或配置,作用在它的子控件上,比如控件所在的宽高、背景、位置等。 常用的容器控件有 Container、Center、Padding 等。 布局控件 布局控件可以类比作原生开发中的 Layout,通常它会拥有一个 children 的属性,用于接收一个控件数组,对这些控件进行特定的排版。 常用的布局控件有 Row、Column、Stack、Flex 等。 基础控件 基础控件就是常用的文字、按钮、图片等控件。 常用的基础控件有 Text、TextField、Button、Image 等。 功能控件 在 Flutter 里还有一类控件,它们不影响 UI 布局,但带有一些特定的功能,比如页面跳转、事件监听、定义主题等。我们把这一类控件称作功能控件。 常用的功能控件有 Navigator、NotificationListener、Theme 等。 开始写 Flutter 代码了。还记不记得,在 Flutter 项目创建之后,是自带一个计数器 demo 的,现在我们用自己的代码实现一遍。代码修改成如下: 运行之后,就可以看到这样的界面了: 按钮每点击一次,数字就会加一。下面我们来分析一下这段代码,看下里面用到的一些 Widget。 StatefulWidget 由于页面中的数字是跟随状态变化的,所以该页面改用 StatefulWidget。StatefulWidget 并不会直接返回一个 Widget,而是返回状态 State,在 State 里再返回 Widget。 Scaffold Scaffold 是一个标准的 Material Design 页面,它包含了标题栏、浮动按钮、侧滑菜单、底部导航栏等配置。我们这里用到了标题栏 appBar、页面内容 body、浮动按钮 floatingActionButton。 AppBar AppBar 就是标题栏,通过查看控件的构造方法,我们可以知道它可配置的属性。 AppBar 的可选参数除了标题 title,还可以配置标题前的内容 leading,右侧的操作按钮 anctions,控件垂直高度 elevation 等。我们只传了 title,其他属性都用默认值。 Center Center 是一个容器类控件,它的作用就是让它的子控件居中显示。 FloatingActionButton 熟悉安卓开发的应该对这个控件比较熟悉,它就是页面右下角一个特定样式的 Button,参数里面的 onPressed 是一个必填项,要传一个点击之后的回调函数。 根据这个例子,下面给大家介绍一下 Flutter 两个比较重要的特性。 点击 Button 之后,我们把 num 变量加一,并使用 setState 通知状态发生了改变,Flutter 会根据新的状态更新 UI。如果有接触过小程序开发,setState 就和小程序的 setData 类似。 在 Flutter 里面我们不需要用 set 方法来更新 UI,可变控件是和状态绑定的,这就是 Flutter 的响应式 UI 编程。 在 Android Q 和 iOS 13 里都加入了暗黑模式,我们也换一个暗黑主题来玩一下。MaterialApp 里有一个 theme 的属性,我们把它配置一下: 这次改完之后不点 Run 了,我们点一下闪电图标 Flutter Hot Reload ,就能看到界面发生了变化: 这就是 Flutter 的 热重载 ,在修改完代码之后,通过热重载就能马上在设备上看到修改结果,可以很大程度上增加开发效率。 下面再给大家介绍几个 Flutter 里的常见操作。 在 Flutter 里,使用 Navigator 来管理页面跳转,比如要跳转到一个 NewPage 可以这样写: 进栈使用 push,出栈则是 pop。 使用 MaterialPageRoute 会模拟出 Android 上页面跳转的过场效果。 我们来看看怎么显示一张本地图片。 先在根目录新建一个存放图片的文件夹,比如叫 images,把图片 picture.png 放进去。 找到根目录下的 pubspec.yaml 文件,这个便是 Flutter 依赖配置文件,我们需要在这里配置一下刚才的图片: 这样,我们就能使用 Image 控件把这张图片显示出来了: 和 node 的 npm 以及 Android 的 jcenter 类似,Flutter 也拥有一个公共仓库 pub.dev。pub.dev 是 Google 官方的 Dart 仓库,在上面可以找到我们需要的包和插件。 Flutter 本身没有 Toast,我们来接入一个。在 pub.dev 上搜索后,我决定使用 fluttertoast: 按照说明,在 pubspec.yaml 文件里的 dependencies 下配置: 点一下 Android Studio 右上角的 Packages get 同步之后就可以使用了: 我们上面使用的都是 Material Design 的控件,它们都是在 flutter/material.dart 包里面的。如果要使用 iOS 风格的控件,则要用到 flutter/cupertino.dart 包: iOS 风格的控件,基本都以 Cupertino 开头。我们把计时器页面里的控件替换一下: 效果如下: 代码的部分就到这里了,接下来跟大家聊一下编译方式,编程语言的编译方式有两种。 关于它们孰优孰劣,就要看从哪个角度去对比了。JIT 的话,它的一大特点就是支持动态发布代码,也就是支持热更新。但要是从性能的角度考虑,AOT 会更好,因为在运行的时候不用再进行编译的操作的,运行的效率会更高一些。 回到我们一开始的时候留下的问题,为什么别的跨平台方案都是用 JavaScript,而 Flutter 要用 Dart 来开发。JavaScript 的编译方式是 JIT 的,它不支持 AOT。而 Dart 同时支持 JIT 和 AOT。 Flutter 在开发阶段使用 JIT,让我们用上了热重载,增加了开发效率。在打包时改用 AOT,保证了正式版应用的性能。 最后讲一下大家比较关心的一个东西,Flutter 是否支持热更新?前面说到 Dart 支持 JIT,所以从技术层面它是支持的。但是目前是不支持的,在官方的计划文档中,可以看到: 至于原因,官方在这里进行了说明。总的来说,是由于政策的限制,以及出于对性能和安全性的考虑,暂时不支持了。 到这就结束啦。由于想把 Flutter 基础在一篇内讲完,没有涉及太多细节,如果要写 Flutter 代码还需要深入学习。但相信理解之后再学,会轻松很多。
2023-07-23 10:26:091

Flutter中InheritedWidget的使用

在Tree中从上往下高效传递数据的基类widget , 定义为:abstract class InheritedWidget extends ProxyWidget Flutter的响应式开发与React类似,数据都是自顶向下的。 假设有祖先组点A,中间经过结点B, C,然后到结点D,D需要从A中获取数据f,那按照自顶向下数据流转,f需要依次传递给B及C,最后才到C。这样开发极为不灵活,成本也比较高。所有Flutter需要有跨结点(只能是祖先后代节点,不能跨兄弟节点)高效传递数据的方案。 大体意思如下: InheritedWidget 是在树中高效向下传递信息的基类部件; 调用[BuildContext.inheritFromWidgetOfExactType]方法可以从 BuildContext 中获取到最近的 InheritedWidget 类型的实例; 在 InheritedWidget 类型的控件被引用,也就是调用过 inheritFromWidgetOfExactType 方法后,当 InheritedWidget 自身状态改变时,会导致引用了 InheritedWidget 类型的子控件重构(rebuild)。 这里随便定义一个人 Person 类。 创建一个类继承 InheritedWidget,并实现 updateShouldNotify 方法。 之前说到调用[BuildContext.inheritFromWidgetOfExactType]方法可以从 BuildContext 中获取到最近的 InheritedWidget 类型的实例,所以此处定义一个静态的 of 方法,通过传入的 context 获取到最近的 InheriedDataWidget 实例。 1.定义数据模型 这里随便定义一个 Person 类。 2.自定义 InheritedWidget 控件类 创建一个类继承 InheritedWidget,并实现 updateShouldNotify 方法。 之前说到调用[BuildContext.inheritFromWidgetOfExactType]方法可以从 BuildContext 中获取到最近的 InheritedWidget 类型的实例,所以此处定义一个静态的 of 方法,通过传入的 context 获取到最近的 InheriedDataWidget 实例。 3.InheriedDataWidget 的使用 InheriedDataWidget 使用起来也很简单,它本身也是一个控件,只要在任意一个页面的子控件调用其构造方法就行,这里我们定义一个形如的 Widget 树。 WidgetA 是一个 StatefulWidget 类型的控件,可以调用 setState 刷新,如果是继承人 Stateless 类型的控件,那我们也可以通过 Stream 或者其他方式刷新数据,感兴趣的请看[什么是 Stream? Dart WidgetA1_1 类 WidgetA1_2 类 WidgetA1_3 类 当我们点击 floatingActionButton 的时候,WidgetA1, WidgetA1_1, WidgetA1_2 的控件都会更新 Person 的信息,而且每点 floatingActionButton 一次, 当我们点击 floatingActionButton 的时候,WidgetA1, WidgetA1_1, WidgetA1_2 的控件都会更新 Person 的信息,而且每点 floatingActionButton 一次,都会输出: 如果我们试图在和 WidgetA 的同一层级的兄弟节点去访问 InheriedDataWidget 的 Person 数据,是不行的,因为父节点中并没有插入 InheriedDataWidget。 把 WidgetB 和 WidgetA 保持同一节点 这也体现了 Inheried(遗传) 这一单词的特性,遗传只存在于父子。兄弟不存在遗传的关系。 这种数据共享的方式在某些场景还是很有用的,就比如说全局主题,字体大小,字体颜色的变更,只要在 App 根层级共享出这些配置数据,然后在触发数据改变之后,所有引用到这些共享数据的地方都会刷新,这换主题,字体是不是就很轻松,事实上 Theme.of(context).primaryColor 之流就是这么干的。 以上就是有关InheritedWidget的使用。 自己也是从事Android开发5年有余了;整理了一些Android开发技术核心笔记和面经题纲,有关更多Android开发进阶技术资料、面经题纲、核心技术笔记; 想要进阶自己、拿高薪的同学请私信我回复“核心笔记”或“面试”领取!
2023-07-23 10:26:161

flutter与flatter用法的区别

flutter是拍翅,振翼的意思。flatter是奉承的意思。
2023-07-23 10:26:381

Flutter与原生通信概述

flutter与原生通信主要有三种方式:MethodChannel、EventChannel、BasicMessageChannel,这三种方式均各有适用的场景:MethodChannel用于native与flutter的方法调用,EventChannel用于native单向的向flutter发送广播消息,BasicMessageChannel用于native与flutter之间的消息互发。 MethodChannel用于双方之间的方法互调,使用步骤是: 1.创建一个MethodChannel对象,传入MethodChannel名称。 2.使用setMethodHandle对对方调用自己的方法进行监听,通过回调中的MethodCall对象方法名判断、获取方法参数,并且返回调用结果。 3.使用invokeMethod来调用对方的方法,可传入方法名,方法参数,以及监听对方的回调结果。 以下是示例: 需要注意的是,MethodChannel的名称需要双方保持一致,否则就不是同一个MethodChannel了。另外这里的方法调用并不是像Java里面反射那样去先找到class示例对象再解析到相应的方法,而是将双方互发的消息包装成了MethodCall对象,拿到这个对象后通过MethodCall里面的方法名去判断要做什么操作,并不是直接就调用了自身(native或flutter)相对应的方法。具体要做什么操作、调用什么方法还是得自己去调用和实现。 EventChannel适用于native向flutter发送广播消息,只是单向的消息发送,native发,flutter收,返过来flutter并不能向native发送消息。例如native可将定位数据不断的报给flutter,或者录像数据等等,所有基于原生能力产生的数据都可以通过EventChannel进行发送。 步骤: 1.创建一个EventChannel对象,传入EventChannel名称。 2.flutter端调用receiveBroadcastStream进行广播消息注册,传入arguments参数即为广播名称,此参数是告诉native端你要接受的广播类型,判别是什么广播发送的数据。 2.native调用setStreamHandler方法进行广播消息监听,onListen回调里会有一个arguments参数,这里及为flutter注册的广播类型,若flutter端没有注册,则native端不会收到这个回调,也就无法进行消息发送。收到flutter端的广播注册后,根据arguments可判断广播类型,然后根据EventChannel.EventSink来进行消息发送,EventSink.success()即可将消息发送给flutter端。 3.flutter进行广播注册会返回一个streamSubscription类型的对象,该对象可以进行消息的停止,native可在onCancel回调里面收到。 示例如下: BasicMessageChannel就是比较常用的消息互发,使用步骤如下: 1.创建BasicMessageChannel对象,传入BasicMessageChannel名称。还需传入编解码方式(可以自己实现),系统提供了一些列的编解码方式,后续会介绍到。 2.使用setMessageHandler方法进行消息监听,也可进行回复。 3.使用send方法进行消息发送。 无论哪种方式的消息传递,最终都是将自定义数据转化为二进制数据进行传递,flutter提供的编解码方式分为MethodCodec和MessageCodec两种,EventChannel和MethodChannel使用的就是MethodCodec,BasicMessageChannel使用的是MessageCodec。MethodCodec其实就是在MessageCodec的基础上将数据包装了一下,使其转化为MethodCall对象方便使用。 MethodCodec源码: MethodCodec提供了两种方式:JSONMethodCodec和StandardMethodCodec,前一种就是JSON和MethodCall对象之间的互转,后一种则是根据传入的数据基本类型(String,Integer等)来进行互转。 MessageCodec则提供了四种方式,如下图,具体就不详细讲述了,看看名字就知道是怎么回事,可以直接去看源码。最常用和默认的就是StandardMessageCodec方式。 从上面的使用方式可以看出,每一种Channel在创建的时候都需要传递一个BinaryMessenger,这个接口可以在FlutterEngine里面拿到,因此需要在FlutterActivity里面实现configFlutterEngine方法里面重写这个方法。FlutterActivity在attach FlutterEngine之后就会调用这个configFlutterEngine方法,通过flutterEngine.getPlugins().add(FlutterPlugin)方法可以FlutterPlugin的回调方法里进行数据的初始化和销毁工作。如下图 这个回调方法里的FlutterPluginBinding提供了一些我们可能会用到的对象,如下:
2023-07-23 10:26:451

Flutter之国际化多语言

在说flutter国际化前,不得不提到,在uni-app中支持的Vue-i18n,两者有相似之处,也有差异的地方。 本篇借鉴了三篇热门帖子 Flutter中的国际化:如何写一个多语言的App Flutter国际化完整例子 Internationalization - Make an Flutter application multi-lingual 只记录根据手机系统语言自动转换app语言 引入后,保存会自动加入安装此依赖 我们新建一个和"/lib"同级别的文件夹"/locale",然后在这个文件夹中新建两个文件,分别为"i18n_en.json" 和" i18n_zh.json"。再在"/lib"文件夹下创建和"main.dart"同级的"translation.dart"和"application.dart"。 u2003u2003文件夹树现在是这个样子的: MyApplication u2003 | u2003 +- android u2003 +- build u2003 +- images u2003 +- ios u2003 +- lib u2003u2003 | u2003u2003 +-main.dart u2003u2003 +-translation.dart u2003u2003 +-application.dart u2003 +- locale u2003u2003 | u2003u2003 +- i18n_en.json u2003u2003 +- i18n_zh.json u2003 +- test 在pubspec.yaml继续加入json,引入静态资源 补充:如果需要强制转换的话(我自己没有用到)
2023-07-23 10:26:531

Flutter开发--Pub包管理

在原生开发中, Android 使用 Gradle 来管理依赖, iOS 用 Cocoapods 来管理依赖,Node 中通过 npm来管理依赖。 Flutter 使用配置文件 pubspec.yaml (位于项目根目录)来管理第三方依赖包。 Pub 是Google官方的Dart Packages仓库,类似于node中的npm仓库,android中的jcenter,我们可以在上面查找我们需要的包和插件,也可以向pub发布我们的包和插件。 Pub工具 包含管理Package、部署Package和部署命令行应用的命令。 如果使用的是Flutter SDK,不要直接使用pub命令。而是使用flutter pub命令,如下: 命令pub get/upgrade/outdated 属于管理Package的依赖关系 用于检索当前 Package 所依赖的其它 Package。如果 pubspec.lock 文件已经存在,则根据该文件中保存的依赖项版本获取对应的依赖项。如有必要,将会创建或更新该文件。 更新 package 依赖 当你添加一个 package 后首次运行 flutter pub get, Flutter 将会保存在 pubspec.lock lockfile 中找到的具体 package 版本。这将确保当你或者团队中其他开发者运行 flutter pub get 后能得到相同版本的 package。 如果你想升级到 package 的最新版本,比如使用 package 的最新特性,请运行 flutter pub upgrade 。这将检索你在 pubspec.yaml 文件中指定的版本约束所允许的最高可用版本。 案例 在flutter项目中导入hive包,在pubspec.yaml文件中添加配置: 执行flutter pub get,可以在 pubspec.lock 中看到 hive 版本是2.1.0,这是因为目前hive的最新版本是2.1.0,配置“^”表示向最新版本兼容,具体可查看Package版本管理( https://dart.cn/tools/pub/versioning ),所以再执行flutter pub upgrade 可以看到版本还是2.1.0,这个时候会发现pub get和 pub upgrade 效果一样。 但是未来如果 hive 发布了2.2.0版本,这个时候使用flutter pub get在pubspec.lock中看到hive版本依旧是2.1.0,而执行flutter pub upgrade 后在pubspec.lock中看到hive版本就是2.2.0。 现在先在flutter 项目的pubspec.yaml文件添加配置,指定hive版本是2.0.5,如下: 这个时候执行flutter pub get后,可以在pubspec.lock的文件中看到hive版本是2.0.5,如果这个时候更改配置为 hive: ^2.0.5,再执行flutter pub get就会发现在pubspec.lock的文件中看到hive版本还是2.0.5,这个时候可以执行flutter pub outdated查看依赖的每个 package,如下图, 可以看到,Upgrable项hive版本号为2.1.0,执行flutter pub upgrade 后可以看到在pubspec.lock的文件中看到hive版本是2.1.0 在pubspec.yaml文件添加配置: lxx_package_demo信息如下图: 执行flutter pub get后在pubspec.lock中看到flutter_log版本是0.0.1 现在修改lxx_package_demo版本号为0.0.2,再执行flutter pub get 会发现版本会及时更新为0.0.2,这个时候执行flutter pub get/upgrade效果一样 参考文档: https://blog.csdn.net/Nathan1987_/article/details/90212896 https://www.cnblogs.com/lulushen/p/14150544.html
2023-07-23 10:27:161

Flutter初探--常用依赖包

国外地址: https://pub.dev 国内镜像: https://pub.flutter-io.cn 以 flutter_screenutil 为例路由框架 annotation_route 状态管理 provider UI适配 flutter_screenutil 刷新控件 flutter_easyrefresh 网络请求 dio toast控件 fluttertoast 图表库 charts_flutter 网络监听 connectivity 事件总线 event_bus 日历组件 table_calendar 官方webview webview_flutter 第三方webview flutter_webview_plugin 该篇文章为常用依赖包总结,用来记录所需要的常用依赖包,后续会不断扩充内容~
2023-07-23 10:27:351

Flutter动画性能, 官方flutter基础动画在真机上能跑到20-30%CPU

这是他提的 : https://github.com/flutter/flutter/issues/102020 用的是这个官方动画效果 ( https://api.flutter.dev/flutter/widgets/ScaleTransition-class.html ) 运行起来的效果 如下:就是在一个Column 中放置了3个的动画 目前测试App在前台,运行中的CPU的情况 打开App的时候 CPU的使用率 ,当App在做网络请求的时候,占用率会更加的高 这是打开百度翻译的APP CPU占有率 记不记得这个图片,电脑的CPU使用率,如果它的占用大于了60%,你就会发现电脑的风扇在拼命的转,而且电脑会运行过慢 但是手机好像没有像电脑那么严重,使用起来也没有那么卡,这个和手机的固件设计有关系 这是另外一个小伙伴的公司的App内存的占用情况 CPU使用率是性能测试是一项重要指标,CPU占用过高会使得设备运行程序出现卡顿与发热,甚至出现应用程序Crash,影响用户体验。在排除硬件环境的限制下,应用程序应该尽可能少的占用CPU。 一个Demo,3个动画的CPU使用率达到了80%,如果用java or kotlin 去实现应该不会有那么高的占有率,所以Flutter的还需要继续的优化。 (App性能测试—CPU使用率): https://cloud.tencent.com/developer/article/1858070
2023-07-23 10:27:491

Flutter开发--视频播放器

目前Flutter平台主流的两个播放器是video_player和fijkplayer pub github 1、Flutter平台官方插件,作者是国外的,有问题沟通比较困难,只能通过提交issue 2、硬解码 4、UI封装: better_player 基于video_player和Chewie的高级视频播放器。它解决了许多典型的用例,并且易于运行。 5、播放器宽高比例与视频内容宽高比例不一致时,会出现图像压缩变形的问题 6、调用原生内核播放器:iOS--AVPlayer, Android--ExoPlayer 7、对于分段源 m3u8 的播放不友好,如果一个切片播放超时,会导致整个播放都失败 8、better_player可以缓存视频,但不能自定义缓存的地址,只能指定key,和缓存的最大内存量(还未研究超出最大的话是不能缓存新的,还是删除最旧的) 9、better_player不能完全自定义UI,只能修改类中的一些开放属性,比如说icon图标,文字颜色啥的 10、无网络有缓存时,封面可以正常展示 11、better_player播放失败有手动retry的设计 pub github 1、fijkplayer 是一个 Flutter 生态的媒体播放器,是对 ijkplayer 的 Flutter 封装,支持 Android 和 iOS。 fijkplayer 使用 ijkplayer 作为播放器内核,ijkplayer 使用 ffmpeg 进行音视频解封装和解码,同时添加了 Android 和 iOS 平台特有的硬件加速解码能力。 2 、国内有QQ群,但是活跃度也是不高。 3、可以缓存视频,可以自定义缓存的地址,方便后续的内存维护。 4、可以通过FijkPanelWidgetBuilder较大程度上自定义UI。 5、无网络有缓存视频时,无法展示封面,因为内部是通过imageProvider去加载网络图片的。 7、播放失败无手动retry的设计 1、两种播放器都是通过外接纹理方案 (Texture),将播放器视频画面渲染接入 flutter 中,性能上优于 PlatformView 的接入方法。 如何自己实现? 下面以video_palyer的iOS源码部分解释: iOS用CVPixelBufferRef将渲染出来的数据存在内存中,Flutter engine会将Texture的数据在内存中直接进行映射无需通过Channel传输,然后Texture Widget就可以把你提供的这些数据显示出来。在我们传输数据的时候会需要将其与 TextureID 绑定,绑定的过程通过BasicMessageChannel实现数据流的传输,以做到实时展示的效果
2023-07-23 10:28:041

Flutter 升级空安全攻略

1、升级依赖的插件版本pubspec.yaml(包括example),pub get 解决依赖冲突 2、pubspec.yaml所在路径下执行 dart pub upgrade --null-safety 检查是否所在flutter工程依赖库是否都升级到了空安全版本 example示例需要进入example路径下检查1、List默认构造方法删除,改用[]; main.dart文件main方法第一行增加CustomFlutterBinding(); 2、flutter clean,删除所有 pubspec.lock文件 ,pub get 3、FutureOr报错引入头文件、import "dart:async"; 4、属性用优先用late 或者 ?声明,在确定不为空情况才用!
2023-07-23 10:28:111

Flutter入门(二)——实现一个简单的demo页面

首先查看入口函数: 类MyApp: MyHomePage: state: build: 此demo页面涉及到两个组件:图片和icon。在这里做一个简单的介绍,更详细的学习请参考flutter官网和相关书籍 在flutter中,我们可以通过Image组件来加载并显示图片,Image的数据源可以是asset、文件、内存以及网络。 ImageProvider 是一个抽象类,主要定义了图片数据获取的接口 load() ,从不同的数据源获取图片需要实现不同的 ImageProvider ,如 AssetImage 是实现了从Asset中加载图片的ImageProvider,而 NetworkImage 实现了从网络加载图片的ImageProvider。 u200b Image也提供了一个快捷的构造函数 Image.asset 用于从asset中加载、显示图片: Image也提供了一个快捷的构造函数 Image.network 用于从网络加载、显示图片: Flutter中,可以像web开发一样使用iconfont,iconfont也即"字体图标",它是将图标做成字体文件,然后通过指定不同的字符而显示不同的图片。 加号为图片组件,减一为icon组件。点击加号,数字加1;点击-1,数字减少1。
2023-07-23 10:28:181

Flutter项目插件整理

#弹窗 oktoast : ^3.1.5 #路由 get : ^4.5.1 #百度地图定位 flutter_bmflocation : ^2.0.0-nullsafety.1 #百度地图-基础地图 flutter_baidu_mapapi_map : ^3.0.0+2 #百度地图-检索 flutter_baidu_mapapi_search : ^3.0.0 #百度地图-计算工具 flutter_baidu_mapapi_utils : ^3.0.0 #屏幕自动适应 flutter_screenutil : ^5.2.0 #Banner图切换 flutter_swiper_plus : ^2.0.4 #网络请求 dio : ^4.0.4 dio_cache_interceptor : ^3.2.2 pretty_dio_logger : ^1.2.0-beta-1 #城市选择器 azlistview : ^2.0.0 #本地存储 get_storage : ^2.0.3 #权限 permission_handler : ^8.3.0 #保存图片 image_gallery_saver : ^1.7.1 # image_save: ^5.0.0 #常用工具类 common_utils : path : plugin/common_utils-2.0.2 #选择器 flutter_picker : ^2.0.2 #生成二维码 qr_flutter : ^4.0.0 #验证码输入框 pin_input_text_field : ^4.1.1 # 汉字转拼音 lpinyin : ^2.0.3 #多张图片上传 wechat_assets_picker : ^6.3.1 wechat_camera_picker : ^2.6.3 #裁剪图片 image_cropper : ^1.5.0 #图片压缩 flutter_luban : ^0.1.13 #家谱树 graphview : ^1.1.1 vector_math : ^2.1.0 #行为验证码 steel_crypt : ^3.0.0+1 encrypt : ^5.0.0 #二维码识别 flutter_qr_reader : ^1.0.5 #右上角小图标 badges : ^2.0.2 #唤醒系统应用 url_launcher : ^6.0.17 flutter_sms : ^2.3.2 #QQ分享 tencent_kit : ^2.1.0 flutter_cache_manager : ^3.3.0 #微信SDK fluwx : ^3.6.1+4 #支付宝SDK tobias : path : plugin/tobias-2.2.0 #个推 getuiflut : ^0.2.11 #极光推送 # jpush_flutter: # path: plugin/jpush_flutter-2.2.2 #极光魔链 jmlink_flutter_plugin : path : plugin/jmlink_flutter_plugin-2.1.2 #极光认证 jverify : path : plugin/jverify-2.2.4 #极光统计 janalytics : path : plugin/janalytics-2.1.5 #倒计时 circular_countdown_timer : ^0.2.0 #加载中效果 flutter_spinkit : ^5.1.0 #APP更新 r_upgrade : path : plugin/r_upgrade-0.3.7+2 #刷新-加载更多 flutter_easyrefresh : ^2.2.1 #右上角弹出式菜单 custom_pop_up_menu : ^1.2.2 #时间轴 timeline_tile : ^2.0.0 #虚线边框 dotted_border : ^2.0.0 like_button : ^2.0.4 #图片 extended_image : ^6.0.1 #图片九宫格 nine_grid_view : ^2.0.0 #时间模糊插件 timeago : path : plugin/timeago-3.1.0 #屏幕截图 screenshot : ^1.2.3 #图片压缩 flutter_image_compress : ^1.1.0 #List左滑右滑 flutter_slidable : ^1.2.0 #底部伸缩抽屉-针对地图 sliding_up_panel : ^2.0.0+1 #键盘高度 flutter_keyboard_size : ^1.0.0+4 #JSON动图 lottie : ^1.2.2 #城市选择器 city_pickers : path : plugin/city_pickers-1.0.1 #调试工具 path_provider : ^2.0.7 #打开HTML webview_flutter : ^2.3.1 #表情 emoji_picker_flutter : ^1.0.8 #扇形进度 ai_progress : ^2.0.0 #喜欢按钮 tiktok_favorite_gesture : ^1.0.0 #获取手机信息 device_info : ^2.0.3 #包信息 package_info : ^2.0.2 device_apps : ^2.1.1 #倒计时 stop_watch_timer : ^1.3.1 #发现Android和iOS上的网络(WiFi和移动/蜂窝)连接状态 connectivity_plus : ^2.2.0 #从应用程序打开iOS和Android手机设置。 app_settings : ^4.1.1 #日志上报 sentry_flutter : ^6.1.2 #后退拦截 back_button_interceptor : ^5.0.2 #视频播放器 better_player : ^0.0.81 #APP启动图 flutter_native_splash : ^2.0.4 #JSON-TO-MAPPER dart_json_mapper : ^2.1.17 #HTML展示 flutter_html : ^3.0.0-alpha.2 #XD to Flutter adobe_xd : ^2.0.1 flutter_svg : ^1.0.3 #APPBAR背景色渐变 new_gradient_app_bar : ^0.2.0 #音频播放 flame_audio : ^1.0.0 #入门介绍页 intro_slider : ^3.0.3 #键盘 keyboard_actions : ^3.4.5 emoji_keyboard_flutter : ^1.2.7 #单选选择框 flutter_pickers : ^2.1.9
2023-07-23 10:30:101

Flutter打包产物

基于flutter版本1.9.1,低版本区别对待。 lib目录,libflutter.so文件,三个目录armeabi-v7a,x86_64和x86,支持arm平台32和x86的32和64。 asset目录,新增flutter_asset目录,三个文件,dart产物。 lib目录,libflutter.so文件,两个目录armeabi-v7,arm64-v8a,支持arm平台32和64。 asset目录,新增flutter_asset目录。 在release模式,libapp.so替代flutter老版本的一些dart产物,如下。 flutter命令打包生成产物,flutter命令脚本会调用dart命令。 dart的编译模式: kernel snapshot 模式,开发阶段,isolate_snapshot_data,vm_snapshot_data,kernel_blob_bin是业务数据。 core jit, 生产阶段,dart的一种二进制模式,这是一种aot模式,vm和isolate。 任重而道远
2023-07-23 10:30:171

flutter属于原生开发吗

混合原生开发 以原生为主 UI视图是原生的框架写的
2023-07-23 10:30:262

Flutter 仿抖音效果 (二) 界面布局

Flutter 仿抖音效果 (一) 全屏点爱星 Flutter 仿抖音效果 (二) 界面布局 [Flutter 仿抖音效果 (三) 视频播放列表] ( https://www.jianshu.com/p/d0f44241d80f ) 项目地址: https://github.com/CZXBigBrother/flutter_TikTok 持续效果更新 1.基本的布局是简单的,外层通过Stack作为根 2.左边点赞的控件组通过Align进行统一布局 3.顶部控件组通过Positioned进行布局,设置顶部距离,其实也可以用align,我们多使用几种来习惯flutter的布局 4.底部同样使用Positioned,设置底部距离 5.子页面的左右滑动使用PageView,一开始我们要从推荐开始左滑到关注,可以使用reverse属性,不需要更多额外的操作 1.pageController监听 刷新顶部的下划线时,我们一样使用StreamController刷新,这样效率比setstate高很多 2.歌曲名走马灯效果 这个效果看起来挺麻烦的其实实现起来超级的简单用最普通的ListView就能快速的实现 首页listview里面套入的是最简单的container+text listview添加一个ScrollController做为滑动的控制 使用一个定时器,把listview滑到最大的位置之后,在滑回去 先通过scroController.position.maxScrollExtent获取最大位置, 然后通过scroController.animateTo进行滑动,因为我设置一次循环的时间是3000毫秒,所以滑过去和滑回来的时间各占一般 new Duration(milliseconds: (time * 0.5).toInt()),还有就是歌名没有大于最大宽度时候其实我们不需要进行滑动,所以判断maxScrollExtent是否大于0来确定是否进行滑动动画
2023-07-23 10:30:331

Flutter:退出应用

-此退出方式适用于Flutter是作为Model方式,存在于原生(例如Android)项目里面,并且,当退出时,需要通知原生项目,原生有需要处理的业务,由原生项目来处理结束整个应用(例如Android的:System.exit(0);) 此退出方式就适合原生项目退出时没有需要处理的业务逻辑,直接就结束应用 Flutter documentation 上关乎 exit() 是这么说的:
2023-07-23 10:30:401

Flutter圆角设置组件

flutter能设置圆角的组件:ClipRRect、ClipOval、CircleAvatar、BoxDecoration BorderRadius.circular、BoxDecoration BoxShape.circle 1.ClipRRect:将 child 剪裁为宽高相等的圆角组件,可设置圆角度数 2.ClipOval: 将child裁剪为宽高相等的圆角组件(只包括圆形和椭圆形),不可设置圆角度数 3.CircleAvatar:只能设置自身圆形,不能裁剪child 4.BoxDecoration BorderRadius.circular 设置自身圆角,不能裁剪child 4.BoxDecoration BoxShape.circle 只能设置自身为圆形,不能裁剪child 参考: flutter 圆角设置
2023-07-23 10:30:591

Flutter生命周期

生命周期是一个从创建到销毁的过程,Flutter生命周期分为两部分: 1.Widget的生命周期 2.APP的生命周期 1.StatelessWidget 对于StatelessWidget来说,生命周期只有build过程。build是用来创建Widget的,在每次页面刷新时会调用build。 2.StatefulWidget StatefulWidget的生命周期依次为: createState是StatefulWidget来创建State的方法,只调用一次, initState是StatefulWidget创建后调用的第一个方法,而且只执行一次。在执行initState时,View没有渲染,但是StatefulWidget 已经被加载到渲染树里了,这事的StatefulWidget的 mount 的值会变为true,知道dispose才会变为false.一般我们把初始化的一些操作都放在initState中。 didChangeDependencies会在initState后立即调用,之后只有当StatefulWidget依赖的InheritedWidget发生变化之后,didChangeDependencies才会调用,所以didChangeDependencies可以调用多次。 build方法会在didChangeDeoendencies之后立即调用,在之后setState()刷新时,会重新调用build绘制页面,所以build方法可以调用多次。但一般不再build中创建除创建Widget的方法,否则会影响渲染效率。 addPostFrameCallback是StatefulWidget渲染结束之后的回调,只会调用一次,一般是在initState里添加回调:, 一般在dispose中做一些取消监听、动画的操作,和initState相对使用。 AppLifecycleState就是App的生命周期,包含四个:
2023-07-23 10:31:061

Flutter(二十三)编译模式

下面我们就聊一下三种模式的区别和应用; 在 Debug 模式 下,app 可以被安装在真机、模拟器、仿真器上进行调试。 Debug 模式 有如下特点: 默认情况下,运行 flutter run 会使用 Debug 模式,点击Android Studio run按钮 ,也是debug模式 下面的情况会出现在 Debug 模式 下: 当我们要发布应用程序时,总是希望最大化的优化性能和应用程序所占据的空间。 在 Release 模式 下是不支持模拟器和仿真器的,只能在真机上运行。 Release 模式 有如下特点: flutter run --release 命令会使用 Release 模式来进行编译,也可以给Android Studio进行配置: 如果继续运行在模拟器上: profile模式 和 release模式 类似,但是会保留一些信息方便我们对性能进行检测。 profile模式 有如下特点: Profile模式最重要的作用就是可以利用DevTools来测试应用的性能; 在开发中,我们可能想要对debug和release模式进行区分,根据不同的模式进行不同的相关设置: 如何进行区分呢?常见的有两种方式: 通过断言assert来区分: 通过kReleaseMode常量来区分 当然,上面只是针对baseURL来进行了区分,开发中如果有多个属性需要区分呢?
2023-07-23 10:31:131

Flutter发布Package(Pub.dev或私有Pub仓库)

u2002u2002因为我们使用Flutter跨平台技术开发App时,会有很多公用组件,因为Flutter中一切皆为Widget,widget也比较细粒度,所以我们需要进行封装,用于一个项目或者公司不同项目中去~ u2002u2002那么今天写写如何发布package或者插件到Pub.dev上,扯扯谈O(∩_∩)O哈哈~ 《Flutter的拨云见日》系列文章如下: 1、Flutter中指定字体(全局或者局部,自有字库或第三方) 2、Flutter发布Package(Pub.dev或私有Pub仓库) 首先,我们知道flutter有四种工程模式:Flutter Application、Flutter Module、Flutter Plugin和Flutter Package。 我们这里就主要讲Package 纯Dart插件的发布吧,都差不多。 创建工程后,就可以编写你的公共组件,或者公用字体库呀啥的, 都行。 在更改下你的pubspec.yaml文件,修改下你的versionCode,项目名称,项目描述,作者等 如果上传失败试试U0001f447的命令: 在执行该命令时,可能会中途调到网页,要求你登录google账号,登录授权,到时候登录账号并授权就可以了。 因为我们直接使用flutter packages pub publish是发布到Pub.dev上,并不是发布到私有仓库,该怎么办呢? 其实呢,也很简单!像versionCode,项目名,等都和发布Pub.dev是一样的。没啥区别。 有两种方式: 就是这么简单o( @ )o 相信大家引用Pub.dev上的第三方库都会了哈,到处都是这里不讲了 在使用flutter pub get就可以拉到私有仓库项目了 以上就差不多聊了聊package发布和获取的事儿了,都很明了,大家可以试试,挺简单的。 PS: 写文不易,觉得没有浪费你时间,请给个点赞~ U0001f601
2023-07-23 10:31:211

Flutter 文件路径

path_provider是flutter提供的一个获取应用存储路径的插件,它封装了统一的api来获取Android和ios两个平台的应用存储路径,提供的api如下: getTemporaryDirectory():获取应用临时文件夹,该文件夹用来保存应用的缓存,可以随时删除用于清缓存,对应于Android的getCacheDir()和ios的NSTemporaryDirectory(); getApplicationDocumentsDirectory():获取应用安装路径,在应用被卸载的时候删除,对应Android的AppDate目录和iOS的NSDocumentDirectory目录; getExternalStorageDirectory():获取存储卡目录,仅支持Android; 我们通过File和Directory来创建文件和文件夹时首先要获取到应用的相关路径,不然会报错; File对象和Directory对象封装在dart:io中,使用时需要先引入该库: Directory对象提供listSync()方法获取文件夹里的内容,该方法返回一个数组; 文件和文件夹都通过delete删除,delete异步,deleteSync同步;如果一个文件夹是非空的删除会报错,删除非空文件夹需要先清空该文件夹: flutter对json序列化需要引入 dart:convert 库: 通过jsonEncode/jsonDecode来转换json对象: // 将test目录下的info.json复制到test2目录下的info2.json中 引入包archive包: 压缩: 压缩前使用ZipFileEncoder先声明处理压缩的对象,调用该对象的zipDirectory方法压缩文件,该方法接受两个参数,第一个是要压缩文件/文件夹的路径,第二个是压缩包的保存路径; 解压:
2023-07-23 10:31:281

Flutter 实现的简单滑块认证

import "package:flutter/material.dart"; class SliderBlockVerify extends StatefulWidget { /// 滑块右边颜色 final Color positiveColor; /// 滑块左边颜色 final Color negativeColor; /// 显示内容 final String text; /// 控件总体宽度 final double width; /// 控件总体高度 final double height; /// 滑块显示的图片 final ImageProvider image; /// 滑块的宽度 final double imageWidth; /// 完成的回调 final GestureTapCallback finishCallBack; SliderBlockVerify({ @required this.image, @required this.finishCallBack, this.positiveColor = Colors.green, this.negativeColor = Colors.grey, this.text = "滑到右边以确认", this.width = 250, this.height = 44, this.imageWidth = 60, }) : assert(image != null), assert(finishCallBack != null); @override _SliderBlockVerifyState createState() => _SliderBlockVerifyState(); } class _SliderBlockVerifyState extends State<SliderBlockVerify> { // double percentage = 0; double initial = 0.0; double distance = 0.0; @override void initState() { super.initState(); } @override Widget build(BuildContext context) { return Container( width: widget.width, height: widget.height, child: GestureDetector( onPanStart: _onPanStart, onPanUpdate: _onPanUpdate, onPanEnd: _onPanEnd, child: Stack( children: [ Row( mainAxisSize: MainAxisSize.max, children: <Widget>[ _positive, _negative, ], ), _text, _icon, ], ), ), ); } Widget get _positive { return Offstage( offstage: distance==0?true:false, child: Container( height: widget.height, width: distance, color: widget.positiveColor, ), ); } Widget get _negative { return Offstage( offstage: distance==(widget.width - widget.imageWidth)?true:false, child:Container( height: widget.height, width: widget.width - distance, color: widget.negativeColor ), ); } Widget get _text{ return Positioned( child: Container( alignment: Alignment.center, width: widget.width, height:widget.height, child: Text( widget.text ), ), ); } Widget get _icon{ return Positioned( child: Container( margin: _iconEdgeInsets, width: widget.imageWidth, child: Image( image: widget.image, width: widget.imageWidth, height: widget.height, fit: BoxFit.fitWidth, alignment: Alignment.center, ), ), ); } EdgeInsets get _iconEdgeInsets { double left = 0; if(distance > widget.width - widget.imageWidth) { left = widget.width - widget.imageWidth; } else { left = distance; } return EdgeInsets.only(left: left); } _onPanStart(DragStartDetails details){ initial = details.globalPosition.dx; } _onPanUpdate(DragUpdateDetails details) { distance = details.globalPosition.dx - initial; distance = distance.clamp(0.0, widget.width - widget.imageWidth); setState(() { }); } _onPanEnd(DragEndDetails details) { initial = 0.0; if(distance >= widget.width - widget.imageWidth -30){ distance = widget.width - widget.imageWidth; if(widget.finishCallBack != null){ widget.finishCallBack(); } } else { distance = 0.0; } setState(() { }); } }
2023-07-23 10:31:361

Flutter 项目升级报错处理

1、flutter Warning: Podfile is out of date Warning: Podfile is out of date This can cause a mismatched version of Flutter to be embedded in your app, which may result in App Store submission rejection or crashes. If you have local Podfile edits you would like to keep, see https://github.com/flutter/flutter/issues/24641 for instructions. To regenerate the Podfile, run: rm iOS/Podfile 2、Automatically assigning platform iOS with version 8.0 on target Runner 或者Automatically assigning platform iOS with version 12.0 on target Runner because no platform was specified. Please specify a platform for this target in your Podfile 解决:只要修改ios目录下podfile 第二行 去掉#号 原因是:没有指定iOS版本。 3、 "AMapFoundation" uses the unencrypted "http" protocol to transfer the Pod. Please be sure you"re in a safe network with only trusted hosts. Otherwise, please reach out to the library author to notify them of this security issue. 类似的问题 解决方法: 登录 https://pub.dev/packages 寻找相关最新版本更新一下。 4、[!] An error occurred while processing the post-install hook of the Podfile. undefined method `each_child" for #<Dir:0x00007f8415636e38> Did you mean? each_slice 解决办法:升级ruby
2023-07-23 10:31:431

Vue前端转Flutter一(环境配置)

(*注:以下仅个人配置过程参考,系统win7-64) 所需软件 vsCode,Android Studio, MuMu模拟器 (直连手机调试的话就不需要了) 配置过程 1、Flutter安装 安装时忘记截图,具体可参考链接 flutter中文网 相关教程+ 百度 ,现在网上教程很多,多踩点坑总会成功的。 2、MuMu模拟器调试时需进行相关配置 (*注:直连手机调试可忽略以下;执行以下操作需要在执行flutter doctor成功后,flutter run执行前) (1)mumu模拟器端口监听,需要执行 (2)mumu模拟器调试flutter run可能会报错,可以改成,具体原因可直接百度“--enable-software-rendering” 3、如需调试ios端可尝试虚拟机+macOS+xCode vmware+macOs可参考链接 VMware15安装MacOS系统 ,笔者按照该步骤已安装成功
2023-07-23 10:31:501

Archsummit 2019重磅分享|闲鱼Flutter&FaaS云端一体化架构

作者:闲鱼技术-国有 国有,闲鱼架构团队负责人。在7月13号落幕的2019年Archsummit峰会上就近一年来闲鱼在Flutter&FaaS一体化项目上的 探索 和实践进行了分享。 随着无线,IoT的发展,5G的到来,移动研发越发向多端化发展。传统的基于Native+Web+服务端的开发方式,研发效率低下,显然已经无法适应发展需要。 我们希望 探索 闲鱼这样规模的独立APP的高效研发架构。主要思路是围绕Flutter解决多端问题,并使Flutter与FaaS等无服务容能力打通,形成云端一体化的研发能力,支持一云多端的发展需要。在某些场景已经取得效果,希望分享过程中的思考,与大家交流。闲鱼选择Flutter主要是出于高性能的考虑。Flutter高性能主要来源于2个原因:更多比较:没有银弹的解决方案,Flutter与RN各有优点。如何选择因素很多,关键看如何取舍,举个例子: 云端技术栈的打通,是减少协同的不错的解法。以往前端+Node.js的一体化方案大家应该不会陌生,然而如果端侧使用了Flutter,那云侧Dart自然是第一选择。FaaS的本质是运行在云端,那Dart适合用在云/Server上吗? Dart语言早于Flutter,在最初的设计上,Dart就可以用于Web、Server。Dart具备一些服务端语言的特点: 闲鱼首先尝试将Dart作为普通的Server,替代传统的Java Server,然后再将Dart容器嵌入到FaaS容器中。建立Dart Server能力是第一步,也是主要的工作量所在。 闲鱼在Dart Server方面的建设思路:开发期: 运行期: 上述内容实现了Flutter&Dart FaaS的技术栈的统一,但仅技术栈统一还远远不够,端、云的同学仍然无法真正互补和一体化打通,原因在于还有更多深入问题需要考虑:面向这些问题,闲鱼的解法思路: 案例一,一体化在资源均衡方面的体现。在近期的一个项目中,云端一体化使原本2个月的项目时间,减少了20天。案例二,一体化在业务闭环方面的体现。负责增长的一位开发同学,专注在增长业务上,在合适的情况下为合适的人投放合适的内容,以此带来用户的增长和活跃效果。一体化的方式下,可以统一云、端的切面,业务研发不再受云、端的限制。一体化是建设高效研发框架的方向,并不是所有场景都需要一体化的开发,但一体化的Flutter、FaaS等技术组件,可以独立使用,也会带来效率提升,并且与原有的开发模式兼容。从一体化的思路去建设,可以使整体架构体系更加一致,也有机会做一体的架构沉淀。 未来闲鱼希望在一体化上做更多尝试和深入 探索 ,包括一体化工具、一体化业务平台、数据化智能化等方向。
2023-07-23 10:32:081

Flutter:快速创建简单闪屏页

近来闲暇时间一直在做Flutter,闪屏页是一个比较常见的需求,网上的闪屏页教程大部分是那种类似于广告页,而非iOS中的 LaunchScreen 性质的闪屏页.按照原来的方案我们要配置闪屏页的话,我们需要同时配置两端的闪屏页,那么有没有比较简单的方案来配置闪屏页呢? 毋庸置疑,当然是有了,那就是Flutter的插件 - flutter_native_splash . 接下来我们就来看一下具体应该怎么使用这个插件. 首先把 flutter_native_splash 导入到工程的 pubspec.yaml 中.这里需要注意的是需要放在 dev_dependencies 下,而不是 dependencies .具体如下所示. 接下来我们就来配置 flutter_native_splash ,在配置之前我们看一下 flutter_native_splash 的可配置项. 例如,我现在只有一个logo图片,那么我想生成iOS和android两端的闪屏页,这时候我只需在 pubspec.yaml 如下设置即可. 当然了,如果你有其他配置可以自行进行添加. 配置完成了,我们该如何生成呢?这时候需要我们打开终端 cd 到我们的工程目录下.如果是Android Studio 或者 VSCode 默认就是在当前工程目录下. 然后我们需要执行下面的三个命令来生成闪屏页 每一次都敲三个命令实属麻烦,我们把上诉的三个命令整合成一个命令,如下所示. 那么,我们不想使用该插件生成的闪屏页该怎么办呢?我们只需要执行下面命令即可. 注:每一次更换图片都是需要重新执行命令重新生成. OK,上面就是关于 flutter_native_splash 的使用全部内容,其实比较简单,如果需要定制化的,建议还是各自平台配置各自的闪屏页.如果有任何问题欢迎在评论区批评指导,感谢大家了.
2023-07-23 10:32:161

Flutter笔记(三):设置白色状态栏

在App设计中状态栏纯色的这种设计很常见,但是如果状态栏需要为白色的时候就必须为黑色字体。在Android中已经有很多成熟的方案来处理这种情况,那我们现在看看在Flutter中这种情况该怎么处理。 这里的ThemeData即为控制App的主题,primarySwatch设置即可控制主题的各类颜色,但是这里的颜色是需要MaterialColor,但是纯色种的黑色和白色不是MaterialColor。所以不能设置primarySwatch为Colors.white。 注:MaterialColor包含以下这些 那么就只能使用其他方式设置主题为白色。即为设置 此时我们可以看到App的状态栏如下所示(Android) 虽然AppBar变成了白色,但是状态栏是灰色显然不是我们想要的。 尝试设置文字颜色,AppBar的Brightness有两种模式light和dark 这个和SystemUiOverlayStyle的light和dark刚好相反 然后设置状态栏颜色 设置为红色之后,得到以下的样式,可以看到状态栏为红色了,文字为白色 那么接下来我们只需要将状态栏设置为白色或者透明,状态栏文字设置为黑色。 最后得到以下视图 注:使用PreferredSize包裹,可以更得心应手哦! SystemUiOverlayStyle在设置时其实有很多系统或者版本的限制 [Flutter]使用主题 flutter设置沉浸式状态栏 https://github.com/leiyun1993/FlutterDemo-GankIO )
2023-07-23 10:32:311

Flutter 之 滚动监听及控制(十九)

ListView、GridView的组件控制器是ScrollController,我们可以通过它来获取视图的滚动信息,并且可以调用里面的方法来更新视图的滚动位置。 ScrollController构造函数如下: ScrollController常用的属性和方法: ScrollController间接继承自Listenable,我们可以根据ScrollController来监听滚动事件,如: 示例 我们创建一个ListView,当滚动位置发生变化时,我们先打印出当前滚动位置,然后判断当前位置是否超过1000像素,如果超过则在屏幕右下角显示一个“返回顶部”的按钮,该按钮点击后可以使ListView恢复到初始位置;如果没有超过1000像素,则隐藏“返回顶部”按钮。 ScrollPosition是用来保存可滚动组件的滚动位置的。一个ScrollController对象可以同时被多个可滚动组件使用,ScrollController会为每一个可滚动组件创建一个ScrollPosition对象,这些ScrollPosition保存在ScrollController的positions属性中(List<ScrollPosition>)。ScrollPosition是真正保存滑动位置信息的对象,offset只是一个便捷属性 一个 ScrollController 虽然可以对应多个可滚动组件,但是有一些操作,如读取滚动位置 offset ,则需要一对一!但是我们仍然可以在一对多的情况下,通过其它方法读取滚动位置,举个例子,假设一个 ScrollController 同时被两个可滚动组件使用,那么我们可以通过如下方式分别读取他们的滚动位置: 我们可以通过 controller.positions.length 来确定 controller 被几个可滚动组件使用。 ScrollPosition 有两个常用方法: animateTo() 和 jumpTo() ,它们是真正来控制跳转滚动位置的方法, ScrollController 的这两个同名方法,内部最终都会调用 ScrollPosition 的。 我们来介绍一下 ScrollController 的另外三个方法: 当 ScrollController 和可滚动组件关联时,可滚动组件首先会调用 ScrollController 的 createScrollPosition() 方法来创建一个 ScrollPosition 来存储滚动位置信息,接着,可滚动组件会调用 attach() 方法,将创建的 ScrollPosition 添加到 ScrollController 的 positions 属性中,这一步称为“注册位置”,只有注册后 animateTo() 和 jumpTo() 才可以被调用。 当可滚动组件销毁时,会调用 ScrollController 的 detach() 方法,将其 ScrollPosition 对象从 ScrollController 的 positions 属性中移除,这一步称为“注销位置”,注销后 animateTo() 和 jumpTo() 将不能再被调用。 需要注意的是, ScrollController 的 animateTo() 和 jumpTo() 内部会调用所有 ScrollPosition 的 animateTo() 和 jumpTo() ,以实现所有和该 ScrollController 关联的可滚动组件都滚动到指定的位置。 Flutter Widget树中子Widget可以通过发送通知(Notification)与父(包括祖先)Widget通信。父级组件可以通过NotificationListener组件来监听自己关注的通知 可滚动组件在滚动时会发送 ScrollNotification 类型的通知, ScrollBar 正是通过监听滚动通知来实现的。通过 NotificationListener 监听滚动事件和通过 ScrollController 有两个主要的不同: 示例 下面,我们监听ListView的滚动通知,然后显示当前滚动进度百分比: 在接收到滚动事件时,参数类型为ScrollNotification,它包括一个metrics属性,它的类型是ScrollMetrics,该属性包含当前ViewPort及滚动位置等信息: https://book.flutterchina.club/chapter6/scroll_controller.html
2023-07-23 10:32:381

Flutter—手机消息推送(notification)

在flutter中使用notifacation,目前可以使用官方的插件 Flutter Local Notifications Plugin 来实现。 在pubspec.yaml中添加 使用该插件的思路大致为:在android中设置权限管理——引入依赖——初始化。 安卓权限管理设置 引入依赖 接下来就可以在项目中初始化使用了,首先在initState()中初始化设置
2023-07-23 10:32:451

Flutter状态管理--GetX的简单使用

一、前言 Flutter开发,就需要对各种状态的管理,就是在请求数据的时候需要实时变化,各种交互变化等,在没有使用GetX之前使用Provider,用Provider的时候觉得真香,挺方便的,需要刷新的时候直接 notifyListeners(); 用了GetX之后觉得Provider太繁琐了。这边介绍下GetX的使用以及常用的方法。 二、 GetX GetX 是 Flutter 上的一个轻量且强大的解决方案:高性能的状态管理、智能的依赖注入和便捷的路由管理。 1、相关优势: 三、使用 1、第一步 引入get 2、第二步 修改入口、配置路由 3、路由 Routes类 Pages类 4、状态管理 我一般一个page对应一个controller, controller来处理逻辑,控制page. 简单使用 5、依赖注入 依赖注入也是我喜欢的,可以减少很多工作。 第一步 第二步 6、跨页面交互 7、黑暗模式 可以参考前期写的博客。 黑暗模式的适配
2023-07-23 10:32:521

Flutter局部刷新方法

Flutter中Widget分为StatefulWidget和StatelessWidget,分别为动态视图和静态视图,视图的更新需要调用StatefulWidget的setState方法,这会遍历调用子Widget的build方法。当一个主页面比较复杂时,会包含多个widget,如果直接调用setState,会遍历所有子Widget的build,这是非常不必要的性能开销,有没有单独刷新指定Widget的方式呢?这个时候就要用到GlobalKey了。 一个StatefulWidget包含一个Button,一个Text,通过点击Button调用主Widget的setState方法,刷新Text,示例如下: 同样一个StatefulWidget包含一个多个Text和Button,点击Button我们只需要刷新指定的Text,通过GlobalKey的方式,实现如下: 主Widget,包含一个需要更新的TextWidget和一个不需要更新的Text 需要单独更新的Widget 传递事件的Button 这样点击Button就只会更新指定的TextWidget了,效果如下: 这只是一个简单的例子,在实际开发中为了页面刷新的高效率,模块化封装非常重要。很多情况下都只需要局部刷新,而不是重构整个视图。所以Globalkey的运用在项目中需要熟练掌握
2023-07-23 10:32:591

flutter与原生混编(iOS)

一、创建项目及配置 1,创建ios项目,同时在同一个根目录下创建flutter项目 flutter项目使用命令flutter create -t module xxxflutter项目名 如图 2,将flutter项目以pod的形式加入ios项目 2.1,如果项目之前没有用过pod,则pod init创建podfile 如果使用过,直接进行步骤2.2。 2.2,podfile中添加 flutter_application_path是flutter项目的路径 2.3,target中加入(一次性将flutter的编译产物由此依赖进入iOS项目中,可跳过步骤3) 3,配置脚本(已完成步骤2.3可进行步骤4) 打开ios项目,在Build Phases中左上角添加Run Script 4,设置bitcode Flutter 目前还不支持 BitCode,需要设置为No 二、混编使以后添加的每个模块都以package形式,在module中pubspec.yaml文件中引用(基于内存消耗考虑) 1,页面跳转 原生处理: flutter在iOS中的使用,主要是以FlutterViewController为载体,并在其内部采用FlutterEngine对视图进行渲染。 导入头文件: flutter处理: 在module项目的main里 定义channel,名字与原生保持一致 2,数据传递 二者之间的数据传递iOS使用FlutterBasicMessageChannel类,flutter使用BasicMessageChannel类,用法与MethodChannel类似 原生处理: 接收数据: 发送数据: flutter处理: 问题: 网上搜的方法,在podfile最前边加eval(File.read(File.join(flutter_application_path, ".ios", "Flutter", "podhelper.rb")), binding)句话 执行pod install失败 于是又搜了下别的文章,添加的第二句话为load File.join(flutter_application_path, ".ios", "Flutter", "podhelper.rb"),试了下成功了
2023-07-23 10:33:061

Flutter解决界面超出bug

如上图,最右边有黄色斑马线类似的线。 在这里查找源码可以看到,Flutter在这里做的处理 _calculateOverflowRegions这个方法,计算界面是否超出边界,如果超出了 就添加一个斑马线的布局,可以通过修改源码的方式,暂时让他隐藏直接return就可以了。 当然,Flutter这样是为了更好的提示开发者,方便开发的。平时调试的时候还是要打开的。除非上线,如果不放心的话,可以这么写。
2023-07-23 10:33:321

Flutter 修改应用程序的名称和图标

在项目中找到 AndroidManifest.xml 文件,其中 android:label="demo" 就是应用程序名称,修改引号中的内容即可 在项目中找到 mipmap-mdpi mipmap-hdpi mipmap-xhdpi mipmap-xxhdpi mipmap-xxxhdpi 文件夹,替换这些文件夹中的 ic_launcher.png 文件即可 注意:图标有多种尺寸的大小,是为了适配不同分辨率的手机而设计的 在项目中找到 Info.plist 文件,其中 CFBundleDisplayName 和 CFBundleName 下面的就是应用程序名称,修改内容即可 找到项目中的 AppIcon.appiconset 文件夹,其中 Contents.json 是配置文件,其它的图片文件就是图标,替换这些图片文件即可 注意:图标有多种尺寸的大小,是为了适配不同分辨率的手机而设计的 插件地址: https://pub.dev/packages/flutter_app_name 在项目中找到 pubspec.yaml 文件,添加内容如下 插件地址: https://pub.dev/packages/flutter_launcher_icons 在项目中找到 pubspec.yaml 文件,添加内容如下 注意:准备一张 1024x1024 的 png 图片,取名为 icon.png 并把它放在 assets/icon 目录中 找到 ~/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_launcher_icons-0.9.2/lib/android.dart 文件修改内容如下 注意:如果使用了镜像地址就找到 ~flutter/.pub-cache/hosted/pub.flutter-io.cn/flutter_launcher_icons-0.9.2/lib/android.dart 文件来修改以上内容 https://github.com/fluttercommunity/flutter_launcher_icons/issues/324
2023-07-23 10:34:031

flutter 常见问题之app体积为何比较大

细心的开发者会发现flutter构建的App体积比native的大一些,是什么原因造成App体积大呢? 其实flutter 在release时App体积和native的大小差不多,而debug时体积通常会大。debug版本体积较大是为了Hot reload和快速编译。如果有flutter开发经验的朋友都体验过,如果您修改一下App的背景颜色,只需save一下就可以立刻看到修改后效果。我称之为“像艺术家一样在创造App”,因此为了实现这些目标,提高开发的效率,debug将占用全部资源。而当我们构建release版时,flutter又会采用AOT策略,提高App运行效率,release版只打包必需的资源,因而体积又会减少。 另外,flutter团队也一直在寻找减小程序大小的方法。
2023-07-23 10:34:111

flutter直播怎么实现?

flutter作为一个相对来说比较新兴的框架,相比于其他框架来说避免不了存在生态不完善的问题。要想实现flutter直播,可以接入即构科技的Express Flutter SDK,然后通过集成、初始化SDK、登录房间服务器、用户推送自己的本地音视频、拉取远端的音视频流等简单五个步骤实现简单的实时音视频场景进行直播。
2023-07-23 10:34:181

Flutter笔记-调用原生IOS高德地图sdk

2017年底因公司业务组合部门调整,新的团队部分维护的项目用React Native技术混合开发。为适应环境变化,开启疯狂RN学习之旅,晚上回来啃资料看视频。可能由于本身对RN技术体验不感冒或者在环境之下强迫学习有点不爽。开始寻找代替方案,Fluter像一束曙光引起了我的注意,之后一直关注并利用闲余时间开始探索。2018年一直学习到使用Flutter写项目,从0.2.0开始到现在1.5版本的发布,终于开始慢慢的爬出坑位了,但是因为部分控件感觉还是不如原生控件好用,因而Flutter提供了PlatformView部件。近期因项目中严重使用依赖地图,故而做了Fluterr使用原生IOS高德地图调研。因为我本身是一名android开发人员,初学IOS并记录下来。 PlatformView是 flutter 官方提供的一个可以嵌入 Android 和 iOS 平台原生 view 的小部件。 在我们实际开发中,我们遇到一些 flutter 官方没有提供的插件可以自己创建编写插件来实现部分功能,但是原生View在 flutter 中会遮挡住flutter 中的小部件,比如你想使用高德地图sdk、视频播放器、直播等原生控件,就无法很好的与 flutter 项目结合。 1、info.plist文件设置 2、 ios 端实现原生组件PlatformView提供原生view 3 、ios 端创建PlatformViewFactory用于生成PlatformView 4、 ios 端创建FlutterPlugin用于注册原生组件 5 、flutter 平台嵌入 原生view iOS端的UiKitView目前还只是preview状态, 默认是不支持的, 需要手动打开开关, 在info.plist文件中新增一行io.flutter.embedded_views_preview为true. 创建类 FlutterMapView 并实现FlutterPlatformView 协议 FlutterMapView.h FlutterMapView.m FlutterMapFactory.h FlutterMapFactory.m FlutterMapPlugin.h FlutterMapPlugin.m 请前往 高德开放平台控制台 申请 iOS Key。 注意:Bundle Identifier需要与申请的时候填写的一致 地图依赖的库列举如下: 基础 SDK AMapFoundationKit.framework 第一步:将解压后的MAMapKit.framework 文件 copy 或 拖拽 到工程文件夹中,左侧目录选中工程名,在 TARGETS->Build Phases-> Link Binary With Libaries 中点击“+”按钮,在弹出的窗口中点击“Add Other”按钮,选择工程目录下的 MAMapKit.framework 文件添加到工程中。 千万不要忘记将AMapFoundationKit也一起加入工程。 3D地图正确配置应如下图所示: 需要引入的资源文件包括:AMap.bundle,其中:AMap.bundle 在 MAMapKit.framework 包中,AMap.bundle资源文件中存储了定位、默认大头针标注视图等图片,可利用这些资源图片进行开发。 左侧目录中选中工程名,在右键菜单中选择Add Files to “工程名”…,从MAMapKit.framework中选择AMap.bundle文件,并勾选“Copy items if needed”复选框,单击“Add”按钮,将资源文件添加到工程中。 成功跑起来 。。 。
2023-07-23 10:34:241