Flutter很好用,but……

前言

为何有这篇文章?java

这篇文章能够说是我的Flutter问题随笔吧,虽然Flutter能够方便的作到跨平台,可是毕竟是新项目,功能没那么全面也是意料之中,因此在此记录跟踪一下目前在使用Flutter过程当中遇到的问题,目前的解决方案,并跟踪记录一下。android

问题列表(持续更新):git

  1. Flutter 中不支持异步测绘大量文字
  2. Flutter IOS 后台音频播放
  3. Flutter 中 NestedScrollView 中存在折叠头、子列表等状况下的滑动等异常
  4. Hero 跳转以后的图片若是在折叠布局中被折叠隐藏了,那么Hero的退出动画没法正常播放,而且原图片没法显示(flutter的master分支已修复)
  5. listView 不支持按index跳转

正文

1. Flutter 中不支持异步测绘大量文字

这个源自于我的练手APP,在开发阅读模块过程当中遇到了这么一个问题:github

若是想要自定义文字间距,段落间距等,那么天然就要使用textPainter本身绘制文字。可是由此引起出一个问题:若是有上万个文字,那么测绘时间会很长。天然会阻塞主进程。canvas

解决这个问题,第一个想法天然就是使用异步处理,那么flutter 中的异步方案有哪些呢?缓存

  1. Future(包括await async那些东西)
  2. isoloate

按照官方文档,大量计算东西应该放到Isolate中,因此,天然而然地,咱们将textPinter测绘方法放到Isolate中执行,可是呢,执行报错:native function not foundbash

缘由就是UI包的类只容许在Flutter的UI Isolate中执行。服务器

此题无解,完结撒花,各回各家,各找各妈(才怪)异步

解决方案一:Pluginasync

这个方法的思路来自于官方开发人员的回答:

right now you would have to write your own line-breaking logic - perhaps as a plugin. We don't currently have any API for doing text layout in a separate isolate. @GaryQian might have some other idea about this too.

因此说,咱们看下官方的Plugin是怎么实现的。

在 Plugin工程中,有这么一个: android_alarm_manager ,这个Plugin中的AlarmService.java文件中,有这么一个方法:startBackgroundIsolate(要素察觉+1)

经过阅读源码,咱们得知,其实说白了就是新建一个FlutterNativeView ,这个FlutterNativeView 不负责渲染界面,只负责当后台线程来用。一样的道理,咱们也能够用一样的方法来处理咱们的须要运行在UI Isolate的异步任务。(至于为何新建一个FlutterNativeView ,就能实现这个需求,粗略的说下是由于,每次新建FlutterNativeView,其实都会新建一些TaskRunner,其中就包含UI 的TaskRunner,总之有兴趣的能够搜下Flutter中的TaskRunner机制了解下)

不过,其实不用本身实现注册,有这么一个第三方:flutter_isolate能够作到这点,用法跟普通的isolate差很少,因此解决方式也很简单:找到原来使用Isolate的那段代码,把Isolate.spawn替换为FlutterIsolate.spawn便可。不过通过测试,在1.10版本上会报错,因此想使用这个方式的话,仍是切回stable 分支使用吧。

解决方案二:分割为多个小任务(我的感受不太推荐这种方式,感受不可控,毕竟假如小任务的执行时间也很长咋办)

这种方式说白了就是每测绘完一行,就提交一次,而不是总体测绘完以后再提交结果。

举个小例子:

Future(() async {
  var result;
  for (var i = 0; i < 1000000; ++i) {
    result = 'result is $i';
    await Future.delayed(Duration.zero);
  }
  print(result);
});
复制代码

用这种方式计算就不会卡UI

解决方案三:目前这个问题已经加入到里程碑了,在将来的某天应该就有解决方案

github.com/flutter/flu…

2. Flutter IOS 后台音频播放

也就是像音乐播放器那样,会有个通知显示进度,即便在桌面也能够播放音乐这种

目前只有Android的实现,IOS这块目前尚未方案……%

3. Flutter 中 NestedScrollView 中存在折叠头、子列表等状况下的滑动等异常

找了半天才发现有个大佬已经搞定了这个问题:

juejin.im/post/5bea43…

使用extended_nested_scroll_view便可解决这个问题,在此记录一下

4. Hero 跳转以后的图片若是在折叠布局中被折叠隐藏了,那么Hero的退出动画没法正常播放,而且原图片没法显示

这个描述可能有些抽象,具体状况以一个例子为例描述:

1、首页放一个图片,给他设置点击跳转详情页,并设置hero动画。

2、将图片设置为SliverAppBar的FlexibleSpaceBar的widget中的内容,而后上拉页面,折叠隐藏掉SliverAppBar。

