You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter报错:notifyListeners仅能在ChangeNotifier子类实例成员中使用

解决Flutter中TransformationController.notifyListeners()调用报错问题

你遇到的错误是因为notifyListeners()是ChangeNotifier类的受保护方法,只能在它的子类内部调用,无法从外部直接触发。TransformationController作为ChangeNotifier的子类,外部代码无权直接调用这个方法。

解决方法

推荐方案:通过修改controller的value触发自动通知

TransformationController的状态更新依赖其value属性,当你修改value时,它会自动调用内部的notifyListeners()通知所有监听者。如果你的场景只是需要触发界面更新、没有实际修改矩阵,可以通过克隆当前value并重新赋值的方式触发更新:

// 替换报错的transformationController.notifyListeners()这一行
transformationController.value = transformationController.value.clone();

这种方式既遵守了类的封装规则,又能触发所有依赖该controller的界面组件更新。

备选方案:自定义子类暴露notifyListeners(不推荐)

如果确实需要手动触发通知,可以创建自定义的TransformationController子类,把notifyListeners方法暴露出来,但这种做法会破坏类的封装性,仅在特殊场景下使用:

class CustomTransformationController extends TransformationController {
  @override
  void notifyListeners() {
    super.notifyListeners();
  }
}

之后将你的transformationController替换为这个自定义类的实例,就能在外部调用notifyListeners()了。

为什么setState无效?

你之前用setState没效果,是因为界面中依赖TransformationController的组件(比如InteractiveViewer)是监听controller的状态变化,而非Widget自身的state。setState只能刷新当前Widget树中依赖state的部分,无法触发依赖controller的组件更新。

修改后的完整代码示例

void _addButton(LongPressStartDetails details) async {
  setState(() {
    animatedIndex = chips.length;
    final chipEntry = ChipEntry(offset: transformationController.toScene(details.localPosition));
    marker = chipEntry;
    chips = [marker];
    labelNumber++;
  });
  await controller.forward(from: 0.0);
  animatedIndex = -1;
  // 替换报错行的代码
  transformationController.value = transformationController.value.clone();
  SharedPreferences prefs = await SharedPreferences.getInstance();
  double encodedX = marker.offset.dx;
  double encodedY = marker.offset.dy;
  prefs.setDouble('chipx', encodedX);
  prefs.setDouble('chipy', encodedY);
}

内容的提问来源于stack exchange,提问作者Mat Koffman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 11:40:07