Jusqu'à présent, j'ai utilisé la réflexion pour mettre à jour la poignée de sélection pour editTexts. Cela fonctionnait bien jusqu'à ce que je mette à jour l'api 29(Q).
Il semble que Google ait fait des mises à jour (ou Java, je ne suis pas tout à fait sûr), mais je reçois maintenant des messages comme :
Accès au champ caché Landroid/widget/Editor;->mDrawableForCursor:Landroid/graphics/drawable/Drawable ; (dark greylist, reflection)
Le point positif est que l'api 29 (après de nombreuses années) dispose d'une méthode stable pour définir la couleur de la poignée de manière programmatique. Malheureusement, elle n'est pas rétro-compatible pour autant que j'aie pu le découvrir et elle a également cassé des choses pour l'api 28. Tout ce qui est en dessous de l'api 28 fonctionne très bien avec la réflexion. Voici mon code qui fonctionne maintenant pour tout ce qui n'est pas l'api 28
/**
* Sets the color for the cursor and handles on the {@link EditText editText}.
*
* @throws EditTextTintError if an error occurs while tinting the view.
*/
public void apply() throws EditTextTintError {
try {
// Get the editor
Field field = TextView.class.getDeclaredField("mEditor");
field.setAccessible(true);
Object editor = field.get(editText);
if (cursorColor != null) {
editText.setHighlightColor(ColorUtils.setAlphaComponent(cursorColor, 40));
// Get the cursor drawable, tint it, and set it on the TextView Editor
// Get the cursor resource id
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
ColorFilter colorFilter = new BlendModeColorFilter(cursorColor, BlendMode.SRC_ATOP);
editText.getTextCursorDrawable().mutate().setColorFilter(colorFilter);
editText.getTextSelectHandle().mutate().setColorFilter(colorFilter);
editText.getTextSelectHandleLeft().mutate().setColorFilter(colorFilter);
editText.getTextSelectHandleRight().mutate().setColorFilter(colorFilter);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
try {
Field fieldP = TextView.class.getDeclaredField("mCursorDrawableRes");
fieldP.setAccessible(true);
int drawableResId = fieldP.getInt(editText);
// Get the editor
fieldP = TextView.class.getDeclaredField("mEditor");
fieldP.setAccessible(true);
Object editorP = fieldP.get(editText);
// Get the drawable and set a color filter
Drawable drawable = ContextCompat.getDrawable(editText.getContext(), drawableResId);
drawable.setColorFilter(cursorColor, PorterDuff.Mode.SRC_ATOP);
// Set the drawables
fieldP = editorP.getClass().getDeclaredField("mDrawableForCursor");
fieldP.setAccessible(true);
fieldP.set(editorP, drawable);
} catch (final Exception ignored) {
ignored.printStackTrace();
}
} else {
String[] resFieldNames = {"mTextSelectHandleLeftRes", "mTextSelectHandleRightRes", "mTextSelectHandleRes"};
String[] drawableFieldNames = {"mSelectHandleLeft", "mSelectHandleRight", "mSelectHandleCenter"};
Integer[] colors = {selectHandleLeftColor, selectHandleRightColor, selectHandleMiddleColor};
for (int i = 0; i < resFieldNames.length; i++) {
Integer color = colors[i];
if (color == null) {
continue;
}
String resFieldName = resFieldNames[i];
String drawableFieldName = drawableFieldNames[i];
field = TextView.class.getDeclaredField(resFieldName);
field.setAccessible(true);
int selectHandleRes = field.getInt(editText);
Drawable selectHandleDrawable = ContextCompat.getDrawable(editText.getContext(), selectHandleRes).mutate();
selectHandleDrawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);
field = editor.getClass().getDeclaredField(drawableFieldName);
field.setAccessible(true);
field.set(editor, selectHandleDrawable);
}
}
}
} catch (Exception e) {
throw new EditTextTintError("Error applying tint to " + editText, e);
}
}
Les arguments en faveur d'Android P sont détruits par la dernière mise à jour de Google :(
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
// insert working code here :D
}
Ma question est la suivante : quelqu'un a-t-il réussi à définir par programme la couleur de la poignée en utilisant l'api 29 pour des appareils fonctionnant avec l'api 28 ?
Par souci de clarté, il s'agit de la poignée dont il est question :