3、按后退键退出详情页,触发hero的关闭动画。

按这三步执行以后,首页原来那张图片就变成空白,并且没法点击。

issue:

github.com/flutter/flu…

github.com/flutter/flu…

因此切换到master分支或者dev分支(问题修复版本v.1.10.14),或者下降稳定版的版本。

5. listView 不支持按index跳转

下面是我搜索出的内容:

stackoverflow.com/questions/5…

pub.dev/packages/in…

pub.dev/packages/sc…

pub.dev/packages/fl…

上面的实现方法各有千秋吧,整理一下主要的缺陷点,之后能够根据实际状况使用:

  1. stackOverflow 中提到了两种方法:一是使用index_list_view,这个稍后统一分析。二是 gist.github.com/debuggerx01… ,不过有老哥将它放在带评论的列表上,结果性能比较差,简介文章中也讲明了,若是处理很差确实可能存在性能问题。
  2. indexed_list_view stackOverflow中也提了,这个适用于无限列表的状况。
  3. scroll_to_index 代码稍微有点侵入性(其实这个不是重点),其次没有jump方法,scroll时长好像也没什么效果,因此若是列表比较大而跳转距离也很大(好比说凡人修仙传的章节那种……),那么动画效果比较感人。(PS:好像这个滑动时间长的问题(github.com/flutter/flu…)已经修复了,虽然在这个issue中没有说,可是我本身在v1.10.14上发现好像如今scroll动画能在很短期内滑动到目标位置了)
  4. flutter_widgets 谷歌大大的产品(不过不是官方正式控件),基本知足需求,方法也很简单,jump方法的什么也有。可是,若是把它放到NestScrollView中搞视差滑动的页面的时候,会致使总体没法滑动,只能滑动ScrollablePositionedList中的内容……(其实缘由就是由于自定义了controller),并且若是存在ExpansionTile这种可伸缩的布局,经过伸缩方式改变了item的高度,ScrollablePositionedList并不会更新高度,而是仍是以改变前高度为准进行index跳转。

如今正在尝试解决ScrollablePositionedList中的视差滑动问题,(得想个办法让NestScrollView届的到ScrollablePositionedList的controller) 在NestScrollView中是经过设置PrimaryScrollController,让innerController管理body滑动的,因此使用这个innerController来替代ScrollablePositionedList的controller便可解决没法滑动的问题,可是随之而来的是一个新的问题,如今按index跳转,会致使body触发滑动,进而直接折叠掉SliverAppBar……………如何让index跳转的时候,body在NestScrollView中的位置不动,只在原地实现自身的index跳转,只有手动滑动的时候才容许改变body在NestScrollView中的位置,目前想法是在SliverAppBar的floating、pinned等控制滑动方式的方法上看看有没有突破口。 不搞了,如今挺好的。直接满屏展现,实在不行加个跳转到顶部按钮,我感受蛮合理的。(大雾)

改变高度这个,目前采用设置addPersistentFrameCallback 方式持续监听。本觉得应该性能比较差,可是测试了一下,好像frame没啥变化,因此应该没啥问题。

题外话

有些同窗可能对我为何须要测量上万字感到困惑,因此在这简单的提下:

测绘上万字这个状况来自于我想把本身原来的一个Android原生小说阅读器,转换为flutter实现(主要是想实现那帮仿真、滚动等翻页动画啥的,练习一下flutter的canvas操做),小说阅读器的基本思路参考自这个项目:任阅

思路基本是这样的:

基本功能是:上一页,下一页,上一章,下一章,章内跳页。

由于要考虑上一章下一章切换以及章内跳转到多少页的这些功能,因此天然以章为基础单位,章内部包含页,取的时候把章的数据拿出来,而后从章中页数据中取出要展现的页的数据,并将其绘制到canvas上。

因此,缓存计算也是计算的章的内容,因此当从服务器下载下来新的章的时候,就有可能遇到上万字的章的状况。

可能也有同窗说:直接按页缓存不就好了,每次只缓存几页的内容,那确定不会遇到须要一次性测量上万字的状况。可是若是纯粹按页缓存的话,若是遇到这两种状况就傻眼了:1. 若是有个用户打开一本新的小说,直接跳到第十章,而后按了上一页。 2. 章节内跳转到第n页(n>缓存页数)。

由于标点符号、全角、特殊字符等非普通汉字的存在,因此咱们是没法直接得知每页展现的内容,天然没法在测量完整章以前得知某页的展现内容,因此要支持上面提到2个状况,必然要测量分页整章内容。

固然,可能我这个思路也不是最优解,若是有更好的方案,但愿各位不吝指教

相关文章
相关标签/搜索