Flutter 入门笔记(Part 9) 进阶一

3 . Flutter中复用原生控件

  • 除去地图、WebView、相机等涉及底层方案的特殊情况外,大部分原生代码能够实现的 UI 效果,完全可以用 Flutter 实现.

  • 使用这种方式对性能造成非常大的影响且不方便维护.

  • 方法通道: 原生逻辑复用

  • 平台视图: 原生视图复用

    4 . Android项目中嵌入Flutter

❝ 官网地址: https://flutter.dev/docs/development/add-to-app

  • FlutterEngine 文档: https://github.com/flutter/flutter/wiki/Experimental:-Reuse-FlutterEngine-across-screens

  • FlutterView 文档: https://github.com/flutter/flutter/wiki/Experimental:-Add-Flutter-View

  • API一会儿就过时了,得去官网看最新的才行.

  • 可以在Android App中开启Flutter的Activity,Flutter的Activity是在另外一个进程,第一次进入特别慢.也可以加入Flutter的View和Fragment

  • 在Android工程下新建一个Flutter的module比较简单直接

    5 . 混合开发导航栈

  • Android跳转Flutter,依赖FlutterView.Flutter在FlutterView中建立了自己的导航栈.

  • 通常会将Flutter容器封装成一个独立的Activity或者ViewController. 这样打开一个普通的Activity既是打开Flutter界面了

  • Flutter页面跳转原生界面,需要利用方法通道,然后用原生去打开响应的界面.

  • Flutter实例化成本非常高,每启动一个Flutter实例,就会创建一套新的渲染机制,即Flutter Engine,以及底层的Isolate.而这些实例之间的内存是不相互共享的,会带来较大的系统资源消耗.

  • 实际开发中,尽量用Flutter去开发闭环的业务模块.原生跳转过去就行,剩下的全部由Flutter内部完成. 尽量避免Flutter页面回到原生页面,原生页面又启动新的Flutter实例的情况.

    6 . 状态管理(跨组件传递数据,Provider)

  • Dart的一个库,可以实现在StatelessWidget中刷新数据.跨组件传递数据.全局共享数据.依赖注入

  • 使用Provider后,我们就再也不需要StalefullWidget了.

  • Provider以InheritedWidget语法糖的方法,通过数据资源封装,数据注入,和数据读写这3个步骤,为我们实现了跨组件(跨页面)之间的数据共享

  • 我们既可以用Provider来实现静态的数据读传递,也可以使用ChangeNotifierProvider来实现动态的数据读写传递,还用通过MultiProvider来实现多个数据资源的共享

  • Provider.of和Consumer都可以实现数据的读取,并且Consumer还可以控制UI刷新的粒度,避免与数据无关的组件的无谓刷新

  • 封装数据

//定义需要共享的数据模型,通过混入ChangeNotifier管理听众
class CounterModel with ChangeNotifier {
  int _count = 0;
  //读方法
  int get counter => _count; 
  //写方法
  void increment() {
    _count++;
    notifyListeners();//通知听众刷新
  }
}
  • 放数据
尽量把数据放到更高的层级

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //通过Provider组件封装数据资源
    //因Provider是InheritedWidget的语法糖,所以它是一个Widget
    //ChangeNotifierProvider只能搞一个
    //MultiProvider可以搞多个
    return MultiProvider(
      providers: [
        //注入字体大小  下个界面读出来
        Provider.value(value: 30.0),
        //注入计数器实例
        ChangeNotifierProvider.value(value: CounterModel())
      ],
      child: MaterialApp(
        home: FirstPage(),
      ),
    );
  }
}
  • 读数据
//示例: 读数据
class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //取出资源  类型是CounterModel
    //获取计时器实例
    final _counter = Provider.of<CounterModel>(context);
    //获取字体大小
    final textSize = Provider.of<double>(context);

    /*
    *
//使用Consumer2获取两个数据资源
Consumer2<CounterModel,double>(
  //builder函数以参数的形式提供了数据资源
  builder: (context, CounterModel counter, double textSize, _) => Text(
      'Value: ${counter.counter}',
      style: TextStyle(fontSize: textSize))
)
* 我们最多可以使用到 Consumer6,即共享 6 个数据资源。
    * */

    return Scaffold(
      body: Center(
        child: Text(
          'Counter: ${_counter.counter}',
          style: TextStyle(fontSize: textSize),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: Text('Go'),
        onPressed: () => Navigator.of(context)
            .push(MaterialPageRoute(builder: (context) => SecondPage())),
      ),
    );
  }
}

//示例: 读和写数据
//使用Consumer 可以精准刷新发生变化的Widget
class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //取出数据
    //final _counter = Provider.of<CounterModel>(context);
    return Scaffold(
      //使用Consumer来封装counter的读取
      body: Consumer(
        //builder函数可以直接获取到counter参数
        //Consumer 中的 builder 实际上就是真正刷新 UI 的函数,它接收 3 个参数,即 context、model 和 child
        builder: (context, CounterModel counter, _) => Center(
          child: Text('Value: ${counter.counter}'),
        ),
      ),
      floatingActionButton: Consumer<CounterModel>(
        builder: (context, CounterModel counter, child) => FloatingActionButton(
          onPressed: counter.increment,
          child: child,
        ),
        child: Icon(Icons.add),
      ),
    );
  }
}

7 . 适配不同分辨率的手机屏幕

  • Flutter中平时写控件的尺寸,其实有点类似于Android中的dp
  • 只能是通过MediaQuery.of(context).size.width获得屏幕宽度来加载什么布局
  • 竖屏时用什么布局,横屏时用什么布局.可以根据屏幕宽度才判断.
  • 如需适配空间等的大小,则需要以切图为基准,算出当前设备的缩放系数,在布局的时候乘一下.

手机扫码阅读