alibaba / fish-redux

An assembled flutter application framework.
https://github.com/alibaba/fish-redux
Apache License 2.0
7.33k stars 843 forks source link

大家如何优雅实现:输入框的清除按钮在有内容才显示啊?类似于MVVM #578

Open jol5 opened 4 years ago

jol5 commented 4 years ago

目前,我想到的就是利用 输入框的 onChange了,如此,又要走一遍fish_redux的Action,好麻烦啊;有没有类似于MVVM一样,Text改变后,自动更新使用了该值的Widget啊?

如: Offstage( offstage: state.usernameController.text.length<=0, child:Icon(....) .....

jing-pei commented 4 years ago

我的建议:封装成一个独立的widget,在框架内调用。不是一切都必须要使用fish-redux,切勿迷信

import 'package:flutter/material.dart';
import 'package:dudulive/global/constants/asset.dart';

typedef OnSearch(String value);

class SearchInputWidget extends StatefulWidget {
  final OnSearch onSearch;

  /// 前缀小玩意儿
  final Widget prefixWidget;

  final Widget suffixWidget;

  final double radius;
  final double boxHeight;

  /// 资源由外部传入,保证独立
  final String inputClearIcon;

  const SearchInputWidget(
      {Key key,
      this.prefixWidget,
      this.suffixWidget,
      this.onSearch,
      this.radius = 16,
      this.boxHeight = 34,
      this.inputClearIcon})
      : super(key: key);

  @override
  _SearchInputWidgetState createState() => _SearchInputWidgetState();
}

class _SearchInputWidgetState extends State<SearchInputWidget> {
  TextEditingController _searchCtrl;

  @override
  Widget build(BuildContext context) {
    final radius = Radius.circular(widget.radius);

    return Container(
      decoration: BoxDecoration(
        borderRadius: BorderRadius.all(radius),
        color: Colors.white,
      ),
      constraints: BoxConstraints(maxHeight: widget.boxHeight),
      child: Row(
        children: <Widget>[
          widget.prefixWidget ?? Container(),
          Padding(
            padding: const EdgeInsets.only(right: 8),
            child: VerticalDivider(
              color: Color(0xFFEEEEEE),
              width: 1,
              thickness: 1,
              indent: 8,
              endIndent: 8,
            ),
          ),
          Expanded(
              child: TextField(
            maxLines: 1,
            controller: _searchCtrl,
            autocorrect: false,
            textInputAction: TextInputAction.search,
            style: TextStyle(fontSize: 14.0),
            decoration: InputDecoration(
              border: InputBorder.none,
              enabledBorder: InputBorder.none,
              disabledBorder: InputBorder.none,
              errorBorder: InputBorder.none,
              isDense: true,
              hintText: '请输入关键字',
              hintStyle: TextStyle(
                  fontSize: 12.0,
                  color: Color(0xFFBDBDBD),
                  fontFamily: 'PingFang-SC-Medium'),
              fillColor: Colors.white,
            ),
            cursorColor: Color(0xFFFF7043),
            autofocus: true,
            onSubmitted: widget.onSearch,
            onChanged: (value) => setState(() {}),
          )),
          _searchCtrl.value.text.length > 0
              ? IconButton(
                  icon: Image.asset(
                    widget.inputClearIcon,
                    width: 10,
                    height: 10,
                  ),
                  onPressed: () {
                    _searchCtrl.clear();
                    setState(() {});
                  })
              : Container(),
          widget.suffixWidget ?? Container(),
        ],
      ),
    );
  }

  @override
  void initState() {
    super.initState();
    _searchCtrl = TextEditingController();
  }

  @override
  void dispose() {
    _searchCtrl.dispose();
    _searchCtrl = null;

    super.dispose();
  }
}
jol5 commented 4 years ago

我的建议:封装成一个独立的widget,在框架内调用。不是一切都必须要使用fish-redux,切勿迷信

import 'package:flutter/material.dart';
import 'package:dudulive/global/constants/asset.dart';

typedef OnSearch(String value);

class SearchInputWidget extends StatefulWidget {
  final OnSearch onSearch;

  /// 前缀小玩意儿
  final Widget prefixWidget;

  final Widget suffixWidget;

  final double radius;
  final double boxHeight;

  /// 资源由外部传入,保证独立
  final String inputClearIcon;

  const SearchInputWidget(
      {Key key,
      this.prefixWidget,
      this.suffixWidget,
      this.onSearch,
      this.radius = 16,
      this.boxHeight = 34,
      this.inputClearIcon})
      : super(key: key);

  @override
  _SearchInputWidgetState createState() => _SearchInputWidgetState();
}

class _SearchInputWidgetState extends State<SearchInputWidget> {
  TextEditingController _searchCtrl;

  @override
  Widget build(BuildContext context) {
    final radius = Radius.circular(widget.radius);

    return Container(
      decoration: BoxDecoration(
        borderRadius: BorderRadius.all(radius),
        color: Colors.white,
      ),
      constraints: BoxConstraints(maxHeight: widget.boxHeight),
      child: Row(
        children: <Widget>[
          widget.prefixWidget ?? Container(),
          Padding(
            padding: const EdgeInsets.only(right: 8),
            child: VerticalDivider(
              color: Color(0xFFEEEEEE),
              width: 1,
              thickness: 1,
              indent: 8,
              endIndent: 8,
            ),
          ),
          Expanded(
              child: TextField(
            maxLines: 1,
            controller: _searchCtrl,
            autocorrect: false,
            textInputAction: TextInputAction.search,
            style: TextStyle(fontSize: 14.0),
            decoration: InputDecoration(
              border: InputBorder.none,
              enabledBorder: InputBorder.none,
              disabledBorder: InputBorder.none,
              errorBorder: InputBorder.none,
              isDense: true,
              hintText: '请输入关键字',
              hintStyle: TextStyle(
                  fontSize: 12.0,
                  color: Color(0xFFBDBDBD),
                  fontFamily: 'PingFang-SC-Medium'),
              fillColor: Colors.white,
            ),
            cursorColor: Color(0xFFFF7043),
            autofocus: true,
            onSubmitted: widget.onSearch,
            onChanged: (value) => setState(() {}),
          )),
          _searchCtrl.value.text.length > 0
              ? IconButton(
                  icon: Image.asset(
                    widget.inputClearIcon,
                    width: 10,
                    height: 10,
                  ),
                  onPressed: () {
                    _searchCtrl.clear();
                    setState(() {});
                  })
              : Container(),
          widget.suffixWidget ?? Container(),
        ],
      ),
    );
  }

  @override
  void initState() {
    super.initState();
    _searchCtrl = TextEditingController();
  }

  @override
  void dispose() {
    _searchCtrl.dispose();
    _searchCtrl = null;

    super.dispose();
  }
}

兄弟说的好啊!确实,这种还是不能都用fish,被困住了。我都换provider了,虽然fish理念是很不错。

jing-pei commented 4 years ago

合理的使用GlobalKey也可以达到局部刷新效果:

==== State ====

class NumLoginState implements Cloneable<NumLoginState> {
// 用于控制按钮状态
  GlobalKey<GradientButtonState> gradientButtonKey =
      new GlobalKey<GradientButtonState>();
}

=======Effect=======

void _onChangeLoginBt(Action action, Context<NumLoginState> ctx) {
  String name = ctx.state.phoneController.text;
  String password = ctx.state.passwordController.text;
  if (name.length == 0 || password.length < 6) {
    ctx.state.gradientButtonKey.currentState.onDisabled(true);
  } else {
    ctx.state.gradientButtonKey.currentState.onDisabled(false);
  }
}

=====StatefulWidget=====

class GradientButton extends StatefulWidget {
  GradientButton({
    Key key}): super(key: key);

  @override
  GradientButtonState createState() => GradientButtonState(disabled);
}

class GradientButtonState extends State<GradientButton> {
  GradientButtonState(this._disabled);

  bool _disabled = false;

  void onDisabled(bool disabled) {
    if (disabled != _disabled) {
      setState(() {
        _disabled = disabled;
      });
    }
  }
  @override
  Widget build(BuildContext context) {
  // 使用_disabled
   }
}