A brief summary of flutter's event distribution mechanism

We need to understand the main classes of event distribution in Flutter: PointerEvent, HitTestResult, HitTestEntry, RenderObject, and the relationship between them.

1. PointerEvent

PointerEvent is the base class for all events in Flutter. It contains the event type, location, timestamp, device information, etc. Subclasses of PointerEvent include PointerDownEvent, PointerMoveEvent, PointerUpEvent, etc.

2. HitTestResult

HitTestResult is the result of event distribution, which records some information during the event distribution process. There is a _hitTestEntries private variable in HitTestResult, which is a List type and used to store the process of event distribution (ie HitTestEntry).

3. HitTestEntry

HitTestEntry records the process of event distribution, which contains a RenderObject and a BoxHitTestResult. RenderObject represents the rendering object corresponding to the current node in the event distribution process, and BoxHitTestResult contains the position information of this node.

4. RenderObject

RenderObject is the base class of the rendering tree node in Flutter, which contains information such as the position, size, and drawing of the node. Each widget corresponds to a RenderObject, which will be converted to the corresponding RenderObject when rendering.

Next, let's analyze the event distribution process in Flutter in detail.

1. Event generation

The generation of events is usually done by the bottom layer of the system, such as clicking the screen or sliding the mouse. When the system detects an event, it will encapsulate the event into a PointerEvent object and pass it to the Flutter engine.

2. Delivery of events

After the Flutter engine receives the event, it will pass the event to the RenderObject corresponding to the root node, that is, the PipelineOwner. PipelineOwner will create a HitTestResult object to record the result of event distribution.

3. Distribution of events

In the PipelineOwner, the _renderView.hitTest method is called to distribute events to the nodes in the rendering tree. The implementation of the hitTest method is as follows:

void hitTest(HitTestResult result, Offset position) {
  assert(attached);
  final HitTestEntry entry = HitTestEntry(this);
  result.add(entry);
  if (hitTestChildren(result, position)) {
    handleEvent(entry);
  }
}

In this method, a HitTestEntry object is first created and added to HitTestResult to record the distribution result. Then call the hitTestChildren method to pass the event down. If the event is handled, call the handleEvent method to handle the event.

The implementation of the hitTestChildren method is as follows:

bool hitTestChildren(HitTestResult result, Offset position) {
  RenderObject child = lastChild;
  while (child != null) {
    final bool hit = child.hitTest(result, position: position);
    if (hit)
      return true;
    child = childBefore(child);
  }
  return false;
}

In this method, first traverse all child nodes of the current node, call their hitTest method, and pass the event down. Returns true if there is a node handling the event among the child nodes, otherwise returns false.

4. Event handling

When an event arrives at a target node, the node's handleEvent method is called to handle the event. The implementation of the handleEvent method varies depending on the node type. For example, GestureDetector will call onTap, onDoubleTap and other callback functions to handle events, while RenderBox will call the handleEventForBox method to handle events.

The implementation of the handleEventForBox method is as follows:

void handleEventForBox(HitTestEntry entry, PointerEvent event) {
  bool absorbed = hitTestSelf();
  if (!absorbed && size.contains(event.localPosition)) {
    handleEvent(entry, event);
    absorbed = true;
  }
  if (!absorbed)
    absorbPointer(event);
}

In this method, first call the hitTestSelf method to determine whether the node can handle events. If the node cannot handle the event, the absorbPointer method is called to mark the event as handled. If the node can handle the event, call the handleEvent method to handle the event and mark the event as handled.

5. Event bubbling

When the event processing is complete, the event is passed up until it reaches the root node. This process is similar to the distribution of events, except that it is passed upwards from the parent node of the current node.

During the entire event distribution process, each RenderObject will create a HitTestEntry object and add it to HitTestResult to record the distribution result. When finally processing the event, Flutter traverses the HitTestEntry objects in HitTestResult, and calls the event processing callback function of each RenderObject in turn.

The detailed process and implementation of event distribution in Flutter. It should be noted that the process of event distribution is very complex and involves many details and optimizations, such as event caching, event simulation, event merging, etc. These details and optimizations are very important for improving application performance and response speed.

Guess you like

Origin blog.csdn.net/qq_28563283/article/details/130349463