多主题的需求在很多 Android 应用中都有存在,实现方式也是多种多样。有以插件化方式实现的,也有以修改原生控件颜色的方式实现的。
本文所写的就是以修改原生控件颜色的方式应用主题的,EditText 的修改。
然而,这个不是这么好做的。。QAQ
首先查阅 EditText 的 API 文档,发现还是提供了两个方法的
使用 EditText.setBackgroundTintList(colorStateList) 可以设置 EditText 下划线的颜色
使用 EditText.setHighlightColor(color) 可以设置 EditText 选中文字后的高亮颜色
恩,改完后确实生效了
但是。。输入光标和光标控制滑块还是原来的颜色,反而不伦不类的了。。
于是查看 EditText 的源码,发现是在它的父类 —— TextView 中的 mEditor 这个对象中控制的,但是这个变量是 private 的,也没有提供公开的获得方法,无奈只好用反射了
1 2 3 4 5 6 7
| private static Field mEditor;
private static void getEditorFieldFromReflect() { if (mEditor == null) { mEditor = ReflectUtils.getDeclaredField(TextView.class, "mEditor"); } }
|
为了让反射达到最大的性能,声明了一个静态属性 mEditor,并在它为 null 的时候才进行反射(下同)
- ReflectUtils 是一个自定义的反射工具类
再获取输入光标的 Field 对象
1 2 3 4 5 6 7
| private static Field mCursorDrawableRes;
private static void getCursorFieldFromReflect() { if (mCursorDrawableRes == null) { mCursorDrawableRes = ReflectUtils.getDeclaredField(TextView.class, "mCursorDrawableRes"); } }
|
这样就获取了输入光标的原始 id,也就是 mCursorDrawableRes
由于原始的 CursorDrawable,是存在于 Android Framework 中的 framework-res.apk 中的,所以这里用一种曲线救国的方式,先获取到他的 id,进而获取到 Drawable,然后通过 Android 5.0 新增的 Tint 方式渲染 Drawable 的颜色,再设置进去
实现代码如下
1 2 3 4 5 6 7 8 9 10 11
| private static void setCursorColor(EditText editText, int color, Object editor) throws Exception { int cursorId = mCursorDrawableRes.getInt(editText); Drawable drawable = editText.getContext().getDrawable(cursorId);
if (drawable != null) { drawable.setTint(color); }
ReflectUtils.setObjectField(mEditor.getType(), "mCursorDrawable", editor, new Drawable[]{drawable, drawable}); }
|
这样输入光标的颜色就修改完成了
之后就是光标控制滑块的颜色了
查看源码,发现这个对应的是三个 Drawable
只是这些的 id 是在 EditText 里的。于是,故技重施,和 mCursorDrawableRes 一样
1 2 3 4 5 6 7 8 9 10
| private static void getSelectFieldFromReflect() { if (mSelectHandleLeft == null || mSelectHandleRight == null || mSelectHandleCenter == null) {
Class<?> EditorClass = mEditor.getType();
mSelectHandleLeft = ReflectUtils.getDeclaredField(EditorClass, "mSelectHandleLeft"); mSelectHandleRight = ReflectUtils.getDeclaredField(EditorClass, "mSelectHandleRight"); mSelectHandleCenter = ReflectUtils.getDeclaredField(EditorClass, "mSelectHandleCenter"); } }
|
1 2 3 4 5 6 7 8 9
| private static void setSelectHandleColor(EditText editText, int color, Object editor) throws Exception { Drawable leftDrawable = (Drawable) mSelectHandleLeft.get(editor); Drawable rightDrawable = (Drawable) mSelectHandleRight.get(editor); Drawable centerDrawable = (Drawable) mSelectHandleCenter.get(editor); updateSelectHandleColor(leftDrawable, "mTextSelectHandleLeftRes", editText, color); updateSelectHandleColor(rightDrawable, "mTextSelectHandleRightRes", editText, color); updateSelectHandleColor(centerDrawable, "mTextSelectHandleRes", editText, color); }
|
最后做个 setColor 的封装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public static void setColor(EditText editText, int color) { setUnderlineColor(editText, color); setHighlightColor(editText, color); try { getEditorFieldFromReflect(); getCursorFieldFromReflect(); getSelectFieldFromReflect(); Object editor = mEditor.get(editText); setCursorColor(editText, color, editor); setSelectHandleColor(editText, color, editor); } catch (Exception e) { e.printStackTrace(); } }
|
需要时直接 EditColorHelper.setColor(EditText, Color) 就可以了