Change cursor color when using selectionColor on Android

Summary:
This matches the behavior on iOS, there was no way before to change the cursor color per input, it was only possible to change it globally via the theme. Ideally cursor color and selection color would be 2 different props but I think this is better than what we have (and matches iOS).

Sadly there is no api to change it pragmatically (only possible via xml) so this uses reflection and can easily break so it is wrapped in a try catch to avoid crashes. I think it is better to just silently fail in this case. Definetly not super happy about the solution but I think it's worth adding since it is possible to do it natively using xml so it would suck not to be able to do it in RN.

**Test plan**
Tested that the cursor has the same color as before the change when not setting the prop and that it gets the selectionColor color when set.
Closes https://github.com/facebook/react-native/pull/12280

Differential Revision: D4571858

Pulled By: astreet

fbshipit-source-id: 7dca2db33a0a4eecb6115b45155549b1265ffbed
This commit is contained in:
Janic Duplessis 2017-02-16 04:29:53 -08:00 committed by Facebook Github Bot
parent a2addbd932
commit ae57b25134
3 changed files with 36 additions and 2 deletions

View File

@ -409,7 +409,7 @@ const TextInput = React.createClass({
*/
secureTextEntry: PropTypes.bool,
/**
* The highlight (and cursor on iOS) color of the text input.
* The highlight and cursor color of the text input.
*/
selectionColor: ColorPropType,
/**

View File

@ -5,6 +5,7 @@ android_library(
srcs = glob(['*.java']),
deps = [
YOGA_TARGET,
react_native_dep('third-party/android/support/v4:lib-support-v4'),
react_native_dep('third-party/java/infer-annotations:infer-annotations'),
react_native_dep('third-party/java/jsr-305:jsr-305'),
react_native_target('java/com/facebook/react/bridge:bridge'),
@ -22,4 +23,3 @@ android_library(
'PUBLIC',
],
)

View File

@ -11,11 +11,14 @@ package com.facebook.react.views.textinput;
import javax.annotation.Nullable;
import java.lang.reflect.Field;
import java.util.LinkedList;
import java.util.Map;
import android.graphics.drawable.Drawable;
import android.graphics.PorterDuff;
import android.graphics.Typeface;
import android.support.v4.content.ContextCompat;
import android.text.Editable;
import android.text.InputFilter;
import android.text.InputType;
@ -310,6 +313,37 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
} else {
view.setHighlightColor(color);
}
setCursorColor(view, color);
}
private void setCursorColor(ReactEditText view, @Nullable Integer color) {
// Evil method that uses reflection because there is no public API to changes
// the cursor color programmatically.
// Based on http://stackoverflow.com/questions/25996032/how-to-change-programatically-edittext-cursor-color-in-android.
try {
// Get the original cursor drawable resource.
Field cursorDrawableResField = TextView.class.getDeclaredField("mCursorDrawableRes");
cursorDrawableResField.setAccessible(true);
int drawableResId = cursorDrawableResField.getInt(view);
Drawable drawable = ContextCompat.getDrawable(view.getContext(), drawableResId);
if (color != null) {
drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);
}
Drawable[] drawables = {drawable, drawable};
// Update the current cursor drawable with the new one.
Field editorField = TextView.class.getDeclaredField("mEditor");
editorField.setAccessible(true);
Object editor = editorField.get(view);
Field cursorDrawableField = editor.getClass().getDeclaredField("mCursorDrawable");
cursorDrawableField.setAccessible(true);
cursorDrawableField.set(editor, drawables);
} catch (NoSuchFieldException ex) {
// Ignore errors to avoid crashing if these private fields don't exist on modified
// or future android versions.
} catch (IllegalAccessException ex) {}
}
@ReactProp(name = "selectTextOnFocus", defaultBoolean = false)