Flutter-总结

简介

谷歌开发的,有自己的渲染引擎,保持Android和iOS保持一致性
渲染方式自己渲染。

  • MaterialApp 类似AppDelegate 可以设置 主题样式,home 首页,路由routes,以及开发模式,debug or release
  • Scaffold [ˈskæfoʊld] 脚手架 包含系统的一些UI组件,例如appBar、floatingActionButton、bottomNavigationBar
  • hot reload和hot restart 热重载和热重启 如果修改了状态相关的代码则需要hot restart,否则只需要hot reload即可

布局

  • alignment 布局
  • Row 横向排列 :主轴,交叉轴(X轴)
  • Column 纵向排列:主轴,交叉轴(Y轴)
  • Stack 层级排列,最大的在最下面(Z轴)
  • Expanded 自动填充:子部件随着父部件的大小自己填充
  • column 布局 设置高度无意义
  • row 布局 设置宽度无意义

生命周期

  • 初始化
    • 构造函数 > initState > didChangeDependencies > Widget build
  • 状态变化
    • 热重载:reassemble > 组件状态改变:didUpdateWidget > widget build
  • 组件移除
    • 页面销毁的时候会依次执行:deactivate > dispose
  • 切至后台
    • didChangeAppLifecycleState(AppLifecycleState.inactive) -> didChangeAppLifecycleState(AppLifecycleState.paused) -> build
  • 切回前台
    • didChangeAppLifecycleState(AppLifecycleState.inactive) -> didChangeAppLifecycleState(AppLifecycleState.resumed) -> build

StatelessWidget - 生命周期

StatelessWidget 的生命周期只有一个,就是 build
build 是用来创建 Widget 的,但因为 build 在每次界面刷新的时候都会调用,所以不要在 build 里写业务逻辑,可以把业务逻辑写到你的 StatelessWidget 的构造函数里。

class TestWidget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    print('StatelessWidget build');
    return Text('Test');
  }
}

StatefulWidget - 生命周期

依次为

  • createState
  • initState
  • didChangeDependencies
  • build
  • addPostFrameCallback
  • didUpdateWidget
  • deactivate
  • dispose
有状态生命周期

状态管理

  • StatelessWidget(无状态)

一旦创建就不会发生变化,定义属性值可以变化,但不会重新渲染UI,

  • StatefulWidget(有状态)
  • state发生变化时会重新渲染UI,类似于Hot Reload
  • 更新/刷新操作:setState(() {});
  • createState 此方法返回状态管理类,进行关联

需要两个类去管理

  • 描述UI
  • 记录状态的State (w,h)不销毁,界面消失才会被干掉 : State属性改变时会根据宽高重新渲染UI

页面Push 和pop

Push

//push 跳转新页面
Navigator.of(context).push(
  MaterialPageRoute(builder: (BuildContext context){
     return DiscoverChildPage(title: this.title,);
  })

);

Pop

Navigator.pop(context);

Flutter混编

Channel

MethodChannel 传递方法 一次通讯

  • 1.通过setInitialRoute 向Flutter传入参数
  • 2.Flutter接收传入参数并显示不同内容 window.defaultRouteName
  • 3.setMethodCallHandler 判断[call.method isEqualToString:@"picture"]

BasicMessageChannel 传递字符串

监听输入框输入文本 持续传输

EventChannel 传递数据流

常见问题

1.部件溢出

A RenderFlex overflowed by 22 pixels on the bottom.
//原因:在水平或者垂直方向上的内容超过了父部件的大小

//解决办法
包一层SingleChildScrollView,让你的页面可以滑动起来。
在Scaffold中设置resizeToAvoidBottomInset为false。默认为ture,防止部件被遮挡。如果使用了这个方法,如果底部有输入框,则会造成遮挡。

2.输入框遮挡

Column配合Expanded来实现

3.SafeArea

一旦有部件固定在顶部或者底部(严谨点的话可以说是在屏幕的四边)。那我我们最好使用SafeArea来包一下。因为Android 和 IOS都有状态栏,甚至IOS还有叫做“HomeIndicator”的横条。所以一不留神就会出现适配问题
使用方法为


Material( // 需要颜色填充到边界区域可以使用
  color: Colors.white,
  child: SafeArea(
    child: Container(),
  ),
)

4.注意平台差异

注意部分组件在Android与IOS平台之间的差异。
ScaffoldAppBarAppBar中默认的title在Android中靠左显示,IOS中居中显示。如果需要两个平台效果统一,需要设置在AppBar中主动设置centerTitle属性。同时AppBar的返回箭头图标也不相同,统一的话需要自定义leading

页面跳转如果使用MaterialPageRoute来做过渡效果,注意Android中新的页面会从屏幕底部滑动到屏幕顶部,IOS中新的页面会从屏幕右侧滑动到屏幕左侧。

如果需要两个平台效果统一,我们不使用自带效果,可以自定义一个

Navigator.push(context, PageRouteBuilder(transitionDuration: Duration(milliseconds: 300),
  pageBuilder: (context, animation, secondaryAnimation){
    return new FadeTransition( //使用渐隐渐入过渡,
      opacity: animation,
      child: TestPage(),
    );
  })
);

