From be2cabc3f89b22aa8624c476e48598274ca5dd75 Mon Sep 17 00:00:00 2001 From: Vladislav Alexeev Date: Tue, 14 Jul 2015 03:12:15 -0700 Subject: [PATCH] Dynamic Text Sizes for Text component Summary: Dynamic Text Sizes for Text component. Text gains new prop - allowFontScaling (true by default). There is also AccessibilityManager module that allows you to tune multipliers per each content size category, but predefined multipliers are there. This could potentially break some apps so please test carefully. --- Examples/UIExplorer/TextExample.ios.js | 19 ++++ Libraries/ART/RCTConvert+ART.m | 2 +- Libraries/Text/RCTShadowRawText.m | 24 ++++ Libraries/Text/RCTShadowText.h | 2 + Libraries/Text/RCTShadowText.m | 49 +++++++- Libraries/Text/RCTTextManager.m | 3 + Libraries/Text/Text.js | 17 ++- React/Base/RCTConvert.h | 3 +- React/Base/RCTConvert.m | 15 ++- React/Modules/RCTAccessibilityManager.h | 27 +++++ React/Modules/RCTAccessibilityManager.m | 144 ++++++++++++++++++++++++ React/Modules/RCTUIManager.h | 6 + React/Modules/RCTUIManager.m | 26 +++++ React/React.xcodeproj/project.pbxproj | 6 + 14 files changed, 331 insertions(+), 12 deletions(-) create mode 100644 React/Modules/RCTAccessibilityManager.h create mode 100644 React/Modules/RCTAccessibilityManager.m diff --git a/Examples/UIExplorer/TextExample.ios.js b/Examples/UIExplorer/TextExample.ios.js index 4aff00e73..cbc3e5b41 100644 --- a/Examples/UIExplorer/TextExample.ios.js +++ b/Examples/UIExplorer/TextExample.ios.js @@ -369,6 +369,25 @@ exports.examples = [ ); }, +}, { + title: 'allowFontScaling attribute', + render: function() { + return ( + + + By default, text will respect Text Size accessibility setting on iOS. + It means that all font sizes will be increased or descreased depending on the value of Text Size setting in + {" "}Settings.app - Display & Brightness - Text Size + + + You can disable scaling for your Text component by passing {"\""}allowFontScaling={"{"}false{"}\""} prop. + + + This text will not scale. + + + ); + }, }]; var styles = StyleSheet.create({ diff --git a/Libraries/ART/RCTConvert+ART.m b/Libraries/ART/RCTConvert+ART.m index 7a607a12c..e6bc09286 100644 --- a/Libraries/ART/RCTConvert+ART.m +++ b/Libraries/ART/RCTConvert+ART.m @@ -87,7 +87,7 @@ RCT_ENUM_CONVERTER(CTTextAlignment, (@{ } NSDictionary *fontDict = dict[@"font"]; - CTFontRef font = (__bridge CTFontRef)[self UIFont:nil withFamily:fontDict[@"fontFamily"] size:fontDict[@"fontSize"] weight:fontDict[@"fontWeight"] style:fontDict[@"fontStyle"]]; + CTFontRef font = (__bridge CTFontRef)[self UIFont:nil withFamily:fontDict[@"fontFamily"] size:fontDict[@"fontSize"] weight:fontDict[@"fontWeight"] style:fontDict[@"fontStyle"] scaleMultiplier:1.0]; if (!font) { return frame; } diff --git a/Libraries/Text/RCTShadowRawText.m b/Libraries/Text/RCTShadowRawText.m index 00a3490bc..4f79d64b5 100644 --- a/Libraries/Text/RCTShadowRawText.m +++ b/Libraries/Text/RCTShadowRawText.m @@ -9,8 +9,32 @@ #import "RCTShadowRawText.h" +#import "RCTUIManager.h" + @implementation RCTShadowRawText +- (instancetype)init +{ + if ((self = [super init])) { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(contentSizeMultiplierDidChange:) + name:RCTUIManagerWillUpdateViewsDueToContentSizeMultiplierChangeNotification + object:nil]; + } + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (void)contentSizeMultiplierDidChange:(NSNotification *)note +{ + [self dirtyLayout]; + [self dirtyText]; +} + - (void)setText:(NSString *)text { if (_text != text) { diff --git a/Libraries/Text/RCTShadowText.h b/Libraries/Text/RCTShadowText.h index fe87e99c1..abb111879 100644 --- a/Libraries/Text/RCTShadowText.h +++ b/Libraries/Text/RCTShadowText.h @@ -30,6 +30,8 @@ extern NSString *const RCTReactTagAttributeName; @property (nonatomic, strong) UIColor *textDecorationColor; @property (nonatomic, assign) NSUnderlineStyle textDecorationStyle; @property (nonatomic, assign) RCTTextDecorationLineType textDecorationLine; +@property (nonatomic, assign) CGFloat fontSizeMultiplier; +@property (nonatomic, assign) BOOL allowFontScaling; - (void)recomputeText; diff --git a/Libraries/Text/RCTShadowText.m b/Libraries/Text/RCTShadowText.m index 621df1ed6..adcca5aed 100644 --- a/Libraries/Text/RCTShadowText.m +++ b/Libraries/Text/RCTShadowText.m @@ -9,6 +9,9 @@ #import "RCTShadowText.h" +#import "RCTAccessibilityManager.h" +#import "RCTUIManager.h" +#import "RCTBridge.h" #import "RCTConvert.h" #import "RCTLog.h" #import "RCTShadowRawText.h" @@ -51,16 +54,31 @@ static css_dim_t RCTMeasure(void *context, float width) _letterSpacing = NAN; _isHighlighted = NO; _textDecorationStyle = NSUnderlineStyleSingle; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(contentSizeMultiplierDidChange:) + name:RCTUIManagerWillUpdateViewsDueToContentSizeMultiplierChangeNotification + object:nil]; } return self; } +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + - (NSString *)description { NSString *superDescription = super.description; return [[superDescription substringToIndex:superDescription.length - 1] stringByAppendingFormat:@"; text: %@>", [self attributedString].string]; } +- (void)contentSizeMultiplierDidChange:(NSNotification *)note +{ + [self dirtyLayout]; + [self dirtyText]; +} + - (NSDictionary *)processUpdatedProperties:(NSMutableSet *)applierBlocks parentProperties:(NSDictionary *)parentProperties { @@ -190,7 +208,9 @@ static css_dim_t RCTMeasure(void *context, float width) [self _addAttribute:NSBackgroundColorAttributeName withValue:self.backgroundColor toAttributedString:attributedString]; } - UIFont *font = [RCTConvert UIFont:nil withFamily:fontFamily size:fontSize weight:fontWeight style:fontStyle]; + UIFont *font = [RCTConvert UIFont:nil withFamily:fontFamily + size:fontSize weight:fontWeight style:fontStyle + scaleMultiplier:(_allowFontScaling && _fontSizeMultiplier > 0.0 ? _fontSizeMultiplier : 1.0)]; [self _addAttribute:NSFontAttributeName withValue:font toAttributedString:attributedString]; [self _addAttribute:NSKernAttributeName withValue:letterSpacing toAttributedString:attributedString]; [self _addAttribute:RCTReactTagAttributeName withValue:self.reactTag toAttributedString:attributedString]; @@ -247,8 +267,9 @@ static css_dim_t RCTMeasure(void *context, float width) NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; paragraphStyle.alignment = _textAlign; paragraphStyle.baseWritingDirection = _writingDirection; - paragraphStyle.minimumLineHeight = _lineHeight; - paragraphStyle.maximumLineHeight = _lineHeight; + CGFloat lineHeight = round(_lineHeight * self.fontSizeMultiplier); + paragraphStyle.minimumLineHeight = lineHeight; + paragraphStyle.maximumLineHeight = lineHeight; [attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:(NSRange){0, attributedString.length}]; @@ -321,4 +342,26 @@ RCT_TEXT_PROPERTY(TextDecorationLine, _textDecorationLine, RCTTextDecorationLine RCT_TEXT_PROPERTY(TextDecorationStyle, _textDecorationStyle, NSUnderlineStyle); RCT_TEXT_PROPERTY(WritingDirection, _writingDirection, NSWritingDirection) +- (void)setAllowFontScaling:(BOOL)allowFontScaling +{ + _allowFontScaling = allowFontScaling; + for (RCTShadowView *child in [self reactSubviews]) { + if ([child isKindOfClass:[RCTShadowText class]]) { + [(RCTShadowText *)child setAllowFontScaling:allowFontScaling]; + } + } + [self dirtyText]; +} + +- (void)setFontSizeMultiplier:(CGFloat)fontSizeMultiplier +{ + _fontSizeMultiplier = fontSizeMultiplier; + for (RCTShadowView *child in [self reactSubviews]) { + if ([child isKindOfClass:[RCTShadowText class]]) { + [(RCTShadowText *)child setFontSizeMultiplier:fontSizeMultiplier]; + } + } + [self dirtyText]; +} + @end diff --git a/Libraries/Text/RCTTextManager.m b/Libraries/Text/RCTTextManager.m index b5f959b73..06d52088a 100644 --- a/Libraries/Text/RCTTextManager.m +++ b/Libraries/Text/RCTTextManager.m @@ -9,6 +9,7 @@ #import "RCTTextManager.h" +#import "RCTAccessibilityManager.h" #import "RCTAssert.h" #import "RCTConvert.h" #import "RCTLog.h" @@ -49,6 +50,7 @@ RCT_EXPORT_SHADOW_PROPERTY(textDecorationStyle, NSUnderlineStyle) RCT_EXPORT_SHADOW_PROPERTY(textDecorationColor, UIColor) RCT_EXPORT_SHADOW_PROPERTY(textDecorationLine, RCTTextDecorationLineType) RCT_EXPORT_SHADOW_PROPERTY(writingDirection, NSWritingDirection) +RCT_EXPORT_SHADOW_PROPERTY(allowFontScaling, BOOL) - (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(RCTSparseArray *)shadowViewRegistry { @@ -69,6 +71,7 @@ RCT_EXPORT_SHADOW_PROPERTY(writingDirection, NSWritingDirection) RCTAssert([shadowView isTextDirty], @"Don't process any nodes that don't have dirty text"); if ([shadowView isKindOfClass:[RCTShadowText class]]) { + [(RCTShadowText *)shadowView setFontSizeMultiplier:self.bridge.accessibilityManager.multiplier]; [(RCTShadowText *)shadowView recomputeText]; } else if ([shadowView isKindOfClass:[RCTShadowRawText class]]) { RCTLogError(@"Raw text cannot be used outside of a tag. Not rendering string: '%@'", diff --git a/Libraries/Text/Text.js b/Libraries/Text/Text.js index d02733749..7b370ac39 100644 --- a/Libraries/Text/Text.js +++ b/Libraries/Text/Text.js @@ -30,6 +30,7 @@ var viewConfig = { validAttributes: merge(ReactNativeViewAttributes.UIView, { isHighlighted: true, numberOfLines: true, + allowFontScaling: true, }), uiViewClassName: 'RCTText', }; @@ -99,16 +100,27 @@ var Text = React.createClass({ * * {nativeEvent: {layout: {x, y, width, height}}}. */ - onLayout: React.PropTypes.func, + onLayout: React.PropTypes.func, + /** + * Specifies should fonts scale to respect Text Size accessibility setting. + */ + allowFontScaling: React.PropTypes.bool, }, viewConfig: viewConfig, - getInitialState: function() { + getInitialState: function(): Object { return merge(this.touchableGetInitialState(), { isHighlighted: false, }); }, + + getDefaultProps: function(): Object { + return { + numberOfLines: 0, + allowFontScaling: true, + }; + }, onStartShouldSetResponder: function(): bool { var shouldSetFromProps = this.props.onStartShouldSetResponder && @@ -231,6 +243,7 @@ if (Platform.OS === 'android') { RCTVirtualText = createReactNativeComponentClass({ validAttributes: merge(ReactNativeViewAttributes.UIView, { isHighlighted: true, + allowFontScaling: false, }), uiViewClassName: 'RCTVirtualText', }); diff --git a/React/Base/RCTConvert.h b/React/Base/RCTConvert.h index 1b010accd..d4657ec74 100644 --- a/React/Base/RCTConvert.h +++ b/React/Base/RCTConvert.h @@ -91,7 +91,8 @@ typedef NSURL RCTFileURL; + (UIFont *)UIFont:(UIFont *)font withStyle:(id)json; + (UIFont *)UIFont:(UIFont *)font withFamily:(id)json; + (UIFont *)UIFont:(UIFont *)font withFamily:(id)family - size:(id)size weight:(id)weight style:(id)style; + size:(id)size weight:(id)weight style:(id)style + scaleMultiplier:(CGFloat)scaleMultiplier; typedef NSArray NSStringArray; + (NSStringArray *)NSStringArray:(id)json; diff --git a/React/Base/RCTConvert.m b/React/Base/RCTConvert.m index 06e080546..2305a1217 100644 --- a/React/Base/RCTConvert.m +++ b/React/Base/RCTConvert.m @@ -779,31 +779,33 @@ static BOOL RCTFontIsCondensed(UIFont *font) withFamily:json[@"fontFamily"] size:json[@"fontSize"] weight:json[@"fontWeight"] - style:json[@"fontStyle"]]; + style:json[@"fontStyle"] + scaleMultiplier:1.0f]; } + (UIFont *)UIFont:(UIFont *)font withSize:(id)json { - return [self UIFont:font withFamily:nil size:json weight:nil style:nil]; + return [self UIFont:font withFamily:nil size:json weight:nil style:nil scaleMultiplier:1.0]; } + (UIFont *)UIFont:(UIFont *)font withWeight:(id)json { - return [self UIFont:font withFamily:nil size:nil weight:json style:nil]; + return [self UIFont:font withFamily:nil size:nil weight:json style:nil scaleMultiplier:1.0]; } + (UIFont *)UIFont:(UIFont *)font withStyle:(id)json { - return [self UIFont:font withFamily:nil size:nil weight:nil style:json]; + return [self UIFont:font withFamily:nil size:nil weight:nil style:json scaleMultiplier:1.0]; } + (UIFont *)UIFont:(UIFont *)font withFamily:(id)json { - return [self UIFont:font withFamily:json size:nil weight:nil style:nil]; + return [self UIFont:font withFamily:json size:nil weight:nil style:nil scaleMultiplier:1.0]; } + (UIFont *)UIFont:(UIFont *)font withFamily:(id)family size:(id)size weight:(id)weight style:(id)style + scaleMultiplier:(CGFloat)scaleMultiplier { // Defaults NSString *const RCTDefaultFontFamily = @"System"; @@ -828,6 +830,9 @@ static BOOL RCTFontIsCondensed(UIFont *font) // Get font attributes fontSize = [self CGFloat:size] ?: fontSize; + if (scaleMultiplier > 0.0 && scaleMultiplier != 1.0) { + fontSize = round(fontSize * scaleMultiplier); + } familyName = [self NSString:family] ?: familyName; isItalic = style ? [self RCTFontStyle:style] : isItalic; fontWeight = weight ? [self RCTFontWeight:weight] : fontWeight; diff --git a/React/Modules/RCTAccessibilityManager.h b/React/Modules/RCTAccessibilityManager.h new file mode 100644 index 000000000..03d22f945 --- /dev/null +++ b/React/Modules/RCTAccessibilityManager.h @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import + +#import "RCTBridgeModule.h" +#import "RCTBridge.h" + +extern NSString *const RCTAccessibilityManagerDidUpdateMultiplierNotification; // posted when multiplier is changed + +@interface RCTAccessibilityManager : NSObject + +@property (nonatomic, readonly) CGFloat multiplier; + +@end + +@interface RCTBridge (RCTAccessibilityManager) + +@property (nonatomic, readonly) RCTAccessibilityManager *accessibilityManager; + +@end diff --git a/React/Modules/RCTAccessibilityManager.m b/React/Modules/RCTAccessibilityManager.m new file mode 100644 index 000000000..9271b1e3d --- /dev/null +++ b/React/Modules/RCTAccessibilityManager.m @@ -0,0 +1,144 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "RCTAccessibilityManager.h" + +#import "RCTLog.h" + +NSString *const RCTAccessibilityManagerDidUpdateMultiplierNotification = @"RCTAccessibilityManagerDidUpdateMultiplierNotification"; + +@interface RCTAccessibilityManager () + +@property (nonatomic, copy) NSDictionary *multipliers; +@property (nonatomic, copy) NSString *contentSizeCategory; +@property (nonatomic, assign) CGFloat multiplier; + +@end + +@implementation RCTAccessibilityManager + +@synthesize bridge = _bridge; + +RCT_EXPORT_MODULE() + ++ (NSDictionary *)JSToUIKitMap +{ + static NSDictionary *map = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + map = @{@"extraSmall": UIContentSizeCategoryExtraSmall, + @"small": UIContentSizeCategorySmall, + @"medium": UIContentSizeCategoryMedium, + @"large": UIContentSizeCategoryLarge, + @"extraLarge": UIContentSizeCategoryExtraLarge, + @"extraExtraLarge": UIContentSizeCategoryExtraExtraLarge, + @"extraExtraExtraLarge": UIContentSizeCategoryExtraExtraExtraLarge, + @"accessibilityMedium": UIContentSizeCategoryAccessibilityMedium, + @"accessibilityLarge": UIContentSizeCategoryAccessibilityLarge, + @"accessibilityExtraLarge": UIContentSizeCategoryAccessibilityExtraLarge, + @"accessibilityExtraExtraLarge": UIContentSizeCategoryAccessibilityExtraExtraLarge, + @"accessibilityExtraExtraExtraLarge": UIContentSizeCategoryAccessibilityExtraExtraExtraLarge}; + }); + return map; +} + ++ (NSString *)UIKitCategoryFromJSCategory:(NSString *)JSCategory +{ + return self.JSToUIKitMap[JSCategory]; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didReceiveNewContentSizeCategory:) + name:UIContentSizeCategoryDidChangeNotification + object:[UIApplication sharedApplication]]; + self.contentSizeCategory = [[UIApplication sharedApplication] preferredContentSizeCategory]; + } + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (void)didReceiveNewContentSizeCategory:(NSNotification *)note +{ + self.contentSizeCategory = note.userInfo[UIContentSizeCategoryNewValueKey]; +} + +- (void)setContentSizeCategory:(NSString *)contentSizeCategory +{ + if (_contentSizeCategory != contentSizeCategory) { + _contentSizeCategory = [contentSizeCategory copy]; + self.multiplier = [self multiplierForContentSizeCategory:_contentSizeCategory]; + [[NSNotificationCenter defaultCenter] postNotificationName:RCTAccessibilityManagerDidUpdateMultiplierNotification object:self]; + } +} + +- (CGFloat)multiplierForContentSizeCategory:(NSString *)category +{ + NSNumber *m = self.multipliers[category]; + if (m.doubleValue <= 0.0) { + RCTLogError(@"Can't determinte multiplier for category %@. Using 1.0.", category); + m = @1.0; + } + return m.doubleValue; +} + +- (NSDictionary *)multipliers +{ + if (_multipliers == nil) { + _multipliers = @{UIContentSizeCategoryExtraSmall: @0.823, + UIContentSizeCategorySmall: @0.882, + UIContentSizeCategoryMedium: @0.941, + UIContentSizeCategoryLarge: @1.0, + UIContentSizeCategoryExtraLarge: @1.118, + UIContentSizeCategoryExtraExtraLarge: @1.235, + UIContentSizeCategoryExtraExtraExtraLarge: @1.353, + UIContentSizeCategoryAccessibilityMedium: @1.786, + UIContentSizeCategoryAccessibilityLarge: @2.143, + UIContentSizeCategoryAccessibilityExtraLarge: @2.643, + UIContentSizeCategoryAccessibilityExtraExtraLarge: @3.143, + UIContentSizeCategoryAccessibilityExtraExtraExtraLarge: @3.571}; + } + return _multipliers; +} + +RCT_EXPORT_METHOD(setAccessibilityContentSizeMultipliers:(NSDictionary *)JSMultipliers) +{ + NSMutableDictionary *multipliers = [[NSMutableDictionary alloc] init]; + for (NSString *__nonnull JSCategory in JSMultipliers) { + NSNumber *m = JSMultipliers[JSCategory]; + NSString *UIKitCategory = [self.class UIKitCategoryFromJSCategory:JSCategory]; + multipliers[UIKitCategory] = m; + } + self.multipliers = multipliers; +} + +RCT_EXPORT_METHOD(getMultiplier:(RCTResponseSenderBlock)callback) +{ + if (callback) { + callback(@[ @(self.multiplier) ]); + } +} + +@end + +@implementation RCTBridge (RCTAccessibilityManager) + +- (RCTAccessibilityManager *)accessibilityManager +{ + return self.modules[RCTBridgeModuleNameForClass([RCTAccessibilityManager class])]; +} + +@end diff --git a/React/Modules/RCTUIManager.h b/React/Modules/RCTUIManager.h index cbd7c167f..1efedc510 100644 --- a/React/Modules/RCTUIManager.h +++ b/React/Modules/RCTUIManager.h @@ -14,6 +14,12 @@ #import "RCTInvalidating.h" #import "RCTViewManager.h" +/** + * Posted right before re-render happens. This is a chance for views to invalidate their state so + * next render cycle will pick up updated views and layout appropriately. + */ +extern NSString *const RCTUIManagerWillUpdateViewsDueToContentSizeMultiplierChangeNotification; + @protocol RCTScrollableProtocol; /** diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m index f526f5f8c..39cd38a21 100644 --- a/React/Modules/RCTUIManager.m +++ b/React/Modules/RCTUIManager.m @@ -14,6 +14,7 @@ #import #import "Layout.h" +#import "RCTAccessibilityManager.h" #import "RCTAnimationType.h" #import "RCTAssert.h" #import "RCTBridge.h" @@ -35,6 +36,8 @@ static void RCTTraverseViewNodes(id view, void (^block)(id)); static NSDictionary *RCTPropsMerge(NSDictionary *beforeProps, NSDictionary *newProps); +NSString *const RCTUIManagerWillUpdateViewsDueToContentSizeMultiplierChangeNotification = @"RCTUIManagerWillUpdateViewsDueToContentSizeMultiplierChangeNotification"; + @interface RCTAnimation : NSObject @property (nonatomic, readonly) NSTimeInterval duration; @@ -262,10 +265,33 @@ static NSDictionary *RCTViewConfigForModule(Class managerClass) _rootViewTags = [[NSMutableSet alloc] init]; _bridgeTransactionListeners = [[NSMutableSet alloc] init]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didReceiveNewContentSizeMultiplier) + name:RCTAccessibilityManagerDidUpdateMultiplierNotification + object:nil]; } return self; } +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (void)didReceiveNewContentSizeMultiplier +{ + __weak RCTUIManager *weakSelf = self; + dispatch_async(self.methodQueue, ^{ + __weak RCTUIManager *strongSelf = weakSelf; + if (strongSelf) { + [[NSNotificationCenter defaultCenter] postNotificationName:RCTUIManagerWillUpdateViewsDueToContentSizeMultiplierChangeNotification + object:strongSelf]; + [strongSelf batchDidComplete]; + } + }); +} + - (BOOL)isValid { return _viewRegistry != nil; diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj index 5e0434b30..d0bbda232 100644 --- a/React/React.xcodeproj/project.pbxproj +++ b/React/React.xcodeproj/project.pbxproj @@ -75,6 +75,7 @@ 83CBBA691A601EF300E9B192 /* RCTEventDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBA661A601EF300E9B192 /* RCTEventDispatcher.m */; }; 83CBBA981A6020BB00E9B192 /* RCTTouchHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBA971A6020BB00E9B192 /* RCTTouchHandler.m */; }; 83CBBACC1A6023D300E9B192 /* RCTConvert.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBACB1A6023D300E9B192 /* RCTConvert.m */; }; + E9B20B7B1B500126007A2DA7 /* RCTAccessibilityManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E9B20B7A1B500126007A2DA7 /* RCTAccessibilityManager.m */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -239,6 +240,8 @@ 83CBBACA1A6023D300E9B192 /* RCTConvert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTConvert.h; sourceTree = ""; }; 83CBBACB1A6023D300E9B192 /* RCTConvert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTConvert.m; sourceTree = ""; }; E3BBC8EB1ADE6F47001BBD81 /* RCTTextDecorationLineType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTTextDecorationLineType.h; sourceTree = ""; }; + E9B20B791B500126007A2DA7 /* RCTAccessibilityManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAccessibilityManager.h; sourceTree = ""; }; + E9B20B7A1B500126007A2DA7 /* RCTAccessibilityManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAccessibilityManager.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -275,6 +278,8 @@ 13B07FE01A69315300A75B9A /* Modules */ = { isa = PBXGroup; children = ( + E9B20B791B500126007A2DA7 /* RCTAccessibilityManager.h */, + E9B20B7A1B500126007A2DA7 /* RCTAccessibilityManager.m */, 13B07FE71A69327A00A75B9A /* RCTAlertManager.h */, 13B07FE81A69327A00A75B9A /* RCTAlertManager.m */, 1372B7081AB030C200659ED6 /* RCTAppState.h */, @@ -567,6 +572,7 @@ 137327EA1AA5CF210034F82E /* RCTTabBarManager.m in Sources */, 13B080261A694A8400A75B9A /* RCTWrapperViewController.m in Sources */, 13B080051A6947C200A75B9A /* RCTScrollView.m in Sources */, + E9B20B7B1B500126007A2DA7 /* RCTAccessibilityManager.m in Sources */, 13B07FF21A69327A00A75B9A /* RCTTiming.m in Sources */, 1372B70A1AB030C200659ED6 /* RCTAppState.m in Sources */, 134FCB3D1A6E7F0800051CC8 /* RCTContextExecutor.m in Sources */,