背景:在有些项目中,我们经常会碰到,例如登录页面这种有textfield输入框和按钮的,当输入框全部输入了内容后,按钮控件更改可点击背景,置为可点击状态,如果存在一个输入框为输入内容,则更改为不可点击背景,置为不可点击的状态。
思路1:通过TextEditingController的addListener监听中restate(),然后刷新整个页面,这种做法会导致频繁的页面刷新和渲染,对性能很不友好。
思路2:只要能避免restate(),这就不会频繁刷新页面了,这就得用到privider了。核心类ChangeNotifier和ChangeNotifierProvider,可以通过监听控制达到同样效果,而不用频繁restate()。
1、导入privider库
dependencies:
flutter:
sdk: flutter
provider: ^4.3.2
2、新建一个ClickableModel类,继承ChangeNotifier。作为被消费对象
class ClickableModel extends ChangeNotifier {
final List<TextEditingController> _textEditingController;
bool _canClick = false;
bool get isClickable => _canClick;
ClickableModel(this._textEditingController) {
_textEditingController.map((e) {
e.addListener(() {
var strList = List<String>();
for (var item in _textEditingController) {
strList.add(item.text.toString());
}
_canClick = strList.contains('') ? false : true;
//触发消费监听
notifyListeners();
});
}).toList();
}
}
这里最总目的是为了获取是否可点击的状态,所以需要传入所有textfield的control,当每次触发调用当前构造函数时,遍历control获取到所有输入框的内容,如果存在空的,则按钮不可点击,否则是可点击的,每次最后要notifyListeners()。
3、新建消费类,这里为了可公用,封装成泛型
class ConsumeComponent<T extends ChangeNotifier> extends StatefulWidget {
final T model;
final Widget child;
final ValueWidgetBuilder<T> builder;
ConsumeComponent({
Key key,
@required this.model,
@required this.builder,
this.child,
}) : super(key: key);
@override
State<StatefulWidget> createState() => _ConsumeComponentState<T>();
}
class _ConsumeComponentState<T extends ChangeNotifier>
extends State<ConsumeComponent<T>> {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<T>.value(
value: widget.model,
child: Consumer<T>(
child: widget.child,
builder: widget.builder,
),
);
}
}
4、页面的调用
//登录按钮
ConsumeComponent<ClickableModel>(
model: ClickableModel(
[_userNameController, _phoneController, _smsCodeController]),
builder: (context, model, child) => Container(
margin: const EdgeInsets.only(top: 40.0, left: 20, right: 20.0),
child: CommonButton(
text: 'Next',
onPressed: !model.isClickable
? null
: () {
//todo somethings
},
btnColor: model.isClickable ? Colors.blue : Colors.grey,
),
),
),
这里只需要传入一个textfield的control数组就可以了,然后根据监听获取到的可点击状态就可以处理剩下的逻辑了。如果有更好的方式或优化,欢迎留言哈哈哈哈!!!