Smart textinput scroll
Summary: This diff changes the textinput component to only scroll (and interrupt parent views from scrolling), when it is possible for the text inside the component to be scrolled. Before (D3735237), we would intercept all touch events on the textinput if it's focused. But this makes it: a.) impossible to scroll a scrollview from within a textinput that cannot be scrolled; b.) different from iOS behavior. What the component now does is intercept move touches, and check if it can scroll in any direction. If it does, it will intercept the touches and stop the parent component from scrolling; otherwise, it will give the control back to the parent component. Note: this might change in the future to also detect the direction of the scroll, and only block the scroll if the component can scroll in that direction. This is however not trivial, since the scroll needs to be above some threshold of pixels. Blocking the parent view from scrolling until that threshold is passed might cause incorrect behavior in the parent component. Reviewed By: astreet Differential Revision: D3764267 fbshipit-source-id: 47e7b5e03855b3c85789e04fc31a8317afbafa84
This commit is contained in:
parent
3efe95d989
commit
372d001a5d
|
@ -15,8 +15,8 @@ import java.util.ArrayList;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
import android.text.SpannableStringBuilder;
|
import android.text.SpannableStringBuilder;
|
||||||
|
@ -29,6 +29,7 @@ import android.text.style.BackgroundColorSpan;
|
||||||
import android.text.style.ForegroundColorSpan;
|
import android.text.style.ForegroundColorSpan;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
@ -68,12 +69,12 @@ public class ReactEditText extends EditText {
|
||||||
private @Nullable ArrayList<TextWatcher> mListeners;
|
private @Nullable ArrayList<TextWatcher> mListeners;
|
||||||
private @Nullable TextWatcherDelegator mTextWatcherDelegator;
|
private @Nullable TextWatcherDelegator mTextWatcherDelegator;
|
||||||
private int mStagedInputType;
|
private int mStagedInputType;
|
||||||
private boolean mTextIsSelectable = true;
|
|
||||||
private boolean mContainsImages;
|
private boolean mContainsImages;
|
||||||
private boolean mBlurOnSubmit;
|
private boolean mBlurOnSubmit;
|
||||||
private @Nullable SelectionWatcher mSelectionWatcher;
|
private @Nullable SelectionWatcher mSelectionWatcher;
|
||||||
private @Nullable ContentSizeWatcher mContentSizeWatcher;
|
private @Nullable ContentSizeWatcher mContentSizeWatcher;
|
||||||
private final InternalKeyListener mKeyListener;
|
private final InternalKeyListener mKeyListener;
|
||||||
|
private boolean mDetectScrollMovement = false;
|
||||||
|
|
||||||
private static final KeyListener sKeyListener = QwertyKeyListener.getInstanceForFullKeyboard();
|
private static final KeyListener sKeyListener = QwertyKeyListener.getInstanceForFullKeyboard();
|
||||||
|
|
||||||
|
@ -124,6 +125,31 @@ public class ReactEditText extends EditText {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouchEvent(MotionEvent ev) {
|
||||||
|
switch (ev.getAction()) {
|
||||||
|
case MotionEvent.ACTION_DOWN:
|
||||||
|
mDetectScrollMovement = true;
|
||||||
|
// Disallow parent views to intercept touch events, until we can detect if we should be
|
||||||
|
// capturing these touches or not.
|
||||||
|
this.getParent().requestDisallowInterceptTouchEvent(true);
|
||||||
|
break;
|
||||||
|
case MotionEvent.ACTION_MOVE:
|
||||||
|
if (mDetectScrollMovement) {
|
||||||
|
if (!canScrollVertically(-1) &&
|
||||||
|
!canScrollVertically(1) &&
|
||||||
|
!canScrollHorizontally(-1) &&
|
||||||
|
!canScrollHorizontally(1)) {
|
||||||
|
// We cannot scroll, let parent views take care of these touches.
|
||||||
|
this.getParent().requestDisallowInterceptTouchEvent(false);
|
||||||
|
}
|
||||||
|
mDetectScrollMovement = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return super.onTouchEvent(ev);
|
||||||
|
}
|
||||||
|
|
||||||
// Consume 'Enter' key events: TextView tries to give focus to the next TextInput, but it can't
|
// Consume 'Enter' key events: TextView tries to give focus to the next TextInput, but it can't
|
||||||
// since we only allow JS to change focus, which in turn causes TextView to crash.
|
// since we only allow JS to change focus, which in turn causes TextView to crash.
|
||||||
@Override
|
@Override
|
||||||
|
@ -252,12 +278,6 @@ public class ReactEditText extends EditText {
|
||||||
setKeyListener(mKeyListener);
|
setKeyListener(mKeyListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setTextIsSelectable(boolean selectable) {
|
|
||||||
mTextIsSelectable = selectable;
|
|
||||||
super.setTextIsSelectable(selectable);
|
|
||||||
}
|
|
||||||
|
|
||||||
// VisibleForTesting from {@link TextInputEventsTestCase}.
|
// VisibleForTesting from {@link TextInputEventsTestCase}.
|
||||||
public void requestFocusFromJS() {
|
public void requestFocusFromJS() {
|
||||||
mIsJSSettingFocus = true;
|
mIsJSSettingFocus = true;
|
||||||
|
|
Loading…
Reference in New Issue