Flutter开发中使用fish_redux怎样在页面中创建TabController呢?

目前 Flutter 开发中,没有像 Android 那么好的生态,开发框架也没有 Android 那样的 mvc、mvp、mvvm 那么成熟,目前 Flutter 开发使用的框架,更多的说的是状态管理。
目前 Flutter 成熟的状态管理有如下几种:

  1. scope_model (provider) : Google 原生的状态管理,通过封装 InheritedWidget 实现了状态管理,而且一并提现 Google 的设计思想,单一原则,这个 Package 仅仅作为状态管理来用,几乎没有学习成本,如果是小型项目使用,只用 Scoped_model 来做状态管理,无疑是非常好的选择,但是越大的项目,使用 scoped_model 来做状态管理,会有点力不从心。
  2. bloc : 早期比较流行的一个状态管理(其实现在也依旧很流行),它能够很好地支持 Stream 方式,学习成本相对较高,不过大小项目皆宜。
  3. redux : 很好用的一个状态管理,学习成本较低,和前端框架的 redux 使用方式相似,如果是前端同学迁移到 Flutter,这个状态管理框架会是一个很好的学习入门方式。
  4. fish_redux : fish_redux 是基于 redux 封装的,不仅仅能够满足状态管理,更是集成了配置式的组装项目,Page 组装,Component 实现,非常干净,易于维护,易于协作,将集中、分治、复用、隔离做的更进一步,缺点就是代码量的急剧增大(而且是非常非常非常急剧增大);

fish_redux : 记录各个模块的用途和用法,通常一个 page (component) 是由以下几个模块组成的:

  1. action : 用来定义在这个页面中发生的动作,同时也可以通过 payload 参数传值,传递一些不能通过 state 传递的值。
  2. effect : 用来处理副作用操作的,比如:显示弹窗、网络请求等操作。它接收来自 View 的“意图”,也包括对应的生命周期的回调,它的处理可能是一个异步函数,数据可能在过程中被修改,所以这里不建议持有数据,而通过上下文来获取最新数据。effect 不修改数据,如果修改,应该发一个 Action 到 Reducer 里去处理。
  3. page : 用来路由注册,同时完成注册 effect、reducer、component、adapter 的功能。
  4. reducer : 用来更新 view ,即直接操作 view 状态。
  5. state : 用来定义页面中的数据,保存页面状态和数据。
  6. view : 用来展示给用户看到的页面。
    在这里插入图片描述

项目结构就如上图所示,每一个页面都需要很多文件。哈哈哈哈!!!

上面只是用来简单记录一下,回归正题,在使用 fish_redux 开发时,遇到一个小问题,在页面中怎样创建 TabController 呢?
不使用 fish_redux 时,我们通常是这么做的,代码如下:

class _HomePageState extends State<TestPage> with SingleTickerProviderStateMixin {
  ScrollController _scrollViewController;
  TabController _tabController;

  @override
  void initState() {
    super.initState();
    _scrollViewController = ScrollController(initialScrollOffset: 0.0);
    _tabController = TabController(vsync: this, length: 3);
  }

  @override
  void dispose() {
    super.dispose();
    _scrollViewController.dispose();
    _tabController.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        elevation: 0.0,
        title: Text("首页"),
      ),
      body: NestedScrollView(
        controller: _scrollViewController,
        headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
          return <Widget>[
            SliverAppBar(
              pinned: true,
              floating: true,
              expandedHeight: 280,
              ... 省略部分代码 ...
              bottom: TabBar(controller: _tabController, tabs: [
                Tab(text: "aaa"),
                Tab(text: "bbb"),
                Tab(text: "ccc"),
              ]),
            )
          ];
        },
        body: TabBarView(controller: _tabController, children: [
          _buildListView("aaa:"),
          _buildListView("bbb:"),
          _buildListView("ccc:"),
        ]),
      ),
    );
  }

initState() 中创建 TabController ,并在 dispose() 中释放。
上面的代码在创建 TabController 时,构造方法中传入了一个 this,即我们在创建 TabController 时,需要传入 TickerProvider ,那么这个 TickerProvider 是哪里来的呢?

	// 我们在构建这个页面时,该页面混入了其它的功能,即 with 后的 SingleTickerProviderStateMixin
	// SingleTickerProviderStateMixin 实现了 TickerProvider,所以我们在构建 TabController 时传 this 即可
	class _HomePageState extends State<TestPage> with SingleTickerProviderStateMixin {}

