Allow overriding EditText construction in ReactTextInputShadowNode (#27782)

Summary:
This PR makes it possible for subclasses of `ReactTextInputShadowNode` to control the construction of the "dummy" `EditText` instance that `ReactTextInputShadowNode` internally uses to determine the expected height of the view. This PR does not change the default behavior, it just opens up that default to being overriden.

This is useful in the case of custom views that have different behavior from a "default" `EditText` instance (`new EditText(context)`). For example, it might have a different style applied.

As a side benefit, this change also makes it easy to have subclasses not apply the default theme, which can allow the custom view to avoid a longstanding crash issue (https://github.com/facebook/react-native/issues/17530).

## Changelog

[Android] [Added] - Allow overriding `EditText` construction in `ReactTextInputShadowNode`
Pull Request resolved: https://github.com/facebook/react-native/pull/27782

Test Plan: All tests pass.

Reviewed By: mdvacca

Differential Revision: D19450593

Pulled By: JoshuaGross

fbshipit-source-id: 8d2ce6117246fc3e2108623312b38583af5722b3
This commit is contained in:
Matt Chowning
2020-02-13 16:08:23 +01:00
committed by Eloy Durán
parent 925330bb83
commit 77305cadf0
@@ -37,7 +37,7 @@ public class ReactTextInputShadowNode extends ReactBaseTextShadowNode
implements YogaMeasureFunction {
private int mMostRecentEventCount = UNSET;
private @Nullable EditText mDummyEditText;
private @Nullable EditText mInternalEditText;
private @Nullable ReactTextInputLocalData mLocalData;
@VisibleForTesting public static final String PROP_TEXT = "text";
@@ -75,20 +75,20 @@ public class ReactTextInputShadowNode extends ReactBaseTextShadowNode
// of Android), and it cannot be changed.
// So, we have to enforce it as a default padding.
// TODO #7120264: Cache this stuff better.
EditText editText = new EditText(getThemedContext());
EditText editText = createInternalEditText();
setDefaultPadding(Spacing.START, ViewCompat.getPaddingStart(editText));
setDefaultPadding(Spacing.TOP, editText.getPaddingTop());
setDefaultPadding(Spacing.END, ViewCompat.getPaddingEnd(editText));
setDefaultPadding(Spacing.BOTTOM, editText.getPaddingBottom());
mDummyEditText = editText;
mInternalEditText = editText;
// We must measure the EditText without paddings, so we have to reset them.
mDummyEditText.setPadding(0, 0, 0, 0);
mInternalEditText.setPadding(0, 0, 0, 0);
// This is needed to fix an android bug since 4.4.3 which will throw an NPE in measure,
// setting the layoutParams fixes it: https://code.google.com/p/android/issues/detail?id=75877
mDummyEditText.setLayoutParams(
mInternalEditText.setLayoutParams(
new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
}
@@ -101,7 +101,7 @@ public class ReactTextInputShadowNode extends ReactBaseTextShadowNode
float height,
YogaMeasureMode heightMode) {
// measure() should never be called before setThemedContext()
EditText editText = Assertions.assertNotNull(mDummyEditText);
EditText editText = Assertions.assertNotNull(mInternalEditText);
if (mLocalData != null) {
mLocalData.apply(editText);
@@ -249,4 +249,12 @@ public class ReactTextInputShadowNode extends ReactBaseTextShadowNode
super.setPadding(spacingType, padding);
markUpdated();
}
/**
* May be overriden by subclasses that would like to provide their own instance of the internal
* {@code EditText} this class uses to determine the expected size of the view.
*/
protected EditText createInternalEditText() {
return new EditText(getThemedContext());
}
}