美文网首页
Flutter入门《Fish-Redux》一

Flutter入门《Fish-Redux》一

作者: 馒Care | 来源:发表于2020-10-23 16:51 被阅读0次

    Fish-Redux 官方README

    Fish-Redux结构初始

    1.工程结构


    fish结构.png

    2.工程初始
    整个fish-redux的简单页面包括如下几个

    Fish-Redux项目结构如何运行

    根据上面对工程结构的初步认识,简单理解咸鱼的这个框架就是
    1.创建页面的时候,所有页面的入口都再Page,类似Android里面的Activity

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

    Page里面有如下几个入参:

    • initState 初始化所有的State属性,如:
    class AutoState implements Cloneable<AutoState> {
      var telTextEditingController = TextEditingController();
      var autoCodeTextEditingController = TextEditingController();
      var autoCodeFocusNode = new FocusNode();
      var isCheckOK;
    ///必须要实现clone,这个是咸鱼的框架设定
      @override
      AutoState clone() {
        return AutoState()
          ..telTextEditingController = telTextEditingController
          ..autoCodeTextEditingController = autoCodeTextEditingController
          ..autoCodeFocusNode = autoCodeFocusNode
          ..isCheckOK = isCheckOK;
      }
    }
    ///初始化所有需要用到的属性
    AutoState initState(Map<String, dynamic> args) {
      return AutoState()
        ..telTextEditingController = TextEditingController()
        ..autoCodeTextEditingController = TextEditingController()
        ..autoCodeFocusNode = new FocusNode()
        ..isCheckOK = false;
    }
    
    • action 类似Android声明的接口内部方法,并不会实现具体业务,需要跟Effect结合使用,如
    enum AutoAction { Login }
    
    class AutoActionCreator {
       static Action onLogin(String type) {
        return Action(AutoAction.Login, payload: type);
      }
    }
    
    
    • effect 实现所有具体声明的方法,类似Android声明接口后,需要实现当前接口,操作具体业务逻辑,如:
    Effect<PassWordState> buildEffect() {
      return combineEffects(<Object, Effect<PassWordState>>{
       ///PassWordAction.action 类似Android定义的接口方法名
    ///_onAction 类似Android接口实现的具体方法
        PassWordAction.Login: _onLogin,
      });
    }
    
    Future _onLogin(Action action, Context<PassWordState> ctx) async {
      Result<LoginRespEntity> result;
      //第三方登录的参数
      if (action.payload == "qq" || action.payload == "wechat") {
      } else {
        var loginReqUserEntity = LoginReqUserEntity()
          ..loginName = ctx.state.controllerForAccount.text
          ..password = ctx.state.controllerForPsd.text
          ..organizeType = -1;
        result = await VvRequestClient.request<LoginRespEntity>(
            ctx.context, LoginApiService.NORMAL_HOST + LoginApiService.LOGINURL,
            queryParameters: loginReqUserEntity.toJson(),
            showLoadingIndicator: true);
      }
      result
        ..yes((value) {
          showToast(value.userCode);
          log('userCode${value.userCode}');
        })
        ..no((err) {
          log('err${err.toString()}');
          if (err.code == ErrorCode.BIND_TEL_ERROR_CODE) {}
        });
    }
    
    • reducer 通过学习发现,Effect主要用来触发action传递过来的事件,执行类似网络请求等业务,而reducer更偏向是执行了业务之后,需要更新State属性,进而刷新UI使用的

    • view 比较简单,就是写UI的地方了,如

    
    Widget buildView(AutoState state, Dispatch dispatch, ViewService viewService) {
      var themeData = Theme.of(viewService.context);
      return Scaffold(
        appBar: Toolbar(),
        body: GestureDetector(
          behavior: HitTestBehavior.opaque,
          onTap: () {
            KeyboardUtils.hide();
          },
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: <Widget>[
    
              Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  Padding(
                    padding:
                        const EdgeInsets.only(left: 37.0, top: 52.0, bottom: 50.0),
                    child: Text(
                      "手机号码登录",
                      style: TextStyle(fontSize: 18.0, color: color343434),
                    ),
                  ),
                  Padding(
                    padding: const EdgeInsets.only(left: 38.0, right: 38.0),
                    child: TextField(
    //                    autofocus: true,
                        keyboardType: TextInputType.phone,
                        controller: state.telTextEditingController,
                        decoration: InputDecoration(
                            enabledBorder: UnderlineInputBorder(
                              borderSide: BorderSide(color: colore3e3e3),
                            ),
                            focusedBorder: UnderlineInputBorder(
                              borderSide: BorderSide(
                                  width: 2.0, color: themeData.accentColor),
                            ),
                            contentPadding: EdgeInsets.only(
                                left: 20.0, right: 20.0, top: 20.0, bottom: 10.0),
                            hintText: "请输入手机号",
                            hintStyle: TextStyle(
                                color: colorA4A4A4,
                                fontSize: 12.0,
                                fontWeight: FontWeight.w300)),
                        maxLength: 11,
                        buildCounter: (BuildContext context,
                                {int currentLength,
                                int maxLength,
                                bool isFocused}) =>
                            null,
                        style:
                            TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold)),
                  ),
                  Padding(
                    padding: const EdgeInsets.only(left: 38.0, right: 38.0),
                    child: TextFormField(
                        focusNode: state.autoCodeFocusNode,
                        keyboardType: TextInputType.phone,
                        controller: state.autoCodeTextEditingController,
                        decoration: InputDecoration(
                            enabledBorder: UnderlineInputBorder(
                              borderSide: BorderSide(color: colore3e3e3),
                            ),
                            focusedBorder: UnderlineInputBorder(
                              borderSide: BorderSide(
                                  width: 2.0, color: themeData.accentColor),
                            ),
                            suffixIcon: CountDownButton(
                              CompleterUtils.produceCompleterAction(
                                  dispatch, AutoActionCreator.onSendAutoCode),
                              state: state.telTextEditingController.text.length ==
                                      11 //小于11位不能点击
                                  ? 1
                                  : 0,
                            ),
                            contentPadding: EdgeInsets.only(
                                left: 20.0, right: 20.0, top: 20.0, bottom: 10.0),
                            hintText: "请输入验证码",
                            hintStyle: TextStyle(
                                color: colorA4A4A4,
                                fontSize: 12.0,
                                fontWeight: FontWeight.w300)),
                        maxLength: 6,
                        buildCounter: (BuildContext context,
                                {int currentLength,
                                int maxLength,
                                bool isFocused}) =>
                            null,
                        style:
                            TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold)),
                  ),
                  Container(
                    width: WindowUtils.getScreenWidth() - 38 * 2,
                    height: 45.0,
                    margin: const EdgeInsets.only(top: 22.0, left: 38, right: 38),
                    child: RaisedButton(
                      elevation: 0.0,
                      color: state.isCheckOK ? themeData.accentColor : colorE4E4E4,
                      shape: new RoundedRectangleBorder(
                          borderRadius: new BorderRadius.circular(22.0)),
                      child: Text("立即登录s"),
                      textColor: colorWhite,
                      onPressed: () {
                        if(state.isCheckOK){
                          dispatch(AutoActionCreator.onLogin("tel"));
                        }else{
                          showToast("widget");
                        }
    
                      },
                    ),
                  ),
                ],
              ),
              Stack(
                alignment: Alignment.bottomCenter,
                children: <Widget>[
                  Image.asset(
                    'assets/auto_page_bg.png',
                    fit: BoxFit.fitWidth,
                    width: WindowUtils.getScreenWidth(),
                  ),
                  Padding(
                    padding: const EdgeInsets.only(bottom: 68.0),
                    child: RichText(
                      text: TextSpan(
                        text: "登录即同意 ",
                        children: [
                          TextSpan(
                            text: "《用户协议》",
                            recognizer: TapGestureRecognizer()
                              ..onTap = () {
                                NavigatorHelper.pushWebPage(
                                    viewService.context,
                                    "用户协议",
                                    "https://blog.csdn.net/yuzhiqiang_1993/article/details/88204031");
                              },
                            style: TextStyle(fontSize: 12.0, color: colorFF6000),
                          ),
                          TextSpan(
                            text: "和",
                            style: TextStyle(fontSize: 12.0),
                          ),
                          TextSpan(
                            text: "《隐私政策》",
                            recognizer: TapGestureRecognizer()
                              ..onTap = () {
                                NavigatorHelper.pushWebPage(
                                    viewService.context,
                                    "隐私政策",
                                    "${HttpConstants.BaseUrl}/assets/protocol.html");
                              },
                            style: TextStyle(fontSize: 12.0, color: colorFF6000),
                          ),
                        ],
                        style: TextStyle(fontSize: 12.0, color: color343434),
                      ),
                    ),
                  ),
                  Padding(
                    padding: const EdgeInsets.only(bottom: 138.0),
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceAround,
                      children: <Widget>[
                        Column(
                          children: <Widget>[
                            IconButton(
                              onPressed: () {
                                dispatch(AutoActionCreator.onLogin('qq'));
                              },
                              icon: Image.asset("assets/qq.png"),
                            ),
                            Text("QQ")
                          ],
                        ),
                        Column(
                          children: <Widget>[
                            IconButton(
                              onPressed: () {
                                dispatch(AutoActionCreator.onLogin('wechat'));
                              },
                              icon: Image.asset("assets/wechat.png"),
                            ),
                            Text("微信")
                          ],
                        ),
                      ],
                    ),
                  )
                ],
              )
            ],
          ),
        ),
      );
    }
    

    着重注意下 controller: state.autoCodeTextEditingController,这句代码,controller是输入框的一个监听器。类似Android的onTextChangeListener。代码也可以看到,是通过state来调用的。这个state就是,我们刚才说的,需要声明的变量。
    同时,也注意这句:ctx.state.controllerForAccount.text
    在effect里面执行具体业务操作,例如登录,需要获取输入框的账号密码,也是通过state.xxx来获取

    总结

    构建Page--》绘制View---》声明state属性--》声明/执行(dispatch)Action方法--》在Effect实现具体方法--》》刷新state--》更新View UI

    Fish-Redux框架相对复杂,不适合初识Flutter的开发者,但是,也建议初学者尝试使用这个框架,因为这个框架把每个层次都相对合理的分层了。不至于耦合度太高。相信,很多人开始写的时候都是类似MVC的方式。Fish-Redux给我感觉,可能会介于MVP/MVVM中间吧。未完待续

    相关文章

      网友评论

          本文标题:Flutter入门《Fish-Redux》一

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