MouseTracker 不再附加注释

概述

Summary

MouseTracker 的方法 attachAnnotationdetachAnnotationisAnnotationAttached 已被移除。

Removed MouseTracker’s methods attachAnnotation, detachAnnotation, and isAnnotationAttached.

上下文

Context

在渲染阶段,通过在感兴趣区域上放置 MouseTrackerAnnotation 可以检测鼠标事件,例如鼠标指针进入、退出或悬停在区域上。每次更新(一个新的帧或事件)时, MouseTracker 会比较更新前后鼠标指针悬停的注释,然后执行相应的回调。

Mouse events, such as when a mouse pointer has entered a region, exited, or is hovering over a region, are detected with the help of MouseTrackerAnnotations that are placed on interested regions during the render phase. Upon each update (a new frame or a new event), MouseTracker compares the annotations hovered by the mouse pointer before and after the update, then dispatches callbacks accordingly.

MouseTracker 类管理鼠标指针的状态,要求 MouseRegion 在挂载(mounted)时附加注释,在移除(unmounted)时分离注释。MouseTracker 使用它来执行 挂载退出检查。(例如,如果是因移除 widget 引起的退出,则不调用 MouseRegion.onExit),防止移除 widget 时调用 setState 引发的异常(详情可见 Issue #44631)。

The MouseTracker class, which manages the state of mouse pointers, used to require MouseRegion to attach annotations when mounted, and detach annotations when unmounted. This was used by MouseTracker to perform the mounted-exit check (for example, MouseRegion.onExit must not be called if the exit was caused by the unmounting of the widget), in order to prevent calling setState of an unmounted widget and throwing exceptions (explained in detail in Issue #44631).

这种机制已经被 MouseRegion 变为一个有状态的 widget 所取代,它可以通过在卸载时阻止回调来自行执行挂载退出检查。因此,这些方法已被删除,MouseTracker 不再跟踪屏幕上的所有注释。

This mechanism has been replaced by making MouseRegion a stateful widget, so that it can perform the mounted-exit check by itself by blocking the callback when unmounted. Therefore, these methods have been removed, and MouseTracker no longer tracks all annotations on the screen.

更改描述

Description of change

MouseTracker 类删除了三个与附加注释相关的方法:

The MouseTracker class has removed three methods related to attaching annotations:

 class MouseTracker extends ChangeNotifier {
   // ...
-  void attachAnnotation(MouseTrackerAnnotation annotation) {/* ... */}

-  void detachAnnotation(MouseTrackerAnnotation annotation) {/* ... */}

-  @visibleForTesting
-  bool isAnnotationAttached(MouseTrackerAnnotation annotation) {/* ... */}
 }

RenderMouseRegionMouseTrackerAnnotation 不再执行挂载退出检查,在 MouseRegion 中仍然执行。

RenderMouseRegion and MouseTrackerAnnotation no longer perform the mounted-exit check, while MouseRegion still does.

迁移指南

Migration guide

删除 MouseTracker.attachAnnotationdetachAnnotation 的调用,这几乎没有影响:

Calls to MouseTracker.attachAnnotation and detachAnnotation should be removed with little to no impact:

  • MouseRegion 的使用应该完全不受影响。

    Uses of MouseRegion should not be affected at all.

  • 如果你的代码直接使用 RenderMouseRegionMouseTrackerAnnotation,请注意现在 onExit 的回调会在 MouseTracker.detachAnnotation 事件引起的退出时触发。如果不涉及任何状态,应该不会有问题,否则你可能希望添加挂载的退出检查,尤其是在回调泄漏时,以便外部 widget 可以调用 setState。例如:

    If your code directly uses RenderMouseRegion or MouseTrackerAnnotation, be aware that onExit is now called when the exit is caused by events that used to call MouseTracker.detachAnnotation. This should not be a problem if no states are involved, otherwise you might want to add the mounted-exit check, especially if the callback is leaked so that outer widgets might call setState in it. For example:

迁移前的代码:

Code before migration:

class MyMouseRegion extends SingleChildRenderObjectWidget {
  const MyMouseRegion({this.onHoverChange});

  final ValueChanged<bool> onHoverChange;

  @override
  RenderMouseRegion createRenderObject(BuildContext context) {
    return RenderMouseRegion(
      onEnter: (_) { onHoverChange(true); },
      onExit: (_) { onHoverChange(false); },
    );
  }

  @override
  void updateRenderObject(BuildContext context, RenderMouseRegion renderObject) {
    renderObject
      ..onEnter = (_) { onHoverChange(true); }
      ..onExit = (_) { onHoverChange(false); };
  }
}

迁移后的代码:

Code after migration:

class MyMouseRegion extends SingleChildRenderObjectWidget {
  const MyMouseRegion({this.onHoverChange});

  final ValueChanged<bool> onHoverChange;

  @override
  RenderMouseRegion createRenderObject(BuildContext context) {
    return RenderMouseRegion(
      onEnter: (_) { onHoverChange(true); },
      onExit: (_) { onHoverChange(false); },
    );
  }

  @override
  void updateRenderObject(BuildContext context, RenderMouseRegion renderObject) {
    renderObject
      ..onEnter = (_) { onHoverChange(true); }
      ..onExit = (_) { onHoverChange(false); };
  }

  @override
  void didUnmountRenderObject(RenderMouseRegion renderObject) {
    renderObject
      ..onExit = onHoverChange == null ? null : (_) {};
  }
}

必须删除 MouseTracker.isAnnotationAttached 的调用。由于注释不再被跟踪,因此该功能在技术上不再可行。如果你需要此功能,请提交 issue。

Calls to MouseTracker.isAnnotationAttached must be removed. This feature is no longer technically possible, since annotations are no longer tracked. If you somehow need this feature, please submit an issue.

时间轴

Timeline

发布于版本:1.15.4
发布于稳定版本:1.17

Landed in version: 1.15.4
In stable release: 1.17

参考文献

References

API 文档:

API documentation:

相关 PR:

Relevant PRs: