mirror of
https://github.com/status-im/react-native.git
synced 2025-02-25 07:35:25 +00:00
Added support of <Text>
's selectable
attribute on iOS
Reviewed By: mmmulani Differential Revision: D4187562 fbshipit-source-id: 131ece141fe8b895914043a7a01c6e042e858331
This commit is contained in:
parent
2a2ba52ab5
commit
5d03ff8035
Binary file not shown.
Before Width: | Height: | Size: 364 KiB After Width: | Height: | Size: 365 KiB |
Binary file not shown.
Before Width: | Height: | Size: 365 KiB After Width: | Height: | Size: 365 KiB |
@ -276,6 +276,17 @@ exports.examples = [
|
||||
</View>
|
||||
);
|
||||
},
|
||||
}, {
|
||||
title: 'Selectable',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<Text selectable={true}>
|
||||
This text is <Text style={{fontWeight: 'bold'}}>selectable</Text> if you click-and-hold.
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
}, {
|
||||
title: 'Text Decoration',
|
||||
render: function() {
|
||||
|
@ -48,6 +48,7 @@ extern NSString *const RCTReactTagAttributeName;
|
||||
@property (nonatomic, strong) UIColor *textShadowColor;
|
||||
@property (nonatomic, assign) BOOL adjustsFontSizeToFit;
|
||||
@property (nonatomic, assign) CGFloat minimumFontScale;
|
||||
@property (nonatomic, assign) BOOL selectable;
|
||||
|
||||
- (void)recomputeText;
|
||||
|
||||
|
@ -115,10 +115,12 @@ static CSSSize RCTMeasure(CSSNodeRef node, float width, CSSMeasureMode widthMode
|
||||
NSNumber *parentTag = [[self reactSuperview] reactTag];
|
||||
NSTextStorage *textStorage = [self buildTextStorageForWidth:width widthMode:CSSMeasureModeExactly];
|
||||
CGRect textFrame = [self calculateTextFrame:textStorage];
|
||||
BOOL selectable = _selectable;
|
||||
[applierBlocks addObject:^(NSDictionary<NSNumber *, UIView *> *viewRegistry) {
|
||||
RCTText *view = (RCTText *)viewRegistry[self.reactTag];
|
||||
view.textFrame = textFrame;
|
||||
view.textStorage = textStorage;
|
||||
view.selectable = selectable;
|
||||
|
||||
/**
|
||||
* NOTE: this logic is included to support rich text editing inside multiline
|
||||
|
@ -14,6 +14,6 @@
|
||||
@property (nonatomic, assign) UIEdgeInsets contentInset;
|
||||
@property (nonatomic, strong) NSTextStorage *textStorage;
|
||||
@property (nonatomic, assign) CGRect textFrame;
|
||||
|
||||
@property (nonatomic, assign) BOOL selectable;
|
||||
|
||||
@end
|
||||
|
@ -9,6 +9,8 @@
|
||||
|
||||
#import "RCTText.h"
|
||||
|
||||
#import <MobileCoreServices/UTCoreTypes.h>
|
||||
|
||||
#import "RCTShadowText.h"
|
||||
#import "RCTUtils.h"
|
||||
#import "UIView+React.h"
|
||||
@ -28,6 +30,7 @@ static void collectNonTextDescendants(RCTText *view, NSMutableArray *nonTextDesc
|
||||
{
|
||||
NSTextStorage *_textStorage;
|
||||
CAShapeLayer *_highlightLayer;
|
||||
UILongPressGestureRecognizer *_longPressGestureRecognizer;
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
@ -51,6 +54,22 @@ static void collectNonTextDescendants(RCTText *view, NSMutableArray *nonTextDesc
|
||||
return [superDescription stringByReplacingCharactersInRange:semicolonRange withString:replacement];
|
||||
}
|
||||
|
||||
- (void)setSelectable:(BOOL)selectable
|
||||
{
|
||||
if (_selectable == selectable) {
|
||||
return;
|
||||
}
|
||||
|
||||
_selectable = selectable;
|
||||
|
||||
if (_selectable) {
|
||||
[self enableContextMenu];
|
||||
}
|
||||
else {
|
||||
[self disableContextMenu];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)reactSetFrame:(CGRect)frame
|
||||
{
|
||||
// Text looks super weird if its frame is animated.
|
||||
@ -177,4 +196,72 @@ static void collectNonTextDescendants(RCTText *view, NSMutableArray *nonTextDesc
|
||||
return _textStorage.string;
|
||||
}
|
||||
|
||||
#pragma mark - Context Menu
|
||||
|
||||
- (void)enableContextMenu
|
||||
{
|
||||
_longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
|
||||
[self addGestureRecognizer:_longPressGestureRecognizer];
|
||||
}
|
||||
|
||||
- (void)disableContextMenu
|
||||
{
|
||||
[self removeGestureRecognizer:_longPressGestureRecognizer];
|
||||
_longPressGestureRecognizer = nil;
|
||||
}
|
||||
|
||||
- (void)handleLongPress:(UILongPressGestureRecognizer *)gesture
|
||||
{
|
||||
#if !TARGET_OS_TV
|
||||
UIMenuController *menuController = [UIMenuController sharedMenuController];
|
||||
|
||||
if (menuController.isMenuVisible) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!self.isFirstResponder) {
|
||||
[self becomeFirstResponder];
|
||||
}
|
||||
|
||||
[menuController setTargetRect:self.bounds inView:self];
|
||||
[menuController setMenuVisible:YES animated:YES];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (BOOL)canBecomeFirstResponder
|
||||
{
|
||||
return _selectable;
|
||||
}
|
||||
|
||||
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
|
||||
{
|
||||
if (action == @selector(copy:)) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
return [super canPerformAction:action withSender:sender];
|
||||
}
|
||||
|
||||
- (void)copy:(id)sender
|
||||
{
|
||||
#if !TARGET_OS_TV
|
||||
NSAttributedString *attributedString = _textStorage;
|
||||
|
||||
NSMutableDictionary *item = [NSMutableDictionary new];
|
||||
|
||||
NSData *rtf = [attributedString dataFromRange:NSMakeRange(0, attributedString.length)
|
||||
documentAttributes:@{NSDocumentTypeDocumentAttribute: NSRTFDTextDocumentType}
|
||||
error:nil];
|
||||
|
||||
if (rtf) {
|
||||
[item setObject:rtf forKey:(id)kUTTypeFlatRTFD];
|
||||
}
|
||||
|
||||
[item setObject:attributedString.string forKey:(id)kUTTypeUTF8PlainText];
|
||||
|
||||
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
|
||||
pasteboard.items = @[item];
|
||||
#endif
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -84,6 +84,7 @@ RCT_EXPORT_SHADOW_PROPERTY(textShadowRadius, CGFloat)
|
||||
RCT_EXPORT_SHADOW_PROPERTY(textShadowColor, UIColor)
|
||||
RCT_EXPORT_SHADOW_PROPERTY(adjustsFontSizeToFit, BOOL)
|
||||
RCT_EXPORT_SHADOW_PROPERTY(minimumFontScale, CGFloat)
|
||||
RCT_EXPORT_SHADOW_PROPERTY(selectable, BOOL)
|
||||
|
||||
- (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(NSDictionary<NSNumber *, RCTShadowView *> *)shadowViewRegistry
|
||||
{
|
||||
|
@ -136,8 +136,6 @@ const Text = React.createClass({
|
||||
onLongPress: React.PropTypes.func,
|
||||
/**
|
||||
* Lets the user select text, to use the native copy and paste functionality.
|
||||
*
|
||||
* @platform android
|
||||
*/
|
||||
selectable: React.PropTypes.bool,
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user