mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Revert "Issues/80711 reland (#26813)" (flutter/engine#26859)
This reverts commit d03313b7b3f97d2083e3977d9e62974687760a33.
This commit is contained in:
parent
616fd2a662
commit
2a526b317d
@ -44,17 +44,12 @@ enum class SemanticsAction : int32_t {
|
||||
kSetText = 1 << 21,
|
||||
};
|
||||
|
||||
const int kVerticalScrollSemanticsActions =
|
||||
const int kScrollableSemanticsActions =
|
||||
static_cast<int32_t>(SemanticsAction::kScrollLeft) |
|
||||
static_cast<int32_t>(SemanticsAction::kScrollRight) |
|
||||
static_cast<int32_t>(SemanticsAction::kScrollUp) |
|
||||
static_cast<int32_t>(SemanticsAction::kScrollDown);
|
||||
|
||||
const int kHorizontalScrollSemanticsActions =
|
||||
static_cast<int32_t>(SemanticsAction::kScrollLeft) |
|
||||
static_cast<int32_t>(SemanticsAction::kScrollRight);
|
||||
|
||||
const int kScrollableSemanticsActions =
|
||||
kVerticalScrollSemanticsActions | kHorizontalScrollSemanticsActions;
|
||||
|
||||
/// C/C++ representation of `SemanticsFlags` defined in
|
||||
/// `lib/ui/semantics.dart`.
|
||||
///\warning This must match the `SemanticsFlags` enum in
|
||||
|
||||
@ -13,8 +13,6 @@
|
||||
#import "flutter/shell/platform/darwin/ios/framework/Source/accessibility_bridge_ios.h"
|
||||
|
||||
constexpr int32_t kRootNodeId = 0;
|
||||
// This can be arbitrary number as long as it is bigger than 0.
|
||||
constexpr float kScrollExtentMaxForInf = 1000;
|
||||
|
||||
@class FlutterCustomAccessibilityAction;
|
||||
@class FlutterPlatformViewSemanticsContainer;
|
||||
@ -33,7 +31,7 @@ constexpr float kScrollExtentMaxForInf = 1000;
|
||||
* The parent of this node in the node tree. Will be nil for the root node and
|
||||
* during transient state changes.
|
||||
*/
|
||||
@property(nonatomic, assign) SemanticsObject* parent;
|
||||
@property(nonatomic, readonly) SemanticsObject* parent;
|
||||
|
||||
/**
|
||||
* The accessibility bridge that this semantics object is attached to. This
|
||||
@ -96,14 +94,6 @@ constexpr float kScrollExtentMaxForInf = 1000;
|
||||
|
||||
- (BOOL)onCustomAccessibilityAction:(FlutterCustomAccessibilityAction*)action;
|
||||
|
||||
/**
|
||||
* Called after accessibility bridge finishes a semantics update.
|
||||
*
|
||||
* Subclasses can override this method if they contain states that can only be
|
||||
* updated once every node in the accessibility tree has finished updating.
|
||||
*/
|
||||
- (void)accessibilityBridgeDidFinishUpdate;
|
||||
|
||||
#pragma mark - Designated initializers
|
||||
|
||||
- (instancetype)init __attribute__((unavailable("Use initWithBridge instead")));
|
||||
@ -169,18 +159,6 @@ constexpr float kScrollExtentMaxForInf = 1000;
|
||||
|
||||
@end
|
||||
|
||||
/// The semantics object for scrollable. This class creates an UIScrollView to interact with the
|
||||
/// iOS.
|
||||
@interface FlutterScrollableSemanticsObject : UIScrollView
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
- (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
|
||||
- (instancetype)initWithCoder:(NSCoder*)coder NS_UNAVAILABLE;
|
||||
- (instancetype)initWithSemanticsObject:(SemanticsObject*)semanticsObject NS_DESIGNATED_INITIALIZER;
|
||||
- (void)accessibilityBridgeDidFinishUpdate;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
* Represents a semantics object that has children and hence has to be presented to the OS as a
|
||||
* UIAccessibilityContainer.
|
||||
|
||||
@ -34,58 +34,6 @@ flutter::SemanticsAction GetSemanticsActionForScrollDirection(
|
||||
return flutter::SemanticsAction::kScrollUp;
|
||||
}
|
||||
|
||||
SkM44 GetGlobalTransform(SemanticsObject* reference) {
|
||||
SkM44 globalTransform = [reference node].transform;
|
||||
for (SemanticsObject* parent = [reference parent]; parent; parent = parent.parent) {
|
||||
globalTransform = parent.node.transform * globalTransform;
|
||||
}
|
||||
return globalTransform;
|
||||
}
|
||||
|
||||
SkPoint ApplyTransform(SkPoint& point, const SkM44& transform) {
|
||||
SkV4 vector = transform.map(point.x(), point.y(), 0, 1);
|
||||
return SkPoint::Make(vector.x / vector.w, vector.y / vector.w);
|
||||
}
|
||||
|
||||
CGPoint ConvertPointToGlobal(SemanticsObject* reference, CGPoint local_point) {
|
||||
SkM44 globalTransform = GetGlobalTransform(reference);
|
||||
SkPoint point = SkPoint::Make(local_point.x, local_point.y);
|
||||
point = ApplyTransform(point, globalTransform);
|
||||
// `rect` is in the physical pixel coordinate system. iOS expects the accessibility frame in
|
||||
// the logical pixel coordinate system. Therefore, we divide by the `scale` (pixel ratio) to
|
||||
// convert.
|
||||
CGFloat scale = [[[reference bridge]->view() window] screen].scale;
|
||||
auto result = CGPointMake(point.x() / scale, point.y() / scale);
|
||||
return [[reference bridge]->view() convertPoint:result toView:nil];
|
||||
}
|
||||
|
||||
CGRect ConvertRectToGlobal(SemanticsObject* reference, CGRect local_rect) {
|
||||
SkM44 globalTransform = GetGlobalTransform(reference);
|
||||
|
||||
SkPoint quad[4] = {
|
||||
SkPoint::Make(local_rect.origin.x, local_rect.origin.y), // top left
|
||||
SkPoint::Make(local_rect.origin.x + local_rect.size.width, local_rect.origin.y), // top right
|
||||
SkPoint::Make(local_rect.origin.x + local_rect.size.width,
|
||||
local_rect.origin.y + local_rect.size.height), // bottom right
|
||||
SkPoint::Make(local_rect.origin.x,
|
||||
local_rect.origin.y + local_rect.size.height) // bottom left
|
||||
};
|
||||
for (auto& point : quad) {
|
||||
point = ApplyTransform(point, globalTransform);
|
||||
}
|
||||
SkRect rect;
|
||||
NSCAssert(rect.setBoundsCheck(quad, 4), @"Transformed points can't form a rect");
|
||||
rect.setBounds(quad, 4);
|
||||
|
||||
// `rect` is in the physical pixel coordinate system. iOS expects the accessibility frame in
|
||||
// the logical pixel coordinate system. Therefore, we divide by the `scale` (pixel ratio) to
|
||||
// convert.
|
||||
CGFloat scale = [[[reference bridge]->view() window] screen].scale;
|
||||
auto result =
|
||||
CGRectMake(rect.x() / scale, rect.y() / scale, rect.width() / scale, rect.height() / scale);
|
||||
return UIAccessibilityConvertFrameToScreenCoordinates(result, [reference bridge]->view());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@implementation FlutterSwitchSemanticsObject {
|
||||
@ -140,152 +88,6 @@ CGRect ConvertRectToGlobal(SemanticsObject* reference, CGRect local_rect) {
|
||||
|
||||
@end // FlutterSwitchSemanticsObject
|
||||
|
||||
@interface FlutterScrollableSemanticsObject ()
|
||||
@property(nonatomic, strong) SemanticsObject* semanticsObject;
|
||||
@end
|
||||
|
||||
@implementation FlutterScrollableSemanticsObject {
|
||||
fml::scoped_nsobject<SemanticsObjectContainer> _container;
|
||||
}
|
||||
|
||||
- (instancetype)initWithSemanticsObject:(SemanticsObject*)semanticsObject {
|
||||
self = [super initWithFrame:CGRectZero];
|
||||
if (self) {
|
||||
_semanticsObject = [semanticsObject retain];
|
||||
[semanticsObject.bridge->view() addSubview:self];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
_container.get().semanticsObject = nil;
|
||||
[_semanticsObject release];
|
||||
[self removeFromSuperview];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event {
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSMethodSignature*)methodSignatureForSelector:(SEL)sel {
|
||||
NSMethodSignature* result = [super methodSignatureForSelector:sel];
|
||||
if (!result) {
|
||||
result = [_semanticsObject methodSignatureForSelector:sel];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
- (void)forwardInvocation:(NSInvocation*)anInvocation {
|
||||
[anInvocation setTarget:_semanticsObject];
|
||||
[anInvocation invoke];
|
||||
}
|
||||
|
||||
- (void)accessibilityBridgeDidFinishUpdate {
|
||||
// In order to make iOS think this UIScrollView is scrollable, the following
|
||||
// requirements must be true.
|
||||
// 1. contentSize must be bigger than the frame size.
|
||||
// 2. The scrollable isAccessibilityElement must return YES
|
||||
//
|
||||
// Once the requirements are met, the iOS uses contentOffset to determine
|
||||
// what scroll actions are available. e.g. If the view scrolls vertically and
|
||||
// contentOffset is 0.0, only the scroll down action is available.
|
||||
[self setFrame:[_semanticsObject accessibilityFrame]];
|
||||
[self setContentSize:[self contentSizeInternal]];
|
||||
[self setContentOffset:[self contentOffsetInternal] animated:NO];
|
||||
if (self.contentSize.width > self.frame.size.width ||
|
||||
self.contentSize.height > self.frame.size.height) {
|
||||
self.isAccessibilityElement = YES;
|
||||
} else {
|
||||
self.isAccessibilityElement = NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setChildren:(NSArray<SemanticsObject*>*)children {
|
||||
[_semanticsObject setChildren:children];
|
||||
// The children's parent is pointing to _semanticsObject, need to manually
|
||||
// set it this object.
|
||||
for (SemanticsObject* child in _semanticsObject.children) {
|
||||
child.parent = (SemanticsObject*)self;
|
||||
}
|
||||
}
|
||||
|
||||
- (id)accessibilityContainer {
|
||||
if (_container == nil) {
|
||||
_container.reset([[SemanticsObjectContainer alloc]
|
||||
initWithSemanticsObject:(SemanticsObject*)self
|
||||
bridge:[_semanticsObject bridge]]);
|
||||
}
|
||||
return _container.get();
|
||||
}
|
||||
|
||||
// private methods
|
||||
|
||||
- (CGSize)contentSizeInternal {
|
||||
CGRect result;
|
||||
const SkRect& rect = _semanticsObject.node.rect;
|
||||
float scrollExtentMax = isfinite(_semanticsObject.node.scrollExtentMax)
|
||||
? _semanticsObject.node.scrollExtentMax
|
||||
: kScrollExtentMaxForInf + _semanticsObject.node.scrollPosition;
|
||||
if (_semanticsObject.node.actions & flutter::kVerticalScrollSemanticsActions) {
|
||||
result = CGRectMake(rect.x(), rect.y(), rect.width(), rect.height() + scrollExtentMax);
|
||||
} else if (_semanticsObject.node.actions & flutter::kHorizontalScrollSemanticsActions) {
|
||||
result = CGRectMake(rect.x(), rect.y(), rect.width() + scrollExtentMax, rect.height());
|
||||
} else {
|
||||
result = CGRectMake(rect.x(), rect.y(), rect.width(), rect.height());
|
||||
}
|
||||
return ConvertRectToGlobal(_semanticsObject, result).size;
|
||||
}
|
||||
|
||||
- (CGPoint)contentOffsetInternal {
|
||||
CGPoint result;
|
||||
CGPoint origin = self.frame.origin;
|
||||
const SkRect& rect = _semanticsObject.node.rect;
|
||||
if (_semanticsObject.node.actions & flutter::kVerticalScrollSemanticsActions) {
|
||||
result = ConvertPointToGlobal(
|
||||
_semanticsObject, CGPointMake(rect.x(), rect.y() + _semanticsObject.node.scrollPosition));
|
||||
} else if (_semanticsObject.node.actions & flutter::kHorizontalScrollSemanticsActions) {
|
||||
result = ConvertPointToGlobal(
|
||||
_semanticsObject, CGPointMake(rect.x() + _semanticsObject.node.scrollPosition, rect.y()));
|
||||
} else {
|
||||
result = origin;
|
||||
}
|
||||
return CGPointMake(result.x - origin.x, result.y - origin.y);
|
||||
}
|
||||
|
||||
// The following methods are explicitly forwarded to the wrapped SemanticsObject because the
|
||||
// forwarding logic above doesn't apply to them since they are also implemented in the
|
||||
// UIScrollView class, the base class.
|
||||
|
||||
- (BOOL)accessibilityActivate {
|
||||
return [_semanticsObject accessibilityActivate];
|
||||
}
|
||||
|
||||
- (void)accessibilityIncrement {
|
||||
[_semanticsObject accessibilityIncrement];
|
||||
}
|
||||
|
||||
- (void)accessibilityDecrement {
|
||||
[_semanticsObject accessibilityDecrement];
|
||||
}
|
||||
|
||||
- (BOOL)accessibilityScroll:(UIAccessibilityScrollDirection)direction {
|
||||
return [_semanticsObject accessibilityScroll:direction];
|
||||
}
|
||||
|
||||
- (BOOL)accessibilityPerformEscape {
|
||||
return [_semanticsObject accessibilityPerformEscape];
|
||||
}
|
||||
|
||||
- (void)accessibilityElementDidBecomeFocused {
|
||||
[_semanticsObject accessibilityElementDidBecomeFocused];
|
||||
}
|
||||
|
||||
- (void)accessibilityElementDidLoseFocus {
|
||||
[_semanticsObject accessibilityElementDidLoseFocus];
|
||||
}
|
||||
@end // FlutterScrollableSemanticsObject
|
||||
|
||||
@implementation FlutterCustomAccessibilityAction {
|
||||
}
|
||||
@end
|
||||
@ -372,9 +174,6 @@ CGRect ConvertRectToGlobal(SemanticsObject* reference, CGRect local_rect) {
|
||||
_node = *node;
|
||||
}
|
||||
|
||||
- (void)accessibilityBridgeDidFinishUpdate { /* Do nothing by default */
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether calling `setSemanticsNode:` with `node` would cause a layout change.
|
||||
*/
|
||||
@ -599,9 +398,27 @@ CGRect ConvertRectToGlobal(SemanticsObject* reference, CGRect local_rect) {
|
||||
}
|
||||
|
||||
- (CGRect)globalRect {
|
||||
const SkRect& rect = [self node].rect;
|
||||
CGRect localRect = CGRectMake(rect.x(), rect.y(), rect.width(), rect.height());
|
||||
return ConvertRectToGlobal(self, localRect);
|
||||
SkM44 globalTransform = [self node].transform;
|
||||
for (SemanticsObject* parent = [self parent]; parent; parent = parent.parent) {
|
||||
globalTransform = parent.node.transform * globalTransform;
|
||||
}
|
||||
|
||||
SkPoint quad[4];
|
||||
[self node].rect.toQuad(quad);
|
||||
for (auto& point : quad) {
|
||||
SkV4 vector = globalTransform.map(point.x(), point.y(), 0, 1);
|
||||
point.set(vector.x / vector.w, vector.y / vector.w);
|
||||
}
|
||||
SkRect rect;
|
||||
rect.setBounds(quad, 4);
|
||||
|
||||
// `rect` is in the physical pixel coordinate system. iOS expects the accessibility frame in
|
||||
// the logical pixel coordinate system. Therefore, we divide by the `scale` (pixel ratio) to
|
||||
// convert.
|
||||
CGFloat scale = [[[self bridge]->view() window] screen].scale;
|
||||
auto result =
|
||||
CGRectMake(rect.x() / scale, rect.y() / scale, rect.width() / scale, rect.height() / scale);
|
||||
return UIAccessibilityConvertFrameToScreenCoordinates(result, [self bridge]->view());
|
||||
}
|
||||
|
||||
#pragma mark - UIAccessibilityElement protocol
|
||||
|
||||
@ -10,8 +10,6 @@
|
||||
|
||||
FLUTTER_ASSERT_ARC
|
||||
|
||||
const CGRect kScreenSize = CGRectMake(0, 0, 600, 800);
|
||||
|
||||
namespace flutter {
|
||||
namespace {
|
||||
|
||||
@ -26,11 +24,7 @@ class SemanticsActionObservation {
|
||||
|
||||
class MockAccessibilityBridge : public AccessibilityBridgeIos {
|
||||
public:
|
||||
MockAccessibilityBridge() : observations({}) {
|
||||
view_ = [[UIView alloc] initWithFrame:kScreenSize];
|
||||
window_ = [[UIWindow alloc] initWithFrame:kScreenSize];
|
||||
[window_ addSubview:view_];
|
||||
}
|
||||
MockAccessibilityBridge() : observations({}) { view_ = [[UIView alloc] init]; }
|
||||
UIView* view() const override { return view_; }
|
||||
UIView<UITextInput>* textInputView() override { return nil; }
|
||||
void DispatchSemanticsAction(int32_t id, SemanticsAction action) override {
|
||||
@ -52,7 +46,6 @@ class MockAccessibilityBridge : public AccessibilityBridgeIos {
|
||||
|
||||
private:
|
||||
UIView* view_;
|
||||
UIWindow* window_;
|
||||
};
|
||||
} // namespace
|
||||
} // namespace flutter
|
||||
@ -167,145 +160,6 @@ class MockAccessibilityBridge : public AccessibilityBridgeIos {
|
||||
XCTAssertEqual([object accessibilityTraits], UIAccessibilityTraitButton);
|
||||
}
|
||||
|
||||
- (void)testVerticalFlutterScrollableSemanticsObject {
|
||||
fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
|
||||
new flutter::MockAccessibilityBridge());
|
||||
fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
|
||||
|
||||
float transformScale = 0.5f;
|
||||
float screenScale = [[bridge->view() window] screen].scale;
|
||||
float effectivelyScale = transformScale / screenScale;
|
||||
float x = 10;
|
||||
float y = 10;
|
||||
float w = 100;
|
||||
float h = 200;
|
||||
float scrollExtentMax = 500.0;
|
||||
float scrollPosition = 150.0;
|
||||
|
||||
flutter::SemanticsNode node;
|
||||
node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
|
||||
node.actions = flutter::kVerticalScrollSemanticsActions;
|
||||
node.rect = SkRect::MakeXYWH(x, y, w, h);
|
||||
node.scrollExtentMax = scrollExtentMax;
|
||||
node.scrollPosition = scrollPosition;
|
||||
node.transform = {
|
||||
transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
|
||||
FlutterSemanticsObject* delegate = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:0];
|
||||
FlutterScrollableSemanticsObject* scrollable =
|
||||
[[FlutterScrollableSemanticsObject alloc] initWithSemanticsObject:delegate];
|
||||
SemanticsObject* scrollable_object = static_cast<SemanticsObject*>(scrollable);
|
||||
[scrollable_object setSemanticsNode:&node];
|
||||
[scrollable_object accessibilityBridgeDidFinishUpdate];
|
||||
XCTAssertTrue(
|
||||
CGRectEqualToRect(scrollable.frame, CGRectMake(x * effectivelyScale, y * effectivelyScale,
|
||||
w * effectivelyScale, h * effectivelyScale)));
|
||||
XCTAssertTrue(CGSizeEqualToSize(
|
||||
scrollable.contentSize,
|
||||
CGSizeMake(w * effectivelyScale, (h + scrollExtentMax) * effectivelyScale)));
|
||||
XCTAssertTrue(CGPointEqualToPoint(scrollable.contentOffset,
|
||||
CGPointMake(0, scrollPosition * effectivelyScale)));
|
||||
}
|
||||
|
||||
- (void)testHorizontalFlutterScrollableSemanticsObject {
|
||||
fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
|
||||
new flutter::MockAccessibilityBridge());
|
||||
fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
|
||||
|
||||
float transformScale = 0.5f;
|
||||
float screenScale = [[bridge->view() window] screen].scale;
|
||||
float effectivelyScale = transformScale / screenScale;
|
||||
float x = 10;
|
||||
float y = 10;
|
||||
float w = 100;
|
||||
float h = 200;
|
||||
float scrollExtentMax = 500.0;
|
||||
float scrollPosition = 150.0;
|
||||
|
||||
flutter::SemanticsNode node;
|
||||
node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
|
||||
node.actions = flutter::kHorizontalScrollSemanticsActions;
|
||||
node.rect = SkRect::MakeXYWH(x, y, w, h);
|
||||
node.scrollExtentMax = scrollExtentMax;
|
||||
node.scrollPosition = scrollPosition;
|
||||
node.transform = {
|
||||
transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
|
||||
FlutterSemanticsObject* delegate = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:0];
|
||||
FlutterScrollableSemanticsObject* scrollable =
|
||||
[[FlutterScrollableSemanticsObject alloc] initWithSemanticsObject:delegate];
|
||||
SemanticsObject* scrollable_object = static_cast<SemanticsObject*>(scrollable);
|
||||
[scrollable_object setSemanticsNode:&node];
|
||||
[scrollable_object accessibilityBridgeDidFinishUpdate];
|
||||
XCTAssertTrue(
|
||||
CGRectEqualToRect(scrollable.frame, CGRectMake(x * effectivelyScale, y * effectivelyScale,
|
||||
w * effectivelyScale, h * effectivelyScale)));
|
||||
XCTAssertTrue(CGSizeEqualToSize(
|
||||
scrollable.contentSize,
|
||||
CGSizeMake((w + scrollExtentMax) * effectivelyScale, h * effectivelyScale)));
|
||||
XCTAssertTrue(CGPointEqualToPoint(scrollable.contentOffset,
|
||||
CGPointMake(scrollPosition * effectivelyScale, 0)));
|
||||
}
|
||||
|
||||
- (void)testCanHandleInfiniteScrollExtent {
|
||||
fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
|
||||
new flutter::MockAccessibilityBridge());
|
||||
fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
|
||||
|
||||
float transformScale = 0.5f;
|
||||
float screenScale = [[bridge->view() window] screen].scale;
|
||||
float effectivelyScale = transformScale / screenScale;
|
||||
float x = 10;
|
||||
float y = 10;
|
||||
float w = 100;
|
||||
float h = 200;
|
||||
float scrollExtentMax = INFINITY;
|
||||
float scrollPosition = 150.0;
|
||||
|
||||
flutter::SemanticsNode node;
|
||||
node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
|
||||
node.actions = flutter::kVerticalScrollSemanticsActions;
|
||||
node.rect = SkRect::MakeXYWH(x, y, w, h);
|
||||
node.scrollExtentMax = scrollExtentMax;
|
||||
node.scrollPosition = scrollPosition;
|
||||
node.transform = {
|
||||
transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
|
||||
FlutterSemanticsObject* delegate = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:0];
|
||||
FlutterScrollableSemanticsObject* scrollable =
|
||||
[[FlutterScrollableSemanticsObject alloc] initWithSemanticsObject:delegate];
|
||||
SemanticsObject* scrollable_object = static_cast<SemanticsObject*>(scrollable);
|
||||
[scrollable_object setSemanticsNode:&node];
|
||||
[scrollable_object accessibilityBridgeDidFinishUpdate];
|
||||
XCTAssertTrue(
|
||||
CGRectEqualToRect(scrollable.frame, CGRectMake(x * effectivelyScale, y * effectivelyScale,
|
||||
w * effectivelyScale, h * effectivelyScale)));
|
||||
XCTAssertTrue(CGSizeEqualToSize(
|
||||
scrollable.contentSize,
|
||||
CGSizeMake(w * effectivelyScale,
|
||||
(h + kScrollExtentMaxForInf + scrollPosition) * effectivelyScale)));
|
||||
XCTAssertTrue(CGPointEqualToPoint(scrollable.contentOffset,
|
||||
CGPointMake(0, scrollPosition * effectivelyScale)));
|
||||
}
|
||||
|
||||
- (void)testFlutterScrollableSemanticsObjectIsNotHittestable {
|
||||
fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
|
||||
new flutter::MockAccessibilityBridge());
|
||||
fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
|
||||
|
||||
flutter::SemanticsNode node;
|
||||
node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
|
||||
node.actions = flutter::kHorizontalScrollSemanticsActions;
|
||||
node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
|
||||
node.scrollExtentMax = 100.0;
|
||||
node.scrollPosition = 0.0;
|
||||
|
||||
FlutterSemanticsObject* delegate = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:0];
|
||||
FlutterScrollableSemanticsObject* scrollable =
|
||||
[[FlutterScrollableSemanticsObject alloc] initWithSemanticsObject:delegate];
|
||||
SemanticsObject* scrollable_object = static_cast<SemanticsObject*>(scrollable);
|
||||
[scrollable_object setSemanticsNode:&node];
|
||||
[scrollable_object accessibilityBridgeDidFinishUpdate];
|
||||
XCTAssertEqual([scrollable hitTest:CGPointMake(10, 10) withEvent:nil], nil);
|
||||
}
|
||||
|
||||
- (void)testSemanticsObjectBuildsAttributedString {
|
||||
fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
|
||||
new flutter::MockAccessibilityBridge());
|
||||
|
||||
@ -200,16 +200,11 @@ void AccessibilityBridge::UpdateSemantics(flutter::SemanticsNodeUpdates nodes,
|
||||
view_controller_.view.accessibilityElements = nil;
|
||||
}
|
||||
|
||||
NSMutableArray<NSNumber*>* doomed_uids = [NSMutableArray arrayWithArray:[objects_ allKeys]];
|
||||
if (root) {
|
||||
NSMutableArray<NSNumber*>* doomed_uids = [NSMutableArray arrayWithArray:[objects_.get() allKeys]];
|
||||
if (root)
|
||||
VisitObjectsRecursivelyAndRemove(root, doomed_uids);
|
||||
}
|
||||
[objects_ removeObjectsForKeys:doomed_uids];
|
||||
|
||||
for (SemanticsObject* object in [objects_ allValues]) {
|
||||
[object accessibilityBridgeDidFinishUpdate];
|
||||
}
|
||||
|
||||
if (!ios_delegate_->IsFlutterViewControllerPresentingModalViewController(view_controller_)) {
|
||||
layoutChanged = layoutChanged || [doomed_uids count] > 0;
|
||||
|
||||
@ -263,11 +258,6 @@ static SemanticsObject* CreateObject(const flutter::SemanticsNode& node,
|
||||
} else if (node.HasFlag(flutter::SemanticsFlags::kHasToggledState) ||
|
||||
node.HasFlag(flutter::SemanticsFlags::kHasCheckedState)) {
|
||||
return [[[FlutterSwitchSemanticsObject alloc] initWithBridge:weak_ptr uid:node.id] autorelease];
|
||||
} else if (node.HasFlag(flutter::SemanticsFlags::kHasImplicitScrolling)) {
|
||||
SemanticsObject* delegateObject =
|
||||
[[[FlutterSemanticsObject alloc] initWithBridge:weak_ptr uid:node.id] autorelease];
|
||||
return (SemanticsObject*)[[[FlutterScrollableSemanticsObject alloc]
|
||||
initWithSemanticsObject:delegateObject] autorelease];
|
||||
} else {
|
||||
return [[[FlutterSemanticsObject alloc] initWithBridge:weak_ptr uid:node.id] autorelease];
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user