[React Native] #WIP Modify RCTShadowText measure function to honor maxNumberOfLines property

This commit is contained in:
Alex Akers 2015-04-07 02:19:49 -07:00
parent 2aa52880b7
commit 397d4666d9
5 changed files with 77 additions and 44 deletions

View File

@ -23,7 +23,7 @@ extern NSString *const RCTReactTagAttributeName;
@property (nonatomic, copy) NSString *fontStyle; @property (nonatomic, copy) NSString *fontStyle;
@property (nonatomic, assign) BOOL isHighlighted; @property (nonatomic, assign) BOOL isHighlighted;
@property (nonatomic, assign) CGFloat lineHeight; @property (nonatomic, assign) CGFloat lineHeight;
@property (nonatomic, assign) NSInteger maxNumberOfLines; @property (nonatomic, assign) NSUInteger maximumNumberOfLines;
@property (nonatomic, assign) CGSize shadowOffset; @property (nonatomic, assign) CGSize shadowOffset;
@property (nonatomic, assign) NSTextAlignment textAlign; @property (nonatomic, assign) NSTextAlignment textAlign;
@ -31,6 +31,8 @@ extern NSString *const RCTReactTagAttributeName;
@property (nonatomic, strong) UIFont *font; @property (nonatomic, strong) UIFont *font;
@property (nonatomic, assign) NSLineBreakMode truncationMode; @property (nonatomic, assign) NSLineBreakMode truncationMode;
- (NSAttributedString *)attributedString; @property (nonatomic, copy, readonly) NSAttributedString *attributedString;
@property (nonatomic, strong, readonly) NSLayoutManager *layoutManager;
@property (nonatomic, strong, readonly) NSTextContainer *textContainer;
@end @end

View File

@ -20,9 +20,17 @@ NSString *const RCTReactTagAttributeName = @"ReactTagAttributeName";
static css_dim_t RCTMeasure(void *context, float width) static css_dim_t RCTMeasure(void *context, float width)
{ {
RCTShadowText *shadowText = (__bridge RCTShadowText *)context; RCTShadowText *shadowText = (__bridge RCTShadowText *)context;
CGSize computedSize = [[shadowText attributedString] boundingRectWithSize:(CGSize){isnan(width) ? CGFLOAT_MAX : width, CGFLOAT_MAX}
options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:[shadowText attributedString]];
context:nil].size; [textStorage addLayoutManager:shadowText.layoutManager];
shadowText.textContainer.size = CGSizeMake(isnan(width) ? CGFLOAT_MAX : width, CGFLOAT_MAX);
shadowText.layoutManager.textStorage = textStorage;
[shadowText.layoutManager ensureLayoutForTextContainer:shadowText.textContainer];
CGSize computedSize = [shadowText.layoutManager usedRectForTextContainer:shadowText.textContainer].size;
[textStorage removeLayoutManager:shadowText.layoutManager];
css_dim_t result; css_dim_t result;
result.dimensions[CSS_WIDTH] = RCTCeilPixelValue(computedSize.width); result.dimensions[CSS_WIDTH] = RCTCeilPixelValue(computedSize.width);
@ -30,8 +38,9 @@ static css_dim_t RCTMeasure(void *context, float width)
return result; return result;
} }
@implementation RCTShadowText @implementation RCTShadowText {
{ NSLayoutManager *_layoutManager;
NSTextContainer *_textContainer;
NSAttributedString *_cachedAttributedString; NSAttributedString *_cachedAttributedString;
UIFont *_font; UIFont *_font;
} }
@ -41,7 +50,15 @@ static css_dim_t RCTMeasure(void *context, float width)
if ((self = [super init])) { if ((self = [super init])) {
_fontSize = NAN; _fontSize = NAN;
_isHighlighted = NO; _isHighlighted = NO;
_textContainer = [[NSTextContainer alloc] init];
_textContainer.lineBreakMode = NSLineBreakByTruncatingTail;
_textContainer.lineFragmentPadding = 0.0;
_layoutManager = [[NSLayoutManager alloc] init];
[_layoutManager addTextContainer:_textContainer];
} }
return self; return self;
} }
@ -201,11 +218,31 @@ RCT_TEXT_PROPERTY(FontFamily, _fontFamily, NSString *);
RCT_TEXT_PROPERTY(FontSize, _fontSize, CGFloat); RCT_TEXT_PROPERTY(FontSize, _fontSize, CGFloat);
RCT_TEXT_PROPERTY(FontWeight, _fontWeight, NSString *); RCT_TEXT_PROPERTY(FontWeight, _fontWeight, NSString *);
RCT_TEXT_PROPERTY(LineHeight, _lineHeight, CGFloat); RCT_TEXT_PROPERTY(LineHeight, _lineHeight, CGFloat);
RCT_TEXT_PROPERTY(MaxNumberOfLines, _maxNumberOfLines, NSInteger);
RCT_TEXT_PROPERTY(ShadowOffset, _shadowOffset, CGSize); RCT_TEXT_PROPERTY(ShadowOffset, _shadowOffset, CGSize);
RCT_TEXT_PROPERTY(TextAlign, _textAlign, NSTextAlignment); RCT_TEXT_PROPERTY(TextAlign, _textAlign, NSTextAlignment);
RCT_TEXT_PROPERTY(TruncationMode, _truncationMode, NSLineBreakMode);
RCT_TEXT_PROPERTY(IsHighlighted, _isHighlighted, BOOL); RCT_TEXT_PROPERTY(IsHighlighted, _isHighlighted, BOOL);
RCT_TEXT_PROPERTY(Font, _font, UIFont *); RCT_TEXT_PROPERTY(Font, _font, UIFont *);
- (NSLineBreakMode)truncationMode
{
return _textContainer.lineBreakMode;
}
- (void)setTruncationMode:(NSLineBreakMode)truncationMode
{
_textContainer.lineBreakMode = truncationMode;
[self dirtyText];
}
- (NSUInteger)maximumNumberOfLines
{
return _textContainer.maximumNumberOfLines;
}
- (void)setMaximumNumberOfLines:(NSUInteger)maximumNumberOfLines
{
_textContainer.maximumNumberOfLines = maximumNumberOfLines;
[self dirtyText];
}
@end @end

