Flutter入门《Fish-Redux》一

2020-10-23  本文已影响0人  馒Care

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里面有如下几个入参:

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;
}
enum AutoAction { Login }

class AutoActionCreator {
   static Action onLogin(String type) {
    return Action(AutoAction.Login, payload: type);
  }
}

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) {}
    });
}

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中间吧。未完待续

上一篇下一篇

猜你喜欢

热点阅读