你可能用过TextEditingController来控制输入框的各种逻辑。是的,它是Flutter中众多Controller中的一个,用于控制对应Widget中的行为逻辑。如果我们自己写一个自定义组件,也想用一个Controller来控制组件逻辑,那该如何实现?
概述
不管是ListView的ScrollerController,还是TextField的TextEditingController...它们都是继承自ChangeNotifier,在定义StatefulWidget时,定义一个controller属性,用于传入Controller实例。在State中可以直接创建Controller的实例,然后再在build函数中,Widget的实例中传入该Controller实例。
示例
下面有个示例组件包含一个按钮和一个Container,当点击按钮时随机产生一个颜色值,然后将Container的背景色设置为该颜色,且该颜色值也出现在按钮上。
import 'package:counter_2/random_color_container_ctrl.dart';
import 'package:flutter/material.dart';
class RandomColorContainer extends StatefulWidget {
final Color color;
const RandomColorContainer({super.key, required this.color});
@override
State<StatefulWidget> createState() {
return _RandomColorContainerState();
}
}
class _RandomColorContainerState extends State<RandomColorContainer> {
late RandomColorContainerController ctrl;
@override
void initState() {
super.initState();
ctrl = RandomColorContainerController(color: widget.color);
ctrl.addListener(() {
setState(() {});
});
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
color: ctrl.color,
width: 200,
height: 200,
),
const SizedBox(height: 20,),
ElevatedButton(
onPressed: () {
ctrl.updateColor();
},
child: Text(ctrl.color.toString()),
)
],
);
}
}
在initState中,初始化了一个Controller,该Controller用于控制组件的颜色值的产生,而组件负责从Controller中读取颜色值。
import 'dart:math';
import 'package:flutter/material.dart';
class RandomColorContainerController extends ChangeNotifier {
Color _currentColor;
RandomColorContainerController({ Color color = Colors.black }):
_currentColor = color;
set color(Color value) {
if (value != _currentColor) {
_currentColor = value;
notifyListeners();
}
}
Color get color => _currentColor;
updateColor() {
color = Color((Random().nextDouble() * 0xffffff).toInt()).withOpacity(1);
}
}
updateColor方法用于更新颜色值,在组件中直接通过ctrl调用。下面是使用
class HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('appBar'),
),
body: const Center(
child: RandomColorContainer(color: Color.fromRGBO(255, 0, 0, 1),),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
},
child: const Text('click'),
),
);
}
}
实例化RandomColorContainer的时候,我们这里并没有从外面传入Controller实例,而是将实例写到里面了。
总结
当你的组件比较复杂,逻辑比较多的时候,我们可以利用Controller将逻辑跟Widget分离。比如你写一个非常复杂的页面,而页面的逻辑可以单独写到一个Controller中。