Flutter知识点

    1. 级联操作符

    Dart 中 级联操作符 可以返回对象从而继续执行其他方法:

    new Column(
          children: [
            new Container(),
          ]
            ..addAll(List.generate(3, (index) {
              return Container();
            }))
            ..addAll([
              new HorizontalLine(height: 5),
            ]),
        );
    
    1. 一次性执行匿名回调函数

    Dart 支持一次性执行匿名回调函数,如:

    void test() {
      () {
        print('hi');
      }();
    }
    

    也可在组件中运用并接收参数,如:

    @override
    Widget build(BuildContext context) {
      return new Scaffold(
        body: new Text((String text) {
          return text;
        }('我是文字')),
    }
    
    1. 可选方法参数

    Dart 方法可以设置 参数默认值指定名称

    比如: getDetail(Sting userName, reposName, {branch = "master"}){} 方法,这里 branch 不设置的话,默认是 “master” 。参数类型 可以指定或者不指定。调用效果: getRepositoryDetailDao(“aaa", "bbbb", branch: "dev");

    1. Assert (断言)

    assert 只在检查模式有效,在开发过程中,assert(unicorn == null); 只有条件为真才正常,否则直接抛出异常,一般用在开发过程中,某些地方不应该出现什么状态的判断。

    1. 扩展

    扩展可以给指定类型的数值增加获取方法,如( ScreenUtil 给 num 加的扩展):

    extension SizeExtension on num {
      num get w => ScreenUtil().setWidth(this);
    
      num get h => ScreenUtil().setHeight(this);
    
      num get sp => ScreenUtil().setSp(this);
    
      num get ssp => ScreenUtil().setSp(this, allowFontScalingSelf: true);
    }
    

    比如我想获取一个 ScreenUtil 适配的50宽度值:

    Container(width: 50.w)
    

    等同于:

    Container(width: ScreenUtil().setWidth(50))
    

    从而简化了代码,提升了开发效率。

    1. runZoned

    可以在自己的区域中运行指定代码(根据 zoneSpecification 使用 Zone.fork 创建的区域),如果代码出现错误将抛出全局错误在 onError:

    runZoned(() {
        runApp(MyApp());
      }, onError: (Object obj, StackTrace stack) {
        print(obj);
        print(stack);
      });
    

    我们通用的错误信息统计平台如 sentry,一般都是放在 runZoned 的 onError 内。

组件

1. ListView 自动内边距

ListView 会在脚手架中未写 AppBar 的情况下自动添加 padding 内边距,内边距值是状态栏高度

2. Draggable 重绘问题

Draggable 的 child 和 feedback 是同一个组件是每次拖动都会重绘组件,如果不想被重绘,在组件的 key 给个 GlobalKey即可。

3. 拿到数组模型索引

List.generate 可以获得数组模型的索引 index,length 写数组模型的长度即可。

4. 输入框内容被清空

如果出现输入框内容输入的时候突然返回到桌面,回来的时候被清空了,可以尝试使用 WidgetsBindingObserver 监听不可见生命周期,输入框焦点自动取消,从而输入框会保存原有内容。(这个问题在早期 flutter 版本出现)

5. 刷新页面的指定组件

如果只想刷新某个页面的指定组件可使用 GlobalKey 包裹此组件的 State 类,调用此组件的时候传过去,想刷新的时候就可以在外面调用这个 GlobalKey 的 setState 或其他刷新方法了。

6. 拿特殊滑动组件内控制器

特殊滑动组件如 NestedScrollView 是有内外控制器的,普通的赋值 controller 只能拿到外部的滑动值,想要拿到内控制可以在 NestedScrollView 的 body 中类在上下文获取,调用上下文的 ancestorWidgetOfExactType


class DataBody extends StatefulWidget {
  @override
  _DataBodyState createState() => _DataBodyState();
}

class _DataBodyState extends State<DataBody> {
  ScrollController pageScrollController;

  Type typeOf<T>() => T;

  @override
  void initState() {
    super.initState();

    PrimaryScrollController primaryScrollController =
        context.ancestorWidgetOfExactType(typeOf<PrimaryScrollController>());

    pageScrollController = primaryScrollController.controller;
  }
}

不过这个在 1.12 已被废弃,新版 Flutter 使用 findAncestorWidgetOfExactType 代替。

功能

1. 无需上下文路由

自己定义个 NavigatorState 的全局 key 然后赋值到 MaterialApp 的 navigatorKey 就能使用 NavigatorState 的所有功能并无需上下文。

2. Future 执行完成错误

如果出现 Future 执行完成错误可尝试使用 Completer 的 future,如:

Future<Null> _refreshData() {
  final Completer<Null> completer = new Completer<Null>();

  new Future.delayed(new Duration(seconds: 2), () {
    completer.complete(null);
  });

  return completer.future;
}

3. 调用方法出现 null 错误

dispose 销毁某对象时在调用 .dispose 前加个 ? 问号,可以避免前面的为空导致调用不到 dispose 方法报错。

4. 页面状态保存

Flutter 中可以通过 mixins AutomaticKeepAliveClientMixin ,然后重写 wantKeepAlive 保持住页面,记得在被保持住的页面 build 中调用 super.build

5. 手势识别范围

使用 GestureDetector 范围只有 child 的设定颜色或使用区域才可被触发,behavior 为 HitTestBehavior.translucent 时整个 child 会被触发,InkWell 组件默认整个 child 会被触发。
hitTest 得到一个包含所有待处理控件列表 HitTestResult
dispatchEvent 进行事件分发并产生竞争,最终胜利者可以得到事件响应权

如果同一个区域内有多个控件都实现了 handleEvent,那么最后事件应该交给谁处理呢?
事件竞争只有符合以下两个条件之一的,才可以得到事件的处理权。

  1. 最后得到直接胜利的控件
  2. 活到最后的控件中排在列表第一位的控件

6. Flutter 手势事件主要是通过竞技判断

主要有 hitTest 把所有需要处理的控件对应的 RenderObject , 从 childparent 全部组合成列表,从最里面一直添加到最外层。

然后从队列头的 child 开始 for 循环执行 handleEvent 方法,执行 handleEvent 的过程不会被拦截打断。

一般情况下 Down 事件不会决出胜利者,大部分时候是在 Move 或者 up 的时候才会决出胜利者。

竞技场关闭时只有一个的就直接胜出响应,没有胜利者就拿排在队列第一个强制胜利响应。

同时还有 didExceedDeadline 处理按住时的 Down 事件额外处理,同时手势处理一般在 GestureRecognizer 的子类进行。

插件开发

1. android 获取 context 和 activity

可以在插件的 Plugin 类实现 ActivityAware,然后在 onAttachedToActivity 和 onReattachedToActivityForConfigChanges 都可以拿到 ActivityPluginBinding 的 binding,binding 调用getActivity。


public class DemoPlugin implements FlutterPlugin, MethodCallHandler, ActivityAware {

    static Context ctx;
    static Activity activity;

    @Override
    public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
        ctx = binding.getApplicationContext();
    }

    @Override
    public void onAttachedToActivity(ActivityPluginBinding binding) {
        activity = binding.getActivity();
        ctx = binding.getActivity();
    }

    @Override
    public void onDetachedFromActivityForConfigChanges() {

    }

    @Override
    public void onReattachedToActivityForConfigChanges(ActivityPluginBinding binding) {
        ctx = binding.getActivity();
        activity = binding.getActivity();
    }
}

2. PlatformView

Flutter 中通过 PlatformView 可以嵌套原生 ViewFlutter UI 中,这里面其实是使用了 Presentation + VirtualDisplay + Surface 等实现的,大致原理就是:

使用了类似副屏显示的技术,VirtualDisplay 类代表一个虚拟显示器,调用 DisplayManagercreateVirtualDisplay() 方法,将虚拟显示器的内容渲染在一个 Surface 控件上,然后将 Surface 的 id 通知给 Dart,让 engine 绘制时,在内存中找到对应的 Surface 画面内存数据,然后绘制出来。实时控件截图渲染显示技术。

3. Platform Channel

Flutter 中可以通过 Platform Channel 让 Dart 代码和原生代码通信的:

  • BasicMessageChannel:用于传递字符串和半结构化的信息。
  • MethodChannel:用于传递方法调用(method invocation)。
  • EventChannel: 用于数据流(event streams)的通信。

同时 Platform Channel 并非是线程安全的
更多详细可查阅闲鱼技术的 《深入理解Flutter Platform Channel》

介绍

1. 运行模式

Flutter 的 Debug 下是 JIT 模式,release 下是 AOT 模式。目前主流的语言大多数只支持其中一种编译方式,如 C 仅支持 AOT,JavaScript 仅支持 JIT,一般来说静态语言使用 AOT,动态语言使用 JIT

AOT 编译方式下,编译器必须在执行代码前将代码编译成机器执行的原生代码,在程序运行时就不需要做其他额外的操作直接快速执行,但是编译时需要区分用户机器架构,生成不同架构的二进制代码

JIT 程序运行前不需要编译代码,而是在运行时动态编译,不用考虑用户机器是什么架构,虽然缩短了开发周期,但是可能导致程序执行速度更慢

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容