Fix multi-character TextInput

Reviewed By: hnery

Differential Revision: D3457105

fbshipit-source-id: dcb364123ed82842d4fb2dee9108f2805249a8f9
This commit is contained in:
Pieter De Baets 2016-06-23 03:53:50 -07:00 committed by Facebook Github Bot 1
parent 57d85f1c3e
commit cc959273da
5 changed files with 24 additions and 66 deletions

View File

@ -18,6 +18,7 @@
#import "RCTText.h"
#import "RCTUtils.h"
#import "RCTConvert.h"
#import "RCTTextView.h"
NSString *const RCTShadowViewAttributeName = @"RCTShadowViewAttributeName";
NSString *const RCTIsHighlightedAttributeName = @"IsHighlightedAttributeName";
@ -98,10 +99,24 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width
UIEdgeInsets padding = self.paddingAsInsets;
CGFloat width = self.frame.size.width - (padding.left + padding.right);
NSNumber *parentTag = [[self reactSuperview] reactTag];
NSTextStorage *textStorage = [self buildTextStorageForWidth:width widthMode:CSS_MEASURE_MODE_EXACTLY];
[applierBlocks addObject:^(NSDictionary<NSNumber *, RCTText *> *viewRegistry) {
RCTText *view = viewRegistry[self.reactTag];
[applierBlocks addObject:^(NSDictionary<NSNumber *, UIView *> *viewRegistry) {
RCTText *view = (RCTText *)viewRegistry[self.reactTag];
view.textStorage = textStorage;
/**
* NOTE: this logic is included to support rich text editing inside multiline
* `<TextInput>` controls. It is required in order to ensure that the
* textStorage (aka attributed string) is copied over from the RCTShadowText
* to the RCTText view in time to be used to update the editable text content.
* TODO: we should establish a delegate relationship betweeen RCTTextView
* and its contaned RCTText element when they get inserted and get rid of this
*/
UIView *parentView = viewRegistry[parentTag];
if ([parentView respondsToSelector:@selector(performTextUpdate)]) {
[(RCTTextView *)parentView performTextUpdate];
}
}];
return parentProperties;
@ -167,13 +182,13 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width
NSTextContainer *textContainer = [NSTextContainer new];
textContainer.lineFragmentPadding = 0.0;
if (_numberOfLines > 0) {
textContainer.lineBreakMode = _lineBreakMode;
} else {
textContainer.lineBreakMode = NSLineBreakByClipping;
}
textContainer.maximumNumberOfLines = _numberOfLines;
textContainer.size = (CGSize){widthMode == CSS_MEASURE_MODE_UNDEFINED ? CGFLOAT_MAX : width, CGFLOAT_MAX};

View File

@ -155,7 +155,6 @@ static void collectNonTextDescendants(RCTText *view, NSMutableArray *nonTextDesc
return reactTag;
}
- (void)didMoveToWindow
{
[super didMoveToWindow];

View File

@ -78,7 +78,6 @@ RCT_EXPORT_SHADOW_PROPERTY(textShadowColor, UIColor)
- (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(NSDictionary<NSNumber *, RCTShadowView *> *)shadowViewRegistry
{
NSMutableSet *textViewTagsToUpdate = [NSMutableSet new];
for (RCTShadowView *rootView in shadowViewRegistry.allValues) {
if (![rootView isReactRootView]) {
// This isn't a root view
@ -103,19 +102,6 @@ RCT_EXPORT_SHADOW_PROPERTY(textShadowColor, UIColor)
RCTLogError(@"Raw text cannot be used outside of a <Text> tag. Not rendering string: '%@'",
[(RCTShadowRawText *)shadowView text]);
} else {
NSNumber *reactTag = shadowView.reactTag;
// This isn't pretty, but hopefully it's temporary
// the problem is, there's no easy way (besides the viewName)
// to tell from the shadowView if the view is an RKTextView
if ([shadowView.viewName hasSuffix:@"TextView"]) {
// Add to textViewTagsToUpdate only if has a RCTShadowText subview
for (RCTShadowView *subview in shadowView.reactSubviews) {
if ([subview isKindOfClass:[RCTShadowText class]]) {
[textViewTagsToUpdate addObject:reactTag];
break;
}
}
}
for (RCTShadowView *child in [shadowView reactSubviews]) {
if ([child isTextDirty]) {
[queue addObject:child];
@ -127,52 +113,7 @@ RCT_EXPORT_SHADOW_PROPERTY(textShadowColor, UIColor)
}
}
/**
* NOTE: this logic is included to support rich text editing inside multiline
* `<TextInput>` controls. It is required in order to ensure that the
* textStorage (aka attributed string) is copied over from the RCTShadowText
* to the RCTText view in time to be used to update the editable text content.
*/
if (textViewTagsToUpdate.count) {
NSMutableArray<RCTViewManagerUIBlock> *uiBlocks = [NSMutableArray new];
for (NSNumber *reactTag in textViewTagsToUpdate) {
RCTShadowView *shadowTextView = shadowViewRegistry[reactTag];
RCTShadowText *shadowText;
for (RCTShadowText *subview in shadowTextView.reactSubviews) {
if ([subview isKindOfClass:[RCTShadowText class]]) {
shadowText = subview;
break;
}
}
UIEdgeInsets padding = shadowText.paddingAsInsets;
CGFloat width = shadowText.frame.size.width - (padding.left + padding.right);
NSTextStorage *textStorage = [shadowText buildTextStorageForWidth:width widthMode:CSS_MEASURE_MODE_EXACTLY];
[uiBlocks addObject:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTTextView *> *viewRegistry) {
RCTTextView *textView = viewRegistry[reactTag];
RCTText *text;
for (RCTText *subview in textView.reactSubviews) {
if ([subview isKindOfClass:[RCTText class]]) {
text = subview;
break;
}
}
text.textStorage = textStorage;
[textView performTextUpdate];
}];
}
return ^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
for (RCTViewManagerUIBlock uiBlock in uiBlocks) {
uiBlock(uiManager, viewRegistry);
}
};
} else {
return nil;
}
return nil;
}
- (RCTViewManagerUIBlock)uiBlockToAmendWithShadowView:(RCTShadowText *)shadowView

View File

@ -125,6 +125,8 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
attrs[NSBackgroundColorAttributeName] = subview.backgroundColor;
_textView.typingAttributes = attrs;
}
[self performTextUpdate];
}
}
@ -133,6 +135,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
[super removeReactSubview:subview];
if (_richTextView == subview) {
_richTextView = nil;
[self performTextUpdate];
}
}

View File

@ -85,7 +85,7 @@ typedef void (^RCTViewManagerUIBlock)(RCTUIManager *uiManager, NSDictionary<NSNu
/**
* Called after view hierarchy manipulation has finished, and all shadow props
* have been set, but before layout has been performed. Useful for performing
* custo layout logic or tasks that involve walking the view hierarchy.
* custom layout logic or tasks that involve walking the view hierarchy.
* To be deprecated, hopefully.
*/
- (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(NSDictionary<NSNumber *, RCTShadowView *> *)shadowViewRegistry;