mirror of
https://github.com/status-im/react-native.git
synced 2025-02-26 08:05:34 +00:00
Test perf effect of reverting D3269333
Reviewed By: javache Differential Revision: D3346235 fbshipit-source-id: 2008f8fb9df5d61da59bb0067b25acd5a71f256f
This commit is contained in:
parent
60e0d2c676
commit
a4b5f1bf10
@ -422,13 +422,12 @@ exports.examples = [
|
||||
);
|
||||
},
|
||||
}, {
|
||||
title: 'Inline views',
|
||||
title: 'Inline images',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<Text>
|
||||
This text contains an inline blue view <View style={{width: 25, height: 25, backgroundColor: 'steelblue'}} /> and
|
||||
an inline image <Image source={require('./flux.png')} style={{width: 30, height: 11, resizeMode: 'cover'}}/>. Neat, huh?
|
||||
This text contains an inline image <Image source={require('./flux.png')} style={{width: 30, height: 11, resizeMode: 'cover'}}/>. Neat, huh?
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
|
@ -201,6 +201,10 @@ var Image = React.createClass({
|
||||
validAttributes: ReactNativeViewAttributes.UIView
|
||||
},
|
||||
|
||||
contextTypes: {
|
||||
isInAParentText: React.PropTypes.bool
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var source = resolveAssetSource(this.props.source) || {};
|
||||
var {width, height, uri} = source;
|
||||
@ -221,6 +225,13 @@ var Image = React.createClass({
|
||||
console.warn('The <Image> component requires a `source` property rather than `src`.');
|
||||
}
|
||||
|
||||
if (this.context.isInAParentText) {
|
||||
RawImage = RCTVirtualImage;
|
||||
if (!width || !height) {
|
||||
console.warn('You must specify a width and height for the image %s', uri);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<RawImage
|
||||
{...this.props}
|
||||
@ -241,6 +252,7 @@ var styles = StyleSheet.create({
|
||||
|
||||
var RCTImageView = requireNativeComponent('RCTImageView', Image);
|
||||
var RCTNetworkImageView = NetworkImageViewManager ? requireNativeComponent('RCTNetworkImageView', Image) : RCTImageView;
|
||||
var RCTVirtualImage = requireNativeComponent('RCTVirtualImage', Image);
|
||||
|
||||
|
||||
module.exports = Image;
|
||||
|
@ -44,6 +44,10 @@
|
||||
134B00A11B54232B00EC8DFB /* RCTImageUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageUtils.m; sourceTree = "<group>"; };
|
||||
139A38821C4D57AD00862840 /* RCTResizeMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTResizeMode.h; sourceTree = "<group>"; };
|
||||
139A38831C4D587C00862840 /* RCTResizeMode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTResizeMode.m; sourceTree = "<group>"; };
|
||||
13EF7F071BC42D4E003F47DD /* RCTShadowVirtualImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTShadowVirtualImage.h; sourceTree = "<group>"; };
|
||||
13EF7F081BC42D4E003F47DD /* RCTShadowVirtualImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTShadowVirtualImage.m; sourceTree = "<group>"; };
|
||||
13EF7F091BC42D4E003F47DD /* RCTVirtualImageManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTVirtualImageManager.h; sourceTree = "<group>"; };
|
||||
13EF7F0A1BC42D4E003F47DD /* RCTVirtualImageManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTVirtualImageManager.m; sourceTree = "<group>"; };
|
||||
13EF7F7D1BC825B1003F47DD /* RCTXCAssetImageLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTXCAssetImageLoader.h; sourceTree = "<group>"; };
|
||||
13EF7F7E1BC825B1003F47DD /* RCTXCAssetImageLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTXCAssetImageLoader.m; sourceTree = "<group>"; };
|
||||
143879361AAD32A300F088A5 /* RCTImageLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTImageLoader.h; sourceTree = "<group>"; };
|
||||
@ -91,6 +95,10 @@
|
||||
35123E6A1B59C99D00EBAD80 /* RCTImageStoreManager.m */,
|
||||
134B00A01B54232B00EC8DFB /* RCTImageUtils.h */,
|
||||
134B00A11B54232B00EC8DFB /* RCTImageUtils.m */,
|
||||
13EF7F071BC42D4E003F47DD /* RCTShadowVirtualImage.h */,
|
||||
13EF7F081BC42D4E003F47DD /* RCTShadowVirtualImage.m */,
|
||||
13EF7F091BC42D4E003F47DD /* RCTVirtualImageManager.h */,
|
||||
13EF7F0A1BC42D4E003F47DD /* RCTVirtualImageManager.m */,
|
||||
58B5115E1A9E6B3D00147676 /* Products */,
|
||||
);
|
||||
indentWidth = 2;
|
||||
@ -161,6 +169,7 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
13EF7F0C1BC42D4E003F47DD /* RCTVirtualImageManager.m in Sources */,
|
||||
35123E6B1B59C99D00EBAD80 /* RCTImageStoreManager.m in Sources */,
|
||||
1304D5AC1AA8C4A30002E2BE /* RCTImageViewManager.m in Sources */,
|
||||
1304D5B21AA8C50D0002E2BE /* RCTGIFImageDecoder.m in Sources */,
|
||||
@ -169,6 +178,7 @@
|
||||
139A38841C4D587C00862840 /* RCTResizeMode.m in Sources */,
|
||||
1304D5AB1AA8C4A30002E2BE /* RCTImageView.m in Sources */,
|
||||
EEF314721C9B0DD30049118E /* RCTImageBlurUtils.m in Sources */,
|
||||
13EF7F0B1BC42D4E003F47DD /* RCTShadowVirtualImage.m in Sources */,
|
||||
13EF7F7F1BC825B1003F47DD /* RCTXCAssetImageLoader.m in Sources */,
|
||||
134B00A21B54232B00EC8DFB /* RCTImageUtils.m in Sources */,
|
||||
);
|
||||
|
@ -8,12 +8,13 @@
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "RCTImageComponent.h"
|
||||
#import "RCTResizeMode.h"
|
||||
|
||||
@class RCTBridge;
|
||||
@class RCTImageSource;
|
||||
|
||||
@interface RCTImageView : UIImageView
|
||||
@interface RCTImageView : UIImageView <RCTImageComponent>
|
||||
|
||||
- (instancetype)initWithBridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
|
28
Libraries/Image/RCTShadowVirtualImage.h
Normal file
28
Libraries/Image/RCTShadowVirtualImage.h
Normal file
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 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 "RCTShadowView.h"
|
||||
#import "RCTImageComponent.h"
|
||||
#import "RCTImageSource.h"
|
||||
#import "RCTResizeMode.h"
|
||||
|
||||
@class RCTBridge;
|
||||
|
||||
/**
|
||||
* Shadow image component, used for embedding images in non-view contexts such
|
||||
* as text. This is NOT used for ordinary <Image> views.
|
||||
*/
|
||||
@interface RCTShadowVirtualImage : RCTShadowView <RCTImageComponent>
|
||||
|
||||
- (instancetype)initWithBridge:(RCTBridge *)bridge;
|
||||
|
||||
@property (nonatomic, strong) RCTImageSource *source;
|
||||
@property (nonatomic, assign) RCTResizeMode resizeMode;
|
||||
|
||||
@end
|
82
Libraries/Image/RCTShadowVirtualImage.m
Normal file
82
Libraries/Image/RCTShadowVirtualImage.m
Normal file
@ -0,0 +1,82 @@
|
||||
/**
|
||||
* 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 "RCTShadowVirtualImage.h"
|
||||
#import "RCTImageLoader.h"
|
||||
#import "RCTImageUtils.h"
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTUIManager.h"
|
||||
#import "RCTUtils.h"
|
||||
|
||||
@implementation RCTShadowVirtualImage
|
||||
{
|
||||
RCTBridge *_bridge;
|
||||
RCTImageLoaderCancellationBlock _cancellationBlock;
|
||||
}
|
||||
|
||||
@synthesize image = _image;
|
||||
|
||||
- (instancetype)initWithBridge:(RCTBridge *)bridge
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_bridge = bridge;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
RCT_NOT_IMPLEMENTED(-(instancetype)init)
|
||||
|
||||
- (void)didSetProps:(NSArray<NSString *> *)changedProps
|
||||
{
|
||||
[super didSetProps:changedProps];
|
||||
|
||||
if (changedProps.count == 0) {
|
||||
// No need to reload image
|
||||
return;
|
||||
}
|
||||
|
||||
// Cancel previous request
|
||||
if (_cancellationBlock) {
|
||||
_cancellationBlock();
|
||||
}
|
||||
|
||||
CGSize imageSize = {
|
||||
RCTZeroIfNaN(self.width),
|
||||
RCTZeroIfNaN(self.height),
|
||||
};
|
||||
|
||||
__weak RCTShadowVirtualImage *weakSelf = self;
|
||||
_cancellationBlock = [_bridge.imageLoader loadImageWithTag:_source.imageURL.absoluteString
|
||||
size:imageSize
|
||||
scale:RCTScreenScale()
|
||||
resizeMode:_resizeMode
|
||||
progressBlock:nil
|
||||
completionBlock:^(NSError *error, UIImage *image) {
|
||||
|
||||
dispatch_async(_bridge.uiManager.methodQueue, ^{
|
||||
RCTShadowVirtualImage *strongSelf = weakSelf;
|
||||
if (![_source isEqual:strongSelf.source]) {
|
||||
// Bail out if source has changed since we started loading
|
||||
return;
|
||||
}
|
||||
strongSelf->_image = image;
|
||||
[strongSelf dirtyText];
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (_cancellationBlock) {
|
||||
_cancellationBlock();
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
14
Libraries/Image/RCTVirtualImageManager.h
Normal file
14
Libraries/Image/RCTVirtualImageManager.h
Normal file
@ -0,0 +1,14 @@
|
||||
/**
|
||||
* 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 "RCTViewManager.h"
|
||||
|
||||
@interface RCTVirtualImageManager : RCTViewManager
|
||||
|
||||
@end
|
25
Libraries/Image/RCTVirtualImageManager.m
Normal file
25
Libraries/Image/RCTVirtualImageManager.m
Normal file
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* 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 "RCTVirtualImageManager.h"
|
||||
#import "RCTShadowVirtualImage.h"
|
||||
|
||||
@implementation RCTVirtualImageManager
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (RCTShadowView *)shadowView
|
||||
{
|
||||
return [[RCTShadowVirtualImage alloc] initWithBridge:self.bridge];
|
||||
}
|
||||
|
||||
RCT_EXPORT_SHADOW_PROPERTY(source, RCTImageSource)
|
||||
RCT_EXPORT_SHADOW_PROPERTY(resizeMode, UIViewContentMode)
|
||||
|
||||
@end
|
@ -13,12 +13,12 @@
|
||||
#import "RCTUIManager.h"
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTImageComponent.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTShadowRawText.h"
|
||||
#import "RCTText.h"
|
||||
#import "RCTUtils.h"
|
||||
|
||||
NSString *const RCTShadowViewAttributeName = @"RCTShadowViewAttributeName";
|
||||
NSString *const RCTIsHighlightedAttributeName = @"IsHighlightedAttributeName";
|
||||
NSString *const RCTReactTagAttributeName = @"ReactTagAttributeName";
|
||||
|
||||
@ -114,45 +114,6 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width
|
||||
[self dirtyPropagation];
|
||||
}
|
||||
|
||||
- (void)applyLayoutToChildren:(css_node_t *)node
|
||||
viewsWithNewFrame:(NSMutableSet<RCTShadowView *> *)viewsWithNewFrame
|
||||
absolutePosition:(CGPoint)absolutePosition
|
||||
{
|
||||
// Run layout on subviews.
|
||||
NSTextStorage *textStorage = [self buildTextStorageForWidth:self.frame.size.width widthMode:CSS_MEASURE_MODE_EXACTLY];
|
||||
NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject;
|
||||
NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
|
||||
NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer];
|
||||
NSRange characterRange = [layoutManager characterRangeForGlyphRange:glyphRange actualGlyphRange:NULL];
|
||||
[layoutManager.textStorage enumerateAttribute:RCTShadowViewAttributeName inRange:characterRange options:0 usingBlock:^(RCTShadowView *child, NSRange range, BOOL *_) {
|
||||
if (child != nil) {
|
||||
css_node_t *childNode = child.cssNode;
|
||||
float width = childNode->style.dimensions[CSS_WIDTH];
|
||||
float height = childNode->style.dimensions[CSS_HEIGHT];
|
||||
if (isUndefined(width) || isUndefined(height)) {
|
||||
RCTLogError(@"Views nested within a <Text> must have a width and height");
|
||||
}
|
||||
UIFont *font = [textStorage attribute:NSFontAttributeName atIndex:range.location effectiveRange:nil];
|
||||
CGRect glyphRect = [layoutManager boundingRectForGlyphRange:range inTextContainer:textContainer];
|
||||
CGRect childFrame = {{
|
||||
RCTRoundPixelValue(glyphRect.origin.x),
|
||||
RCTRoundPixelValue(glyphRect.origin.y + glyphRect.size.height - height + font.descender)
|
||||
}, {
|
||||
RCTRoundPixelValue(width),
|
||||
RCTRoundPixelValue(height)
|
||||
}};
|
||||
|
||||
NSRange truncatedGlyphRange = [layoutManager truncatedGlyphRangeInLineFragmentForGlyphAtIndex:range.location];
|
||||
BOOL childIsTruncated = NSIntersectionRange(range, truncatedGlyphRange).length != 0;
|
||||
|
||||
[child collectUpdatedFrames:viewsWithNewFrame
|
||||
withFrame:childFrame
|
||||
hidden:childIsTruncated
|
||||
absolutePosition:absolutePosition];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (NSTextStorage *)buildTextStorageForWidth:(CGFloat)width widthMode:(css_measure_mode_t)widthMode
|
||||
{
|
||||
if (_cachedTextStorage && width == _cachedTextStorageWidth && widthMode == _cachedTextStorageWidthMode) {
|
||||
@ -238,48 +199,33 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width
|
||||
|
||||
_effectiveLetterSpacing = letterSpacing.doubleValue;
|
||||
|
||||
UIFont *font = [RCTConvert UIFont:nil withFamily:fontFamily
|
||||
size:fontSize weight:fontWeight style:fontStyle
|
||||
scaleMultiplier:_allowFontScaling ? _fontSizeMultiplier : 1.0];
|
||||
|
||||
CGFloat heightOfTallestSubview = 0.0;
|
||||
NSMutableAttributedString *attributedString = [NSMutableAttributedString new];
|
||||
for (RCTShadowView *child in [self reactSubviews]) {
|
||||
if ([child isKindOfClass:[RCTShadowText class]]) {
|
||||
RCTShadowText *shadowText = (RCTShadowText *)child;
|
||||
[attributedString appendAttributedString:
|
||||
[shadowText _attributedStringWithFontFamily:fontFamily
|
||||
fontSize:fontSize
|
||||
fontWeight:fontWeight
|
||||
fontStyle:fontStyle
|
||||
letterSpacing:letterSpacing
|
||||
useBackgroundColor:YES
|
||||
foregroundColor:shadowText.color ?: foregroundColor
|
||||
backgroundColor:shadowText.backgroundColor ?: backgroundColor
|
||||
opacity:opacity * shadowText.opacity]];
|
||||
[child setTextComputed];
|
||||
[shadowText _attributedStringWithFontFamily:fontFamily
|
||||
fontSize:fontSize
|
||||
fontWeight:fontWeight
|
||||
fontStyle:fontStyle
|
||||
letterSpacing:letterSpacing
|
||||
useBackgroundColor:YES
|
||||
foregroundColor:shadowText.color ?: foregroundColor
|
||||
backgroundColor:shadowText.backgroundColor ?: backgroundColor
|
||||
opacity:opacity * shadowText.opacity]];
|
||||
} else if ([child isKindOfClass:[RCTShadowRawText class]]) {
|
||||
RCTShadowRawText *shadowRawText = (RCTShadowRawText *)child;
|
||||
[attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:shadowRawText.text ?: @""]];
|
||||
[child setTextComputed];
|
||||
} else if ([child conformsToProtocol:@protocol(RCTImageComponent)]) {
|
||||
NSTextAttachment *imageAttachment = [NSTextAttachment new];
|
||||
imageAttachment.image = ((id<RCTImageComponent>)child).image;
|
||||
imageAttachment.bounds = (CGRect){CGPointZero, {RCTZeroIfNaN(child.width), RCTZeroIfNaN(child.height)}};
|
||||
[attributedString appendAttributedString:[NSAttributedString attributedStringWithAttachment:imageAttachment]];
|
||||
} else {
|
||||
float width = child.cssNode->style.dimensions[CSS_WIDTH];
|
||||
float height = child.cssNode->style.dimensions[CSS_HEIGHT];
|
||||
if (isUndefined(width) || isUndefined(height)) {
|
||||
RCTLogError(@"Views nested within a <Text> must have a width and height");
|
||||
}
|
||||
NSTextAttachment *attachment = [NSTextAttachment new];
|
||||
attachment.bounds = (CGRect){CGPointZero, {width, height}};
|
||||
NSMutableAttributedString *attachmentString = [NSMutableAttributedString new];
|
||||
[attachmentString appendAttributedString:[NSAttributedString attributedStringWithAttachment:attachment]];
|
||||
[attachmentString addAttribute:RCTShadowViewAttributeName value:child range:(NSRange){0, attachmentString.length}];
|
||||
[attributedString appendAttributedString:attachmentString];
|
||||
if (height > heightOfTallestSubview) {
|
||||
heightOfTallestSubview = height;
|
||||
}
|
||||
// Don't call setTextComputed on this child. RCTTextManager takes care of
|
||||
// processing inline UIViews.
|
||||
RCTLogError(@"<Text> can't have any children except <Text>, <Image> or raw strings");
|
||||
}
|
||||
|
||||
[child setTextComputed];
|
||||
}
|
||||
|
||||
[self _addAttribute:NSForegroundColorAttributeName
|
||||
@ -295,10 +241,13 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width
|
||||
toAttributedString:attributedString];
|
||||
}
|
||||
|
||||
UIFont *font = [RCTConvert UIFont:nil withFamily:fontFamily
|
||||
size:fontSize weight:fontWeight style:fontStyle
|
||||
scaleMultiplier:_allowFontScaling ? _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];
|
||||
[self _setParagraphStyleOnAttributedString:attributedString heightOfTallestSubview:heightOfTallestSubview];
|
||||
[self _setParagraphStyleOnAttributedString:attributedString];
|
||||
|
||||
// create a non-mutable attributedString for use by the Text system which avoids copies down the line
|
||||
_cachedAttributedString = [[NSAttributedString alloc] initWithAttributedString:attributedString];
|
||||
@ -321,7 +270,6 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width
|
||||
* varying lineHeights, we simply take the max.
|
||||
*/
|
||||
- (void)_setParagraphStyleOnAttributedString:(NSMutableAttributedString *)attributedString
|
||||
heightOfTallestSubview:(CGFloat)heightOfTallestSubview
|
||||
{
|
||||
// check if we have lineHeight set on self
|
||||
__block BOOL hasParagraphStyle = NO;
|
||||
@ -329,7 +277,9 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width
|
||||
hasParagraphStyle = YES;
|
||||
}
|
||||
|
||||
__block float newLineHeight = _lineHeight ?: 0.0;
|
||||
if (!_lineHeight) {
|
||||
self.lineHeight = 0.0;
|
||||
}
|
||||
|
||||
CGFloat fontSizeMultiplier = _allowFontScaling ? _fontSizeMultiplier : 1.0;
|
||||
|
||||
@ -338,25 +288,15 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width
|
||||
if (value) {
|
||||
NSParagraphStyle *paragraphStyle = (NSParagraphStyle *)value;
|
||||
CGFloat maximumLineHeight = round(paragraphStyle.maximumLineHeight / fontSizeMultiplier);
|
||||
if (maximumLineHeight > newLineHeight) {
|
||||
newLineHeight = maximumLineHeight;
|
||||
if (maximumLineHeight > self.lineHeight) {
|
||||
self.lineHeight = maximumLineHeight;
|
||||
}
|
||||
hasParagraphStyle = YES;
|
||||
}
|
||||
}];
|
||||
|
||||
if (self.lineHeight != newLineHeight) {
|
||||
self.lineHeight = newLineHeight;
|
||||
}
|
||||
|
||||
NSTextAlignment newTextAlign = _textAlign ?: NSTextAlignmentNatural;
|
||||
if (self.textAlign != newTextAlign) {
|
||||
self.textAlign = newTextAlign;
|
||||
}
|
||||
NSWritingDirection newWritingDirection = _writingDirection ?: NSWritingDirectionNatural;
|
||||
if (self.writingDirection != newWritingDirection) {
|
||||
self.writingDirection = newWritingDirection;
|
||||
}
|
||||
self.textAlign = _textAlign ?: NSTextAlignmentNatural;
|
||||
self.writingDirection = _writingDirection ?: NSWritingDirectionNatural;
|
||||
|
||||
// if we found anything, set it :D
|
||||
if (hasParagraphStyle) {
|
||||
@ -364,9 +304,6 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width
|
||||
paragraphStyle.alignment = _textAlign;
|
||||
paragraphStyle.baseWritingDirection = _writingDirection;
|
||||
CGFloat lineHeight = round(_lineHeight * fontSizeMultiplier);
|
||||
if (heightOfTallestSubview > lineHeight) {
|
||||
lineHeight = ceilf(heightOfTallestSubview);
|
||||
}
|
||||
paragraphStyle.minimumLineHeight = lineHeight;
|
||||
paragraphStyle.maximumLineHeight = lineHeight;
|
||||
[attributedString addAttribute:NSParagraphStyleAttributeName
|
||||
|
@ -13,17 +13,6 @@
|
||||
#import "RCTUtils.h"
|
||||
#import "UIView+React.h"
|
||||
|
||||
static void collectNonTextDescendants(RCTText *view, NSMutableArray *nonTextDescendants)
|
||||
{
|
||||
for (UIView *child in view.reactSubviews) {
|
||||
if ([child isKindOfClass:[RCTText class]]) {
|
||||
collectNonTextDescendants((RCTText *)child, nonTextDescendants);
|
||||
} else {
|
||||
[nonTextDescendants addObject:child];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@implementation RCTText
|
||||
{
|
||||
NSTextStorage *_textStorage;
|
||||
@ -130,15 +119,6 @@ static void collectNonTextDescendants(RCTText *view, NSMutableArray *nonTextDesc
|
||||
[_highlightLayer removeFromSuperlayer];
|
||||
_highlightLayer = nil;
|
||||
}
|
||||
|
||||
for (UIView *child in [self subviews]) {
|
||||
[child removeFromSuperview];
|
||||
}
|
||||
NSMutableArray *nonTextDescendants = [NSMutableArray new];
|
||||
collectNonTextDescendants(self, nonTextDescendants);
|
||||
for (UIView *child in nonTextDescendants) {
|
||||
[self addSubview:child];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSNumber *)reactTagAtPoint:(CGPoint)point
|
||||
|
@ -20,18 +20,6 @@
|
||||
#import "RCTTextView.h"
|
||||
#import "UIView+React.h"
|
||||
|
||||
static void collectDirtyNonTextDescendants(RCTShadowText *shadowView, NSMutableArray *nonTextDescendants) {
|
||||
for (RCTShadowView *child in shadowView.reactSubviews) {
|
||||
if ([child isKindOfClass:[RCTShadowText class]]) {
|
||||
collectDirtyNonTextDescendants((RCTShadowText *)child, nonTextDescendants);
|
||||
} else if ([child isKindOfClass:[RCTShadowRawText class]]) {
|
||||
// no-op
|
||||
} else if ([child isTextDirty]) {
|
||||
[nonTextDescendants addObject:child];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@interface RCTShadowText (Private)
|
||||
|
||||
- (NSTextStorage *)buildTextStorageForWidth:(CGFloat)width widthMode:(css_measure_mode_t)widthMode;
|
||||
@ -97,7 +85,6 @@ RCT_EXPORT_SHADOW_PROPERTY(textShadowColor, UIColor)
|
||||
if ([shadowView isKindOfClass:[RCTShadowText class]]) {
|
||||
((RCTShadowText *)shadowView).fontSizeMultiplier = self.bridge.accessibilityManager.multiplier;
|
||||
[(RCTShadowText *)shadowView recomputeText];
|
||||
collectDirtyNonTextDescendants((RCTShadowText *)shadowView, queue);
|
||||
} else if ([shadowView isKindOfClass:[RCTShadowRawText class]]) {
|
||||
RCTLogError(@"Raw text cannot be used outside of a <Text> tag. Not rendering string: '%@'",
|
||||
[(RCTShadowRawText *)shadowView text]);
|
||||
|
@ -216,6 +216,7 @@
|
||||
13E067501A70F44B002CDEE1 /* RCTView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTView.m; sourceTree = "<group>"; };
|
||||
13E067531A70F44B002CDEE1 /* UIView+React.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+React.h"; sourceTree = "<group>"; };
|
||||
13E067541A70F44B002CDEE1 /* UIView+React.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+React.m"; sourceTree = "<group>"; };
|
||||
13EF7F441BC69646003F47DD /* RCTImageComponent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTImageComponent.h; sourceTree = "<group>"; };
|
||||
13F17A831B8493E5007D4C75 /* RCTRedBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRedBox.h; sourceTree = "<group>"; };
|
||||
13F17A841B8493E5007D4C75 /* RCTRedBox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRedBox.m; sourceTree = "<group>"; };
|
||||
14200DA81AC179B3008EE6BA /* RCTJavaScriptLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTJavaScriptLoader.h; sourceTree = "<group>"; };
|
||||
@ -384,6 +385,7 @@
|
||||
13AB90BF1B6FA36700713B4F /* RCTComponentData.h */,
|
||||
13456E941ADAD482009F94A7 /* RCTConvert+MapKit.h */,
|
||||
13AB90C01B6FA36700713B4F /* RCTComponentData.m */,
|
||||
13EF7F441BC69646003F47DD /* RCTImageComponent.h */,
|
||||
13456E911ADAD2DE009F94A7 /* RCTConvert+CoreLocation.h */,
|
||||
13456E921ADAD2DE009F94A7 /* RCTConvert+CoreLocation.m */,
|
||||
13456E951ADAD482009F94A7 /* RCTConvert+MapKit.m */,
|
||||
|
19
React/Views/RCTImageComponent.h
Normal file
19
React/Views/RCTImageComponent.h
Normal file
@ -0,0 +1,19 @@
|
||||
/**
|
||||
* 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 <UIKit/UIKit.h>
|
||||
|
||||
/**
|
||||
* Generic interface for components that contain an image.
|
||||
*/
|
||||
@protocol RCTImageComponent <NSObject>
|
||||
|
||||
@property (nonatomic, strong, readonly) UIImage *image;
|
||||
|
||||
@end
|
@ -139,32 +139,12 @@ typedef void (^RCTApplierBlock)(NSDictionary<NSNumber *, UIView *> *viewRegistry
|
||||
- (NSDictionary<NSString *, id> *)processUpdatedProperties:(NSMutableSet<RCTApplierBlock> *)applierBlocks
|
||||
parentProperties:(NSDictionary<NSString *, id> *)parentProperties NS_REQUIRES_SUPER;
|
||||
|
||||
/**
|
||||
* Can be called by a parent on a child in order to calculate all views whose frame needs
|
||||
* updating in that branch. Adds these frames to `viewsWithNewFrame`. Useful if layout
|
||||
* enters a view where flex doesn't apply (e.g. Text) and then you want to resume flex
|
||||
* layout on a subview.
|
||||
*/
|
||||
- (void)collectUpdatedFrames:(NSMutableSet<RCTShadowView *> *)viewsWithNewFrame
|
||||
withFrame:(CGRect)frame
|
||||
hidden:(BOOL)hidden
|
||||
absolutePosition:(CGPoint)absolutePosition;
|
||||
|
||||
/**
|
||||
* Recursively apply layout to children.
|
||||
* The job of applyLayoutNode:viewsWithNewFrame:absolutePosition is to apply the layout to
|
||||
* this node.
|
||||
* The job of applyLayoutToChildren:viewsWithNewFrame:absolutePosition is to enumerate the
|
||||
* children and tell them to apply layout.
|
||||
* The functionality is split into two methods so subclasses can override applyLayoutToChildren
|
||||
* while using the default implementation of applyLayoutNode.
|
||||
*/
|
||||
- (void)applyLayoutNode:(css_node_t *)node
|
||||
viewsWithNewFrame:(NSMutableSet<RCTShadowView *> *)viewsWithNewFrame
|
||||
absolutePosition:(CGPoint)absolutePosition NS_REQUIRES_SUPER;
|
||||
- (void)applyLayoutToChildren:(css_node_t *)node
|
||||
viewsWithNewFrame:(NSMutableSet<RCTShadowView *> *)viewsWithNewFrame
|
||||
absolutePosition:(CGPoint)absolutePosition;
|
||||
|
||||
/**
|
||||
* The following are implementation details exposed to subclasses. Do not call them directly
|
||||
|
@ -157,13 +157,6 @@ static void RCTProcessMetaProps(const float metaProps[META_PROP_COUNT], float st
|
||||
absolutePosition.x += node->layout.position[CSS_LEFT];
|
||||
absolutePosition.y += node->layout.position[CSS_TOP];
|
||||
|
||||
[self applyLayoutToChildren:node viewsWithNewFrame:viewsWithNewFrame absolutePosition:absolutePosition];
|
||||
}
|
||||
|
||||
- (void)applyLayoutToChildren:(css_node_t *)node
|
||||
viewsWithNewFrame:(NSMutableSet<RCTShadowView *> *)viewsWithNewFrame
|
||||
absolutePosition:(CGPoint)absolutePosition
|
||||
{
|
||||
for (int i = 0; i < node->children_count; ++i) {
|
||||
RCTShadowView *child = (RCTShadowView *)_reactSubviews[i];
|
||||
[child applyLayoutNode:node->get_child(node->context, i)
|
||||
@ -216,37 +209,6 @@ static void RCTProcessMetaProps(const float metaProps[META_PROP_COUNT], float st
|
||||
}
|
||||
}
|
||||
|
||||
- (void)collectUpdatedFrames:(NSMutableSet<RCTShadowView *> *)viewsWithNewFrame
|
||||
withFrame:(CGRect)frame
|
||||
hidden:(BOOL)hidden
|
||||
absolutePosition:(CGPoint)absolutePosition
|
||||
{
|
||||
if (_hidden != hidden) {
|
||||
// The hidden state has changed. Even if the frame hasn't changed, add
|
||||
// this ShadowView to viewsWithNewFrame so the UIManager will process
|
||||
// this ShadowView's UIView and update its hidden state.
|
||||
_hidden = hidden;
|
||||
[viewsWithNewFrame addObject:self];
|
||||
}
|
||||
|
||||
if (!CGRectEqualToRect(frame, _frame)) {
|
||||
_cssNode->style.position_type = CSS_POSITION_ABSOLUTE;
|
||||
_cssNode->style.dimensions[CSS_WIDTH] = frame.size.width;
|
||||
_cssNode->style.dimensions[CSS_HEIGHT] = frame.size.height;
|
||||
_cssNode->style.position[CSS_LEFT] = frame.origin.x;
|
||||
_cssNode->style.position[CSS_TOP] = frame.origin.y;
|
||||
// Our parent has asked us to change our cssNode->styles. Dirty the layout
|
||||
// so that we can rerun layout on this node. The request came from our parent
|
||||
// so there's no need to dirty our ancestors by calling dirtyLayout.
|
||||
_layoutLifecycle = RCTUpdateLifecycleDirtied;
|
||||
}
|
||||
|
||||
[self fillCSSNode:_cssNode];
|
||||
resetNodeLayout(self.cssNode);
|
||||
layoutNode(_cssNode, frame.size.width, frame.size.height, CSS_DIRECTION_INHERIT);
|
||||
[self applyLayoutNode:_cssNode viewsWithNewFrame:viewsWithNewFrame absolutePosition:absolutePosition];
|
||||
}
|
||||
|
||||
- (CGRect)measureLayoutRelativeToAncestor:(RCTShadowView *)ancestor
|
||||
{
|
||||
CGPoint offset = CGPointZero;
|
||||
@ -497,7 +459,6 @@ RCT_BORDER_PROPERTY(Right, RIGHT)
|
||||
{ \
|
||||
_cssNode->style.dimensions[CSS_##cssProp] = value; \
|
||||
[self dirtyLayout]; \
|
||||
[self dirtyText]; \
|
||||
} \
|
||||
- (CGFloat)getProp \
|
||||
{ \
|
||||
|
14
docs/Text.md
14
docs/Text.md
@ -21,20 +21,6 @@ Behind the scenes, React Native converts this to a flat `NSAttributedString` or
|
||||
9-17: bold, red
|
||||
```
|
||||
|
||||
## Nested Views (iOS Only)
|
||||
|
||||
On iOS, you can nest views within your Text component. Here's an example:
|
||||
|
||||
```javascript
|
||||
<Text>
|
||||
There is a blue square
|
||||
<View style={{width: 50, height: 50, backgroundColor: 'steelblue'}} />
|
||||
in between my text.
|
||||
</Text>
|
||||
```
|
||||
|
||||
In order to use this feature, you must give the view a `width` and a `height`.
|
||||
|
||||
## Containers
|
||||
|
||||
The `<Text>` element is special relative to layout: everything inside is no longer using the flexbox layout but using text layout. This means that elements inside of a `<Text>` are no longer rectangles, but wrap when they see the end of the line.
|
||||
|
Loading…
x
Reference in New Issue
Block a user