插入一个知识点,Dart 语言中 with 的含义:
with 表示 mixins (混入),就是在类中混入其他功能。
使用 mixins 可以实现类似于多继承的功能。mixins 和接口完全不一样,是一个全新的特性。

  1. mixins 只能继承 Object
  2. mixins 没有构造函数
  3. mixins 和接口实现一样可以在 with 后面使用多个 mixins,用逗号隔开

那么,使用 fish_redux 时,由于我们在构建一个页面时,要按照上图所示的结构,即 view 中构建需要展示给用户的界面,代码如下所示:

	/// 首页
	Widget buildView(SettingState state, Dispatch dispatch, ViewService viewService) {
  		return Scaffold(
   			backgroundColor: colorGeneration(),
    		body: Center(
      			child: Text('首页')
    		),
  		);
	}

很显然这里没有混入 TickerProvider 相关的功能,那么在这个页面中创建 TabController 时传入 this 是会报错的,那么该如何实现呢?
解决步骤如下:
首先,需要创建一个 ComponentState ,代码如下:

	import 'package:fish_redux/fish_redux.dart';
	import '../state.dart';

	/// 创建 TabComponent 继承自 ComponentState
	class TabComponent extends ComponentState<MineState>
   		 with SingleTickerProviderStateMixin {
	}

其次在 page 页面重写 createState( ) 方法,并创建 TabComponent ,代码如下:

import 'package:fish_redux/fish_redux.dart';

import 'components/mine_tab_component.dart';
import 'effect.dart';
import 'reducer.dart';
import 'state.dart';
import 'view.dart';

class MinePage extends Page<MineState, Map<String, dynamic>> {
  MinePage()
      : super(
            initState: initState,
            effect: buildEffect(),
            reducer: buildReducer(),
            view: buildView,
            dependencies: Dependencies<MineState>(
                adapter: null,
                slots: <String, Dependent<MineState>>{
                }),
            middleware: <Middleware<MineState>>[
            ],);

  @override
  ComponentState<MineState> createState() {
  	// 创建 TabComponent
    return TabComponent();
  }
}

然后在 effect 中,构建并初始化 TabController,然后赋值给 state 中的 tabController,代码如下:

import 'package:fish_redux/fish_redux.dart';
import 'action.dart';
import 'state.dart';

Effect<MineState> buildEffect() {
  return combineEffects(<Object, Effect<MineState>>{
    Lifecycle.initState: _initController,
  });
}

/// 初始化 TabController
void _initController(Action action, Context<MineState> ctx) {
  // 获取到 TickerProvider
  final TickerProvider tickerProvider = ctx.stfState as TickerProvider;
  // 创建 TabController
  var _controller = TabController(vsync: tickerProvider, length: ctx.state.tabList.length);
  // 赋值给 state 中的 tabController
  ctx.state.tabController = _controller;
}

fish_redux 中的 Lifecycle 生命周期是跟 Flutter 中的生命周期是对应的,页面这里初始化的一些资源,在该页面销毁之前都是有效的。

state 中的代码如下所示:

import 'package:fish_redux/fish_redux.dart';

class MineState implements Cloneable<MineState> {
  int tabIndex = 0; // 当前选中的tab索引
  List<String> tabList = ["AAA", "BBB", "CCC"]; // tabs list
  TabController tabController;  // TabController

  @override
  MineState clone() {
    return MineState()
      ..tabIndex = tabIndex
      ..tabList = tabList
      ..tabController = tabController;
  }
}

MineState initState(Map<String, dynamic> args) {
  return MineState();
}

最后,在 view 中就可以直接使用 state.tabController,代码如下所示:

Widget buildView(MineState state, Dispatch dispatch, ViewService viewService) {
  _tabIndex = state.tabIndex;

  return Scaffold(
    backgroundColor: Color(0xFFFFFFFF),
    body: extended.NestedScrollView(
      headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
        return <Widget>[
          SliverAppBar(
            pinned: true,
            floating: true,
            expandedHeight: 800.0,
            ... 省略部分代码 ...
            bottom: TabBar(controller: state.tabController, tabs: [
              Tab(child: Text("AAA")),
              Tab(child: Text("BBB")),
              Tab(child: Text("CCC")),
            ]),
          ),
        ];
      },
      body: TabBarView(controller: state.tabController, children: [
        _buildListView("aaa:"),
        _buildListView("bbb:"),
        _buildListView("ccc:"),
      ]),
    ),
  );
}

OK啦!!!大功告成,去实现并测试一下吧!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值