104 lines
3.0 KiB
Objective-C
104 lines
3.0 KiB
Objective-C
/**
|
|
* 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 "RCTText.h"
|
|
|
|
#import "RCTShadowText.h"
|
|
#import "RCTUtils.h"
|
|
#import "UIView+React.h"
|
|
|
|
@implementation RCTText
|
|
{
|
|
NSTextStorage *_textStorage;
|
|
NSMutableArray *_reactSubviews;
|
|
}
|
|
|
|
- (instancetype)initWithFrame:(CGRect)frame
|
|
{
|
|
if ((self = [super initWithFrame:frame])) {
|
|
_textStorage = [[NSTextStorage alloc] init];
|
|
_reactSubviews = [NSMutableArray array];
|
|
|
|
self.isAccessibilityElement = YES;
|
|
self.accessibilityTraits |= UIAccessibilityTraitStaticText;
|
|
|
|
self.opaque = NO;
|
|
self.contentMode = UIViewContentModeRedraw;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)reactSetFrame:(CGRect)frame
|
|
{
|
|
// Text looks super weird if its frame is animated.
|
|
// This disables the frame animation, without affecting opacity, etc.
|
|
[UIView performWithoutAnimation:^{
|
|
[super reactSetFrame:frame];
|
|
}];
|
|
}
|
|
|
|
- (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex
|
|
{
|
|
[_reactSubviews insertObject:subview atIndex:atIndex];
|
|
}
|
|
|
|
- (void)removeReactSubview:(UIView *)subview
|
|
{
|
|
[_reactSubviews removeObject:subview];
|
|
}
|
|
|
|
- (NSMutableArray *)reactSubviews
|
|
{
|
|
return _reactSubviews;
|
|
}
|
|
|
|
- (void)setTextStorage:(NSTextStorage *)textStorage
|
|
{
|
|
_textStorage = textStorage;
|
|
[self setNeedsDisplay];
|
|
}
|
|
|
|
- (void)drawRect:(CGRect)rect
|
|
{
|
|
NSLayoutManager *layoutManager = [_textStorage.layoutManagers firstObject];
|
|
NSTextContainer *textContainer = [layoutManager.textContainers firstObject];
|
|
CGRect textFrame = UIEdgeInsetsInsetRect(self.bounds, _contentInset);
|
|
NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer];
|
|
[layoutManager drawBackgroundForGlyphRange:glyphRange atPoint:textFrame.origin];
|
|
[layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:textFrame.origin];
|
|
}
|
|
|
|
- (NSNumber *)reactTagAtPoint:(CGPoint)point
|
|
{
|
|
NSNumber *reactTag = self.reactTag;
|
|
|
|
CGFloat fraction;
|
|
NSLayoutManager *layoutManager = [_textStorage.layoutManagers firstObject];
|
|
NSTextContainer *textContainer = [layoutManager.textContainers firstObject];
|
|
NSUInteger characterIndex = [layoutManager characterIndexForPoint:point
|
|
inTextContainer:textContainer
|
|
fractionOfDistanceBetweenInsertionPoints:&fraction];
|
|
|
|
// If the point is not before (fraction == 0.0) the first character and not
|
|
// after (fraction == 1.0) the last character, then the attribute is valid.
|
|
if (_textStorage.length > 0 && (fraction > 0 || characterIndex > 0) && (fraction < 1 || characterIndex < _textStorage.length - 1)) {
|
|
reactTag = [_textStorage attribute:RCTReactTagAttributeName atIndex:characterIndex effectiveRange:NULL];
|
|
}
|
|
return reactTag;
|
|
}
|
|
|
|
#pragma mark - Accessibility
|
|
|
|
- (NSString *)accessibilityLabel
|
|
{
|
|
return _textStorage.string;
|
|
}
|
|
|
|
@end
|