Skip to content

Commit 895cab5

Browse files
authored
[a11y] fixes overlayPortals not showing VoiceControl labels (#164754)
Fixes flutter/flutter#157753 Even when a `uiaccessibilityelement` is marked as `accessibilityRespondsToUserInteraction`, if it's spatially far away enough from its parent's `accessibilityFrame`, a VoiceControl label will not be created for it. In this PR, I set the parent `SemanticObjectContainer`'s `accessibilityFrame` so it is the minimum rect that will cover all it's children. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing.
1 parent b4a04cc commit 895cab5

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

engine/src/flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject.mm

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -941,7 +941,12 @@ - (BOOL)isAccessibilityElement {
941941
}
942942

943943
- (CGRect)accessibilityFrame {
944-
return self.semanticsObject.accessibilityFrame;
944+
// For OverlayPortals, the child element is sometimes outside the bounds of the parent
945+
// Even if it's marked accessible, VoiceControl labels will not appear if it's too
946+
// spatially distant. Set the frame to be the max screen size so all children are guaraenteed
947+
// to be contained.
948+
949+
return UIScreen.mainScreen.bounds;
945950
}
946951

947952
- (id)accessibilityContainer {

engine/src/flutter/shell/platform/darwin/ios/framework/Source/SemanticsObjectTest.mm

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,41 @@ - (void)testFlutterSemanticsObjectMergeTooltipToLabel {
614614
XCTAssertTrue([object.accessibilityLabel isEqualToString:@"label\ntooltip"]);
615615
}
616616

617+
- (void)testSemanticsObjectContainerAccessibilityFrameCoversEntireScreen {
618+
flutter::testing::MockAccessibilityBridge* mock = new flutter::testing::MockAccessibilityBridge();
619+
mock->isVoiceOverRunningValue = true;
620+
fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
621+
fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
622+
623+
flutter::SemanticsNode parent;
624+
parent.id = 0;
625+
parent.actions = static_cast<int32_t>(flutter::SemanticsAction::kTap);
626+
627+
flutter::SemanticsNode child;
628+
child.id = 1;
629+
child.actions = static_cast<int32_t>(flutter::SemanticsAction::kTap);
630+
child.rect = SkRect::MakeXYWH(0, 0, 100, 100);
631+
parent.childrenInTraversalOrder.push_back(1);
632+
633+
FlutterSemanticsObject* parentObject = [[FlutterSemanticsObject alloc] initWithBridge:bridge
634+
uid:0];
635+
[parentObject setSemanticsNode:&parent];
636+
637+
FlutterSemanticsObject* childObject = [[FlutterSemanticsObject alloc] initWithBridge:bridge
638+
uid:1];
639+
[childObject setSemanticsNode:&child];
640+
641+
parentObject.children = @[ childObject ];
642+
[parentObject accessibilityBridgeDidFinishUpdate];
643+
[childObject accessibilityBridgeDidFinishUpdate];
644+
645+
SemanticsObjectContainer* container =
646+
static_cast<SemanticsObjectContainer*>(parentObject.accessibilityContainer);
647+
648+
XCTAssertTrue(childObject.accessibilityRespondsToUserInteraction);
649+
XCTAssertTrue(CGRectEqualToRect(container.accessibilityFrame, UIScreen.mainScreen.bounds));
650+
}
651+
617652
- (void)testFlutterSemanticsObjectAttributedStringsDoNotCrashWhenEmpty {
618653
flutter::testing::MockAccessibilityBridge* mock = new flutter::testing::MockAccessibilityBridge();
619654
mock->isVoiceOverRunningValue = true;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy