mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Remove scopesRoute engine inference and fix SemanticRole/SemanticBehavior naming collision
This commit is contained in:
parent
85ebb013d1
commit
fee032f2ec
@ -72,7 +72,7 @@ class SemanticIncrementable extends SemanticRole {
|
||||
}
|
||||
|
||||
@override
|
||||
bool get acceptsPointerEvents => true;
|
||||
bool get shouldAcceptPointerEvents => true;
|
||||
|
||||
@override
|
||||
bool focusAsRouteDefault() {
|
||||
|
||||
@ -33,7 +33,7 @@ class SemanticPlatformView extends SemanticRole {
|
||||
/// This is so that the platform views are not obscured by semantic elements
|
||||
/// and can be reached by inspecting the web page.
|
||||
@override
|
||||
bool get acceptsPointerEvents => false;
|
||||
bool get shouldAcceptPointerEvents => false;
|
||||
|
||||
@override
|
||||
void update() {
|
||||
|
||||
@ -602,7 +602,7 @@ abstract class SemanticRole {
|
||||
///
|
||||
/// This approach allows framework full control when specified, with reasonable
|
||||
/// fallback inference for backward compatibility.
|
||||
bool get acceptsPointerEvents {
|
||||
bool get shouldAcceptPointerEvents {
|
||||
final hitTestBehavior = semanticsObject.hitTestBehavior;
|
||||
|
||||
// TIER 1: Framework Declaration
|
||||
@ -646,22 +646,6 @@ abstract class SemanticRole {
|
||||
}
|
||||
}
|
||||
|
||||
// Route-scoped containers accept pointer events as a fallback.
|
||||
// This fixes the dialog dismissal bug (issue #149001) by ensuring that
|
||||
// dialog containers act as barriers, preventing clicks on empty space
|
||||
// from passing through to the modal barrier underneath.
|
||||
//
|
||||
// Note: Ideally, the framework should explicitly set
|
||||
// SemanticsHitTestBehavior.opaque for dialogs instead of relying on this
|
||||
// engine-side inference. This fallback exists for backward compatibility
|
||||
// and cases where framework doesn't specify the behavior.
|
||||
if (semanticsObject.hasChildren) {
|
||||
return semanticsObject.scopesRoute;
|
||||
}
|
||||
|
||||
// Leaf nodes default to transparent.
|
||||
// Non-interactive leaf nodes (like empty space) should not intercept
|
||||
// pointer events.
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1879,7 +1863,7 @@ class SemanticsObject {
|
||||
// Apply updates to the DOM.
|
||||
_updateRole();
|
||||
|
||||
if (semanticRole!.acceptsPointerEvents) {
|
||||
if (semanticRole!.shouldAcceptPointerEvents) {
|
||||
element.style.pointerEvents = 'all';
|
||||
} else {
|
||||
element.style.pointerEvents = 'none';
|
||||
|
||||
@ -208,7 +208,7 @@ class SemanticTextField extends SemanticRole {
|
||||
}
|
||||
|
||||
@override
|
||||
bool get acceptsPointerEvents => true;
|
||||
bool get shouldAcceptPointerEvents => true;
|
||||
|
||||
/// The element used for editing, e.g. `<input>`, `<textarea>`, which is
|
||||
/// different from the host [element].
|
||||
|
||||
@ -1628,52 +1628,9 @@ void _testContainer() {
|
||||
);
|
||||
});
|
||||
|
||||
test('route-scoped containers accept pointer events', () async {
|
||||
test('non-interactive containers do not accept pointer events', () async {
|
||||
final ui.SemanticsUpdateBuilder builder = ui.SemanticsUpdateBuilder();
|
||||
// Create a route-scoped container (like a dialog) with children
|
||||
updateNode(
|
||||
builder,
|
||||
flags: const ui.SemanticsFlags(scopesRoute: true),
|
||||
childrenInTraversalOrder: Int32List.fromList(<int>[1, 2]),
|
||||
childrenInHitTestOrder: Int32List.fromList(<int>[1, 2]),
|
||||
);
|
||||
updateNode(builder, id: 1);
|
||||
updateNode(builder, id: 2);
|
||||
|
||||
owner().updateSemantics(builder.build());
|
||||
|
||||
final DomElement routeContainer = owner().semanticsHost.querySelector(
|
||||
'#${kFlutterSemanticNodePrefix}0',
|
||||
)!;
|
||||
expect(
|
||||
routeContainer.style.pointerEvents,
|
||||
'all',
|
||||
reason:
|
||||
'Route-scoped containers (like dialogs) should accept pointer events to prevent clicks from escaping to the barrier',
|
||||
);
|
||||
|
||||
final DomElement child1 = owner().semanticsHost.querySelector(
|
||||
'#${kFlutterSemanticNodePrefix}1',
|
||||
)!;
|
||||
expect(
|
||||
child1.style.pointerEvents,
|
||||
'none',
|
||||
reason: 'Non-interactive leaf nodes should not accept pointer events',
|
||||
);
|
||||
|
||||
final DomElement child2 = owner().semanticsHost.querySelector(
|
||||
'#${kFlutterSemanticNodePrefix}2',
|
||||
)!;
|
||||
expect(
|
||||
child2.style.pointerEvents,
|
||||
'none',
|
||||
reason: 'Non-interactive leaf nodes should not accept pointer events',
|
||||
);
|
||||
});
|
||||
|
||||
test('regular containers do not accept pointer events', () async {
|
||||
final ui.SemanticsUpdateBuilder builder = ui.SemanticsUpdateBuilder();
|
||||
// Create a regular container (NOT route-scoped) with children
|
||||
// Create a container with children but no explicit hitTestBehavior
|
||||
updateNode(
|
||||
builder,
|
||||
childrenInTraversalOrder: Int32List.fromList(<int>[1]),
|
||||
@ -1689,7 +1646,8 @@ void _testContainer() {
|
||||
expect(
|
||||
container.style.pointerEvents,
|
||||
'none',
|
||||
reason: 'Regular containers (without scopesRoute) should not accept pointer events',
|
||||
reason:
|
||||
'Non-interactive containers should not accept pointer events when hitTestBehavior is defer',
|
||||
);
|
||||
});
|
||||
|
||||
@ -1725,30 +1683,6 @@ void _testContainer() {
|
||||
);
|
||||
});
|
||||
|
||||
test('hitTestBehavior.opaque overrides scopesRoute for containers', () async {
|
||||
final ui.SemanticsUpdateBuilder builder = ui.SemanticsUpdateBuilder();
|
||||
// Create a route-scoped container with explicit transparent behavior
|
||||
updateNode(
|
||||
builder,
|
||||
flags: const ui.SemanticsFlags(scopesRoute: true),
|
||||
hitTestBehavior: ui.SemanticsHitTestBehavior.transparent,
|
||||
childrenInTraversalOrder: Int32List.fromList(<int>[1]),
|
||||
childrenInHitTestOrder: Int32List.fromList(<int>[1]),
|
||||
);
|
||||
updateNode(builder, id: 1);
|
||||
|
||||
owner().updateSemantics(builder.build());
|
||||
|
||||
final DomElement container = owner().semanticsHost.querySelector(
|
||||
'#${kFlutterSemanticNodePrefix}0',
|
||||
)!;
|
||||
expect(
|
||||
container.style.pointerEvents,
|
||||
'none',
|
||||
reason: 'Explicit hitTestBehavior.transparent should override scopesRoute',
|
||||
);
|
||||
});
|
||||
|
||||
test('hitTestBehavior takes precedence over interactive behaviors', () async {
|
||||
final ui.SemanticsUpdateBuilder builder = ui.SemanticsUpdateBuilder();
|
||||
// Create a tappable node with explicit transparent behavior
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user