5.保持页面状态

比如点击导航栏来回切换页面,默认情况下会丢失原页面状态,也就是每次切换都会重新初始化页面。这种情况解决方法就是PageViewBottomNavigationBar结合使用,同时子页面State中继承AutomaticKeepAliveClientMixin并重写wantKeepAlive为true。代码大致如下:


class _TestState extends State<Test> with AutomaticKeepAliveClientMixin{

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Container();
  }

  @override
  bool get wantKeepAlive => true;
}

6.依赖版本问题

首先这里建议凡是Flutter的插件在填写版本号时不要使用^符号。

依赖版本问题

^符号意味着你可以使用此插件的最新版本(大于等于当前版本)。这会导致什么问题呢?可能你前一天代码还能跑起来,今天就编译出错了。因为这些插件中包括Android、IOS的所用依赖环境配置,常见的就是新版本使用了AndroidX的依赖,但是还有些插件并没有使用AndroidX,导致了两者的冲突。

7.常见第三方使用

7-1.Toast插件-oktoast

# Toast插件 https://github.com/OpenFlutter/flutter_oktoast
  oktoast: ^2.2.0
  
  import 'package:oktoast/oktoast.dart';
class Toast {
  static show(String msg, {duration = 2000}) {
    showToast(
        msg,
        duration: Duration(milliseconds: duration),
        dismissOtherToast: true
    );
  }
  static cancelToast() {
    dismissAllToast();
  }
}

7-1 图片加载

# 图片缓存 https://github.com/renefloor/flutter_cached_network_image
  cached_network_image: ^1.1.1
  /// 加载本地资源图片
Widget loadAssetImage(String name, {double width, double height, BoxFit fit}){
  return Image.asset(
    Utils.getImgPath(name),
    height: height,
    width: width,
    fit: fit,
  );
}

/// 加载网络图片
Widget loadNetworkImage(String imageUrl, {String placeholder : "none", double width, double height, BoxFit fit: BoxFit.cover}){
  return CachedNetworkImage(
    imageUrl: imageUrl == null ? "" : imageUrl,
    placeholder: (context, url) => loadAssetImage(placeholder, height: height, width: width, fit: fit),
    errorWidget: (context, url, error) => loadAssetImage(placeholder, height: height, width: width, fit: fit),
    width: width,
    height: height,
    fit: fit,
  );
}

8.Redux 和 flutter_redux 详解

  • Redux 是一种单向数据流,可以轻松开发,维护和测试应用程序,flutter_redux是用来简化redux的使用
  • 在Redux中,所用的状态都储存在Store里,这个Store会放在App顶层
  • View拿到Store储存的状态并把它映射成视图
  • Redux让我们不能让View直接操作数据,而是通过发起一个action来告诉Reducer,状态改变
  • 这时Reducer接收到了这个action,他就回去遍历action 表然后找到匹配的action, 根据action生成新的状态放在Store中
  • Store丢弃了老的状态对象,储存了新的状态对象后,就通知所有使用到了这个状态的View更新
  • ==能够同步不同View种的状态==

View 发起一个状态改变的action-> Reducer(状态生成器)找到匹配的action, 根据action生成新的状态放在Store中 ->通知所有使用到了这个状态的View更新,进而同步不同View的状态

使用

  • ①添加依赖
  • ②创建State @immutable
  • ③创建action
  • ④创建reducer : 状态生成器,它接收一个我们原来的状态,然后接收一个action,再匹配这个action生成一个新的状态
  • ⑤创建store : 将store储存在应用的入口,并初始化应用状态
  • ⑥将Store放入顶层 : StoreProvider,接收一个store,和child Widget
  • ⑦在子页面中获取Store中的state : StoreConnector能够通过StoreProvider找到顶层的store。而且能够在state发生变化时rebuilt Widget
同步不同View的状态

补充

1.Flutter vs ReactNative 渲染机制

  • RN的效率由于是将View编译成了原生View,效率比HTML5高很多,但它也有效率问题,RN的渲染机制是基于前端框架的考虑,复杂的UI渲染是需要依赖多个view叠加
  • Flutter在渲染技术上,选择了自己实现,直接通过 skia 渲染,有更好的可控性,使用了新的语言Dart,避免了RN的那种通过桥接器与Javascript通讯导致效率低下的问题,性能优于RN.

ReactNative

  • 采用Javascript开发,需学React,成本高
  • 需要JavaScript桥接器,实现JS到Native转化,性能耗损
  • 访问原生UI,频繁操作易出性能问题
  • 支持线上动态性,可有效避免频繁更新版本

Flutter

  • 采用Dart开发,可直接编译成Native代码(易学)
  • 自带UI组件和渲染器,仅依赖系统提供的Canvas(无桥接耗损)
  • 暂不支持线上动态性,目前Android支持,ios不支持

2.setState方法是立即生效吗?

setState 其实是调用了 markNeedsBuild ,该方法内部标记此Element 为 Dirty ,然后在下一帧 WidgetsBinding.drawFrame 才会被绘制,这可以看出 setState 并不是立即生效的

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