mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-02-13 09:20:15 +08:00
Dynamic Text Sizes for Text component
Summary: Dynamic Text Sizes for Text component. Text gains new prop - allowFontScaling (false by default). There is also AccessibilityManager module that allows you to tune multipliers per each content size category.
This commit is contained in:
27
React/Modules/RCTAccessibilityManager.h
Normal file
27
React/Modules/RCTAccessibilityManager.h
Normal file
@@ -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 <Foundation/Foundation.h>
|
||||
|
||||
#import "RCTBridgeModule.h"
|
||||
#import "RCTBridge.h"
|
||||
|
||||
extern NSString *const RCTAccessibilityManagerDidUpdateMultiplierNotification; // posted when multiplier is changed
|
||||
|
||||
@interface RCTAccessibilityManager : NSObject <RCTBridgeModule>
|
||||
|
||||
@property (nonatomic, readonly) CGFloat multiplier;
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTBridge (RCTAccessibilityManager)
|
||||
|
||||
@property (nonatomic, readonly) RCTAccessibilityManager *accessibilityManager;
|
||||
|
||||
@end
|
||||
144
React/Modules/RCTAccessibilityManager.m
Normal file
144
React/Modules/RCTAccessibilityManager.m
Normal file
@@ -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
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
#import "Layout.h"
|
||||
#import "RCTAccessibilityManager.h"
|
||||
#import "RCTAnimationType.h"
|
||||
#import "RCTAssert.h"
|
||||
#import "RCTBridge.h"
|
||||
@@ -42,6 +43,8 @@ static void RCTTraverseViewNodes(id<RCTViewNodeProtocol> view, react_view_node_b
|
||||
}
|
||||
}
|
||||
|
||||
NSString *const RCTUIManagerWillUpdateViewsDueToContentSizeMultiplierChangeNotification = @"RCTUIManagerWillUpdateViewsDueToContentSizeMultiplierChangeNotification";
|
||||
|
||||
@interface RCTAnimation : NSObject
|
||||
|
||||
@property (nonatomic, readonly) NSTimeInterval duration;
|
||||
@@ -269,10 +272,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;
|
||||
|
||||
Reference in New Issue
Block a user