Flutter-总结

作者: StevenHu_Sir | 来源:发表于2019-08-15 13:13 被阅读0次

简介

谷歌开发的,有自己的渲染引擎,保持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 并不是立即生效的

相关文章

网友评论

    本文标题:Flutter-总结

    本文链接:https://www.haomeiwen.com/subject/ueqzjctx.html