创建自定义Controller

56 阅读2分钟

你可能用过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中。