mirror of
https://github.com/status-im/react-native.git
synced 2025-02-05 06:04:15 +00:00
Add onSelectionChange for Android TextInput
Summary: public Add an onSelectionChange method to TextInput that works on Android same as iOS Reviewed By: andreicoman11 Differential Revision: D2780131 fb-gh-sync-id: 9b3b8fbd9ea653d43e3107a338e4bc08bde2e8c6
This commit is contained in:
parent
857dd59340
commit
6dc6794881
@ -216,6 +216,10 @@ var TextInput = React.createClass({
|
|||||||
* Callback that is called when text input ends.
|
* Callback that is called when text input ends.
|
||||||
*/
|
*/
|
||||||
onEndEditing: PropTypes.func,
|
onEndEditing: PropTypes.func,
|
||||||
|
/**
|
||||||
|
* Callback that is called when the text input selection is changed
|
||||||
|
*/
|
||||||
|
onSelectionChange: PropTypes.func,
|
||||||
/**
|
/**
|
||||||
* Callback that is called when the text input's submit button is pressed.
|
* Callback that is called when the text input's submit button is pressed.
|
||||||
* Invalid if multiline={true} is specified.
|
* Invalid if multiline={true} is specified.
|
||||||
@ -474,6 +478,17 @@ var TextInput = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_renderAndroid: function() {
|
_renderAndroid: function() {
|
||||||
|
var onSelectionChange;
|
||||||
|
if (this.props.selectionState || this.props.onSelectionChange) {
|
||||||
|
onSelectionChange = (event: Event) => {
|
||||||
|
if (this.props.selectionState) {
|
||||||
|
var selection = event.nativeEvent.selection;
|
||||||
|
this.props.selectionState.update(selection.start, selection.end);
|
||||||
|
}
|
||||||
|
this.props.onSelectionChange && this.props.onSelectionChange(event);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
var autoCapitalize = UIManager.UIText.AutocapitalizationType[this.props.autoCapitalize];
|
var autoCapitalize = UIManager.UIText.AutocapitalizationType[this.props.autoCapitalize];
|
||||||
var textAlign =
|
var textAlign =
|
||||||
UIManager.AndroidTextInput.Constants.TextAlign[this.props.textAlign];
|
UIManager.AndroidTextInput.Constants.TextAlign[this.props.textAlign];
|
||||||
@ -489,6 +504,7 @@ var TextInput = React.createClass({
|
|||||||
if (childCount > 1) {
|
if (childCount > 1) {
|
||||||
children = <Text>{children}</Text>;
|
children = <Text>{children}</Text>;
|
||||||
}
|
}
|
||||||
|
|
||||||
var textContainer =
|
var textContainer =
|
||||||
<AndroidTextInput
|
<AndroidTextInput
|
||||||
ref="input"
|
ref="input"
|
||||||
@ -505,6 +521,7 @@ var TextInput = React.createClass({
|
|||||||
onFocus={this._onFocus}
|
onFocus={this._onFocus}
|
||||||
onBlur={this._onBlur}
|
onBlur={this._onBlur}
|
||||||
onChange={this._onChange}
|
onChange={this._onChange}
|
||||||
|
onSelectionChange={onSelectionChange}
|
||||||
onTextInput={this._onTextInput}
|
onTextInput={this._onTextInput}
|
||||||
onEndEditing={this.props.onEndEditing}
|
onEndEditing={this.props.onEndEditing}
|
||||||
onSubmitEditing={this.props.onSubmitEditing}
|
onSubmitEditing={this.props.onSubmitEditing}
|
||||||
|
@ -64,6 +64,7 @@ public class ReactEditText extends EditText {
|
|||||||
private @Nullable TextWatcherDelegator mTextWatcherDelegator;
|
private @Nullable TextWatcherDelegator mTextWatcherDelegator;
|
||||||
private int mStagedInputType;
|
private int mStagedInputType;
|
||||||
private boolean mContainsImages;
|
private boolean mContainsImages;
|
||||||
|
private @Nullable SelectionWatcher mSelectionWatcher;
|
||||||
|
|
||||||
public ReactEditText(Context context) {
|
public ReactEditText(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
@ -150,6 +151,27 @@ public class ReactEditText extends EditText {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSelectionChanged(int selStart, int selEnd) {
|
||||||
|
super.onSelectionChanged(selStart, selEnd);
|
||||||
|
if (mSelectionWatcher != null && hasFocus()) {
|
||||||
|
mSelectionWatcher.onSelectionChanged(selStart, selEnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onFocusChanged(
|
||||||
|
boolean focused, int direction, Rect previouslyFocusedRect) {
|
||||||
|
super.onFocusChanged(focused, direction, previouslyFocusedRect);
|
||||||
|
if (focused && mSelectionWatcher != null) {
|
||||||
|
mSelectionWatcher.onSelectionChanged(getSelectionStart(), getSelectionEnd());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSelectionWatcher(SelectionWatcher selectionWatcher) {
|
||||||
|
mSelectionWatcher = selectionWatcher;
|
||||||
|
}
|
||||||
|
|
||||||
/*protected*/ int getStagedInputType() {
|
/*protected*/ int getStagedInputType() {
|
||||||
return mStagedInputType;
|
return mStagedInputType;
|
||||||
}
|
}
|
||||||
@ -170,7 +192,8 @@ public class ReactEditText extends EditText {
|
|||||||
mStagedInputType = type;
|
mStagedInputType = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ void requestFocusFromJS() {
|
// VisibleForTesting from {@link TextInputEventsTestCase}.
|
||||||
|
public void requestFocusFromJS() {
|
||||||
mIsJSSettingFocus = true;
|
mIsJSSettingFocus = true;
|
||||||
requestFocus();
|
requestFocus();
|
||||||
mIsJSSettingFocus = false;
|
mIsJSSettingFocus = false;
|
||||||
|
@ -166,6 +166,15 @@ public class ReactTextInputManager extends
|
|||||||
(int) Math.ceil(PixelUtil.toPixelFromSP(fontSize)));
|
(int) Math.ceil(PixelUtil.toPixelFromSP(fontSize)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ReactProp(name = "onSelectionChange", defaultBoolean = false)
|
||||||
|
public void setOnSelectionChange(final ReactEditText view, boolean onSelectionChange) {
|
||||||
|
if (onSelectionChange) {
|
||||||
|
view.setSelectionWatcher(new ReactSelectionWatcher(view));
|
||||||
|
} else {
|
||||||
|
view.setSelectionWatcher(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ReactProp(name = "placeholder")
|
@ReactProp(name = "placeholder")
|
||||||
public void setPlaceholder(ReactEditText view, @Nullable String placeholder) {
|
public void setPlaceholder(ReactEditText view, @Nullable String placeholder) {
|
||||||
view.setHint(placeholder);
|
view.setHint(placeholder);
|
||||||
@ -418,6 +427,40 @@ public class ReactTextInputManager extends
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ReactSelectionWatcher implements SelectionWatcher {
|
||||||
|
|
||||||
|
private ReactEditText mReactEditText;
|
||||||
|
private EventDispatcher mEventDispatcher;
|
||||||
|
private int mPreviousSelectionStart;
|
||||||
|
private int mPreviousSelectionEnd;
|
||||||
|
|
||||||
|
public ReactSelectionWatcher(ReactEditText editText) {
|
||||||
|
mReactEditText = editText;
|
||||||
|
ReactContext reactContext = (ReactContext) editText.getContext();
|
||||||
|
mEventDispatcher = reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSelectionChanged(int start, int end) {
|
||||||
|
// Android will call us back for both the SELECTION_START span and SELECTION_END span in text
|
||||||
|
// To prevent double calling back into js we cache the result of the previous call and only
|
||||||
|
// forward it on if we have new values
|
||||||
|
if (mPreviousSelectionStart != start || mPreviousSelectionEnd != end) {
|
||||||
|
mEventDispatcher.dispatchEvent(
|
||||||
|
new ReactTextInputSelectionEvent(
|
||||||
|
mReactEditText.getId(),
|
||||||
|
SystemClock.uptimeMillis(),
|
||||||
|
start,
|
||||||
|
end
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
mPreviousSelectionStart = start;
|
||||||
|
mPreviousSelectionEnd = end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable Map getExportedViewConstants() {
|
public @Nullable Map getExportedViewConstants() {
|
||||||
return MapBuilder.of(
|
return MapBuilder.of(
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.facebook.react.views.textinput;
|
||||||
|
|
||||||
|
import com.facebook.react.bridge.Arguments;
|
||||||
|
import com.facebook.react.bridge.WritableMap;
|
||||||
|
import com.facebook.react.uimanager.events.Event;
|
||||||
|
import com.facebook.react.uimanager.events.RCTEventEmitter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event emitted by EditText native view when the text selection changes.
|
||||||
|
*/
|
||||||
|
/* package */ class ReactTextInputSelectionEvent
|
||||||
|
extends Event<ReactTextInputSelectionEvent> {
|
||||||
|
|
||||||
|
private static final String EVENT_NAME = "topSelectionChange";
|
||||||
|
|
||||||
|
private int mSelectionStart;
|
||||||
|
private int mSelectionEnd;
|
||||||
|
|
||||||
|
public ReactTextInputSelectionEvent(
|
||||||
|
int viewId,
|
||||||
|
long timestampMs,
|
||||||
|
int selectionStart,
|
||||||
|
int selectionEnd) {
|
||||||
|
super(viewId, timestampMs);
|
||||||
|
mSelectionStart = selectionStart;
|
||||||
|
mSelectionEnd = selectionEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getEventName() {
|
||||||
|
return EVENT_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispatch(RCTEventEmitter rctEventEmitter) {
|
||||||
|
rctEventEmitter.receiveEvent(getViewTag(), getEventName(), serializeEventData());
|
||||||
|
}
|
||||||
|
|
||||||
|
private WritableMap serializeEventData() {
|
||||||
|
WritableMap eventData = Arguments.createMap();
|
||||||
|
|
||||||
|
WritableMap selectionData = Arguments.createMap();
|
||||||
|
selectionData.putInt("start", mSelectionStart);
|
||||||
|
selectionData.putInt("end", mSelectionEnd);
|
||||||
|
|
||||||
|
eventData.putMap("selection", selectionData);
|
||||||
|
return eventData;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.facebook.react.views.textinput;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this interface to be informed of selection changes in the ReactTextEdit
|
||||||
|
* This is used by the ReactTextInputManager to forward events from the EditText to JS
|
||||||
|
*/
|
||||||
|
interface SelectionWatcher {
|
||||||
|
public void onSelectionChanged(int start, int end);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user