View File

@ -11,9 +11,10 @@
@interface RCTText : UIView @interface RCTText : UIView
@property (nonatomic, strong) NSLayoutManager *layoutManager;
@property (nonatomic, strong) NSTextContainer *textContainer;
@property (nonatomic, copy) NSAttributedString *attributedText; @property (nonatomic, copy) NSAttributedString *attributedText;
@property (nonatomic, assign) NSLineBreakMode lineBreakMode;
@property (nonatomic, assign) NSUInteger numberOfLines;
@property (nonatomic, assign) UIEdgeInsets contentInset; @property (nonatomic, assign) UIEdgeInsets contentInset;
@end @end

View File

@ -23,15 +23,7 @@
- (instancetype)initWithFrame:(CGRect)frame - (instancetype)initWithFrame:(CGRect)frame
{ {
if ((self = [super initWithFrame:frame])) { if ((self = [super initWithFrame:frame])) {
_textContainer = [[NSTextContainer alloc] init];
_textContainer.lineBreakMode = NSLineBreakByTruncatingTail;
_textContainer.lineFragmentPadding = 0.0;
_layoutManager = [[NSLayoutManager alloc] init];
[_layoutManager addTextContainer:_textContainer];
_textStorage = [[NSTextStorage alloc] init]; _textStorage = [[NSTextStorage alloc] init];
[_textStorage addLayoutManager:_layoutManager];
self.contentMode = UIViewContentModeRedraw; self.contentMode = UIViewContentModeRedraw;
} }
@ -50,25 +42,31 @@
[self setNeedsDisplay]; [self setNeedsDisplay];
} }
- (NSUInteger)numberOfLines - (void)setTextContainer:(NSTextContainer *)textContainer
{ {
return _textContainer.maximumNumberOfLines; if ([_textContainer isEqual:textContainer]) return;
}
_textContainer = textContainer;
for (NSInteger i = _layoutManager.textContainers.count - 1; i >= 0; i--) {
[_layoutManager removeTextContainerAtIndex:i];
}
[_layoutManager addTextContainer:_textContainer];
- (void)setNumberOfLines:(NSUInteger)numberOfLines
{
_textContainer.maximumNumberOfLines = numberOfLines;
[self setNeedsDisplay]; [self setNeedsDisplay];
} }
- (NSLineBreakMode)lineBreakMode - (void)setLayoutManager:(NSLayoutManager *)layoutManager
{ {
return _textContainer.lineBreakMode; if ([_layoutManager isEqual:layoutManager]) return;
}
_layoutManager = layoutManager;
for (NSLayoutManager *layoutManager in _textStorage.layoutManagers) {
[_textStorage removeLayoutManager:layoutManager];
}
[_textStorage addLayoutManager:_layoutManager];
- (void)setLineBreakMode:(NSLineBreakMode)lineBreakMode
{
_textContainer.lineBreakMode = lineBreakMode;
[self setNeedsDisplay]; [self setNeedsDisplay];
} }

