在TextInput React-Native上获取光标位置

时间:2022-09-22 18:58:10

Does anyone have any ideas on how to get the caret position of a TextInput? I tried onSelectionChange and creating an event emitter from DocumentSelectionState but neither appear to be working (they don't fire anything, no matter what I select).

有没有人对如何获得TextInput的插入位置有任何想法?我尝试了onSelectionChange并从DocumentSelectionState创建一个事件发射器,但似乎都没有工作(无论我选择什么,它们都不会触发任何东西)。

For Example: https://rnplay.org/apps/eZnvIA

例如:https://rnplay.org/apps/eZnvIA

3 个解决方案

#1


11  

onSelectionChange={(event) => console.log(event.nativeEvent.selection)}

#2


1  

If you're willing to get semi-adventurous, you can update the react-native library to allow retrieving the cursor (x/y) coordinates (relative to the TextInput), in the onSelectionChange event parameter.

如果您愿意进行半冒险,可以更新react-native库以允许在onSelectionChange事件参数中检索光标(x / y)坐标(相对于TextInput)。

Full instructions for IOS AND Android. (Disclaimer: I did not come up with this solution)

IOS和Android的完整说明。 (免责声明:我没有提出这个解决方案)

TLDR - IOS + ReactNative 0.49.1

node_modules/react-native/Libraries/Text/RCTTextSelection.h

/**
 * Object containing information about a TextInput's selection.
 */
@interface RCTTextSelection : NSObject

@property (nonatomic, assign, readonly) NSInteger start;
@property (nonatomic, assign, readonly) NSInteger end;
/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
@property (nonatomic, assign, readonly) CGPoint cursorPosition;

- (instancetype)initWithStart:(NSInteger)start end:(NSInteger)end cursorPosition:(CGPoint)cursorPosition;
/* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */

@end

node_modules/react-native/Libraries/Text/RCTTextSelection.m

@implementation RCTTextSelection

    /* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
- (instancetype)initWithStart:(NSInteger)start end:(NSInteger)end cursorPosition:(CGPoint)cursorPosition
    /* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
{
  if (self = [super init]) {
    _start = start;
    _end = end;
    /* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
    _cursorPosition = cursorPosition;
    /* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
  }
  return self;
}

@end

@implementation RCTConvert (RCTTextSelection)

+ (RCTTextSelection *)RCTTextSelection:(id)json
{
  if ([json isKindOfClass:[NSDictionary class]]) {
    NSInteger start = [self NSInteger:json[@"start"]];
    NSInteger end = [self NSInteger:json[@"end"]];
    /* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
    CGPoint cursorPosition = CGPointMake(
      [self CGFloat:json[@"cursorPositionX"]],
      [self CGFloat:json[@"cursorPositionY"]]
    );
    return [[RCTTextSelection alloc] initWithStart:start
                                               end:end 
                                    cursorPosition:cursorPosition];
    /* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
  }

  return nil;
}

@end

node_modules/react-native/Libraries/Text/RCTTextInput.m

- (RCTTextSelection *)selection
{
  id<RCTBackedTextInputViewProtocol> backedTextInput = self.backedTextInputView;

  UITextRange *selectedTextRange = backedTextInput.selectedTextRange;
  return [[RCTTextSelection new] initWithStart:[backedTextInput offsetFromPosition:backedTextInput.beginningOfDocument toPosition:selectedTextRange.start]
                                           end:[backedTextInput offsetFromPosition:backedTextInput.beginningOfDocument toPosition:selectedTextRange.end]
      /* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
                                cursorPosition:[backedTextInput caretRectForPosition:selectedTextRange.start].origin];
      /* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
}

...

- (void)textInputDidChangeSelection
{
  if (!_onSelectionChange) {
    return;
  }

  RCTTextSelection *selection = self.selection;
  _onSelectionChange(@{
    @"selection": @{
      @"start": @(selection.start),
      @"end": @(selection.end),
      /* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
      @"cursorPositionX": @(selection.cursorPosition.x),
      @"cursorPositionY": @(selection.cursorPosition.y)
      /* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
    },
  });
}

#3


-4  

As a start, you probably want to use the onChange or even onChangeText event instead. That will get your alert firing.

首先,您可能希望使用onChange或甚至onChangeText事件。这将使你的警报开火。

#1


11  

onSelectionChange={(event) => console.log(event.nativeEvent.selection)}

#2


1  

If you're willing to get semi-adventurous, you can update the react-native library to allow retrieving the cursor (x/y) coordinates (relative to the TextInput), in the onSelectionChange event parameter.

如果您愿意进行半冒险,可以更新react-native库以允许在onSelectionChange事件参数中检索光标(x / y)坐标(相对于TextInput)。

Full instructions for IOS AND Android. (Disclaimer: I did not come up with this solution)

IOS和Android的完整说明。 (免责声明:我没有提出这个解决方案)

TLDR - IOS + ReactNative 0.49.1

node_modules/react-native/Libraries/Text/RCTTextSelection.h

/**
 * Object containing information about a TextInput's selection.
 */
@interface RCTTextSelection : NSObject

@property (nonatomic, assign, readonly) NSInteger start;
@property (nonatomic, assign, readonly) NSInteger end;
/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
@property (nonatomic, assign, readonly) CGPoint cursorPosition;

- (instancetype)initWithStart:(NSInteger)start end:(NSInteger)end cursorPosition:(CGPoint)cursorPosition;
/* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */

@end

node_modules/react-native/Libraries/Text/RCTTextSelection.m

@implementation RCTTextSelection

    /* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
- (instancetype)initWithStart:(NSInteger)start end:(NSInteger)end cursorPosition:(CGPoint)cursorPosition
    /* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
{
  if (self = [super init]) {
    _start = start;
    _end = end;
    /* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
    _cursorPosition = cursorPosition;
    /* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
  }
  return self;
}

@end

@implementation RCTConvert (RCTTextSelection)

+ (RCTTextSelection *)RCTTextSelection:(id)json
{
  if ([json isKindOfClass:[NSDictionary class]]) {
    NSInteger start = [self NSInteger:json[@"start"]];
    NSInteger end = [self NSInteger:json[@"end"]];
    /* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
    CGPoint cursorPosition = CGPointMake(
      [self CGFloat:json[@"cursorPositionX"]],
      [self CGFloat:json[@"cursorPositionY"]]
    );
    return [[RCTTextSelection alloc] initWithStart:start
                                               end:end 
                                    cursorPosition:cursorPosition];
    /* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
  }

  return nil;
}

@end

node_modules/react-native/Libraries/Text/RCTTextInput.m

- (RCTTextSelection *)selection
{
  id<RCTBackedTextInputViewProtocol> backedTextInput = self.backedTextInputView;

  UITextRange *selectedTextRange = backedTextInput.selectedTextRange;
  return [[RCTTextSelection new] initWithStart:[backedTextInput offsetFromPosition:backedTextInput.beginningOfDocument toPosition:selectedTextRange.start]
                                           end:[backedTextInput offsetFromPosition:backedTextInput.beginningOfDocument toPosition:selectedTextRange.end]
      /* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
                                cursorPosition:[backedTextInput caretRectForPosition:selectedTextRange.start].origin];
      /* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
}

...

- (void)textInputDidChangeSelection
{
  if (!_onSelectionChange) {
    return;
  }

  RCTTextSelection *selection = self.selection;
  _onSelectionChange(@{
    @"selection": @{
      @"start": @(selection.start),
      @"end": @(selection.end),
      /* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
      @"cursorPositionX": @(selection.cursorPosition.x),
      @"cursorPositionY": @(selection.cursorPosition.y)
      /* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
    },
  });
}

#3


-4  

As a start, you probably want to use the onChange or even onChangeText event instead. That will get your alert firing.

首先,您可能希望使用onChange或甚至onChangeText事件。这将使你的警报开火。