View File

@ -33,15 +33,6 @@
#pragma mark - View properties #pragma mark - View properties
RCT_REMAP_VIEW_PROPERTY(containerBackgroundColor, backgroundColor, UIColor) RCT_REMAP_VIEW_PROPERTY(containerBackgroundColor, backgroundColor, UIColor)
RCT_CUSTOM_VIEW_PROPERTY(numberOfLines, NSInteger, RCTText)
{
NSLineBreakMode truncationMode = NSLineBreakByClipping;
view.numberOfLines = json ? [RCTConvert NSInteger:json] : defaultView.numberOfLines;
if (view.numberOfLines > 0) {
truncationMode = NSLineBreakByTruncatingTail;
}
view.lineBreakMode = truncationMode;
}
#pragma mark - Shadow properties #pragma mark - Shadow properties
@ -65,8 +56,8 @@ RCT_CUSTOM_SHADOW_PROPERTY(containerBackgroundColor, UIColor, RCTShadowText)
RCT_CUSTOM_SHADOW_PROPERTY(numberOfLines, NSInteger, RCTShadowText) RCT_CUSTOM_SHADOW_PROPERTY(numberOfLines, NSInteger, RCTShadowText)
{ {
NSLineBreakMode truncationMode = NSLineBreakByClipping; NSLineBreakMode truncationMode = NSLineBreakByClipping;
view.maxNumberOfLines = json ? [RCTConvert NSInteger:json] : defaultView.maxNumberOfLines; view.maximumNumberOfLines = json ? [RCTConvert NSInteger:json] : defaultView.maximumNumberOfLines;
if (view.maxNumberOfLines > 0) { if (view.maximumNumberOfLines > 0) {
truncationMode = NSLineBreakByTruncatingTail; truncationMode = NSLineBreakByTruncatingTail;
} }
view.truncationMode = truncationMode; view.truncationMode = truncationMode;
@ -124,12 +115,16 @@ RCT_CUSTOM_SHADOW_PROPERTY(numberOfLines, NSInteger, RCTShadowText)
}; };
} }
- (RCTViewManagerUIBlock)uiBlockToAmendWithShadowView:(RCTShadowView *)shadowView - (RCTViewManagerUIBlock)uiBlockToAmendWithShadowView:(RCTShadowText *)shadowView
{ {
NSNumber *reactTag = shadowView.reactTag; NSNumber *reactTag = shadowView.reactTag;
UIEdgeInsets padding = shadowView.paddingAsInsets; UIEdgeInsets padding = shadowView.paddingAsInsets;
return ^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) { return ^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) {
((RCTText *)viewRegistry[reactTag]).contentInset = padding; RCTText *text = (RCTText *)viewRegistry[reactTag];
text.contentInset = padding;
text.layoutManager = shadowView.layoutManager;
text.textContainer = shadowView.textContainer;
}; };
} }