MaterialDrawer 是 Android 下用户不少的一个侧滑菜单类库,优点是为常见场景进行了相对周全的考虑和支持,缺点是在设计上有点过犹不及的意味。
三太爷在手上业余维护的一个项目,里面用到了它,所以在进行某些改动时,也不得不面对它,思考如何下手。上一次的需求在于,1. 要向 AccountHeader 中增加新的控件,2. 出于充分利用空间以及原有控件的某些功能的目的,希望将其原始 AccountHeader 中的预留的几个非主用户的头像控件复用起来;行为控制反倒好办,难点在于它自有风格是图片自动裁剪为圆形,要把这个行为屏蔽掉,以正确显示设置的图标,3. 要对复用过的头像控件增加 badge 功能。
对于需求 1,经过考察后发现可以算作是有官方支持的途径的,解决。需求 2,最后在合适的地方以轻量级的反射操作达到目的,解决。需求 3,由于 badge 的加入会干扰现有布局,以及在用户登入登出时头像控件的显隐操作,所以稍微费了点周折,也解决了。
后来发现,App 本身有个用户可以定制主题色调的功能,设置以后,侧滑菜单的默认设置有时候就会显得不很协调。翻看了一下 MaterialDrawer 的接口,似乎没有找到在程序运行过程中动态改变颜色的函数。在其项目的 issues 里,有人提问如何改变选定条目的高亮色,作者提供的思路一直驻留在更改 style/theme 资源文件的方向上,令人烦郁。问了几个专业 Android 开发的小兄弟,提供的信息也不能令人满意。
一开始的构思是,找到作用与 Drawer 的一个方法,使之在调用时不但将现有条目全部应用为所设置的颜色,还会将此值记下,作用于后续可能新增/重新创建的条目上。后来经过对源代码的考察,以及跟小伙伴们的探讨,决定仅增加对现有条目的影响,但并不希望仅提供作用于单一条目的方法,而使调用者自行去遍历;但同时,保留仅仅作用于单一条目的能力是必要的。于是跟峰峰小起锦标赛,看谁先写出来,然后再讨论优劣。
当晚(前天,13 号),花了一个多两个来钟头来写,后来索性要把它写完整为对条目内各个部分/状态颜色的支持,还做了一次重构,以达到代码复用的最佳状态。MaterialDrawer 中对颜色有所控制的条目类为 BaseDrawerItem
,因此本工具类的主要作用对象也就是针对它了。代码如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
package net.somedoc.android.ui.utils; import android.graphics.Color; import com.mikepenz.materialdrawer.Drawer; import com.mikepenz.materialdrawer.holder.ColorHolder; import com.mikepenz.materialdrawer.model.BaseDrawerItem; import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import java.util.Random; public class MaterialDrawerColorManager { // TODO: 可能弱引用才对 protected ArrayList<Drawer> mDrawers; public boolean addDrawer(Drawer drawer) { if (drawer == null) return false; if (mDrawers == null) mDrawers = new ArrayList<>(); return mDrawers.add(drawer); } public boolean removeDrawer(Drawer drawer) { if (drawer == null) return true; if (mDrawers == null) return false; return mDrawers.remove(drawer); } // // MaterialDrawer 的 BaseDrawerItem 类中共有七个颜色,其设置方式都一样 // 七种颜色是: // 1. selectedColor // 2. textColor // 3. selectedTextColor // 4. disabledtextColor // 5. iconColor // 6. selectedIconColor // 7. disabledIconColor // public enum ColorType { SELECTED_COLOR, TEXT_COLOR, SELECTED_TEXT_COLOR, DISABLED_TEXT_COLOR, ICON_COLOR, SELECTED_ICON_COLOR, DISABLED_ICON_COLOR, } // 0. 通用处理方式 public boolean setColor(int color, ColorType ct) { if (mDrawers == null) return true; for (Drawer drawer : mDrawers) setColor(drawer, color, ct); return true; } public static boolean setColor(Drawer drawer, int color, ColorType ct) { if (drawer == null) return false; List<IDrawerItem> items = drawer.getDrawerItems(); if (items == null) return true; for (IDrawerItem item : items) { BaseDrawerItem bdi; try { bdi = (BaseDrawerItem) item; } catch (Exception e) { continue; } setItemColor(bdi, color, ct); } return true; } protected static final String[] mColorFieldNames = { "selectedColor", "textColor", "selectedTextColor", "disabledTextColor", "iconColor", "selectedIconColor", "disabledIconColor", }; public static boolean setItemColor(BaseDrawerItem item, int color, ColorType ct) { if (item == null) return false; ColorHolder ch = ColorHolder.fromColor(color); try { Class cls = BaseDrawerItem.class; Field mask = cls.getDeclaredField(mColorFieldNames[ct.ordinal()]); mask.setAccessible(true); mask.set(item, ch); } catch (Exception e) { return false; } return true; } // 1. 处理 selectedColor public boolean setSelectedColor(int color) { return setColor(color, ColorType.SELECTED_COLOR); } public static boolean setSelectedColor(Drawer drawer, int color) { return setColor(drawer, color, ColorType.SELECTED_COLOR); } public static boolean setItemSelectedColor(BaseDrawerItem item, int color) { return setItemColor(item, color, ColorType.SELECTED_COLOR); } // 2. 处理 textColor public boolean setTextColor(int color) { return setColor(color, ColorType.TEXT_COLOR); } public static boolean setTextColor(Drawer drawer, int color) { return setColor(drawer, color, ColorType.TEXT_COLOR); } public static boolean setItemTextColor(BaseDrawerItem item, int color) { return setItemColor(item, color, ColorType.TEXT_COLOR); } // 3. 处理 selectedTextColor public boolean setSelectedTextColor(int color) { return setColor(color, ColorType.SELECTED_TEXT_COLOR); } public static boolean setSelectedTextColor(Drawer drawer, int color) { return setColor(drawer, color, ColorType.SELECTED_TEXT_COLOR); } public static boolean setItemSelectedTextColor(BaseDrawerItem item, int color) { return setItemColor(item, color, ColorType.SELECTED_TEXT_COLOR); } // 4. 处理 disabledTextColor public boolean setDisabledTextColor(int color) { return setColor(color, ColorType.DISABLED_TEXT_COLOR); } public static boolean setDisabledTextColor(Drawer drawer, int color) { return setColor(drawer, color, ColorType.DISABLED_TEXT_COLOR); } public static boolean setItemDisabledTextColor(BaseDrawerItem item, int color) { return setItemColor(item, color, ColorType.DISABLED_TEXT_COLOR); } // 5. 处理 iconColor public boolean setIconColor(int color) { return setColor(color, ColorType.ICON_COLOR); } public static boolean setIconColor(Drawer drawer, int color) { return setColor(drawer, color, ColorType.ICON_COLOR); } public static boolean setItemIconColor(BaseDrawerItem item, int color) { return setItemColor(item, color, ColorType.ICON_COLOR); } // 6. 处理 selectedIconColor public boolean setSelectedIconColor(int color) { return setColor(color, ColorType.SELECTED_ICON_COLOR); } public static boolean setSelectedIconColor(Drawer drawer, int color) { return setColor(drawer, color, ColorType.SELECTED_ICON_COLOR); } public static boolean setItemSelectedIconColor(BaseDrawerItem item, int color) { return setItemColor(item, color, ColorType.SELECTED_ICON_COLOR); } // 7. 处理 disabledIconColor public boolean setDisabledIconColor(int color) { return setColor(color, ColorType.DISABLED_ICON_COLOR); } public static boolean setDisabledIconColor(Drawer drawer, int color) { return setColor(drawer, color, ColorType.DISABLED_ICON_COLOR); } public static boolean setItemDisabledIconColor(BaseDrawerItem item, int color) { return setItemColor(item, color, ColorType.DISABLED_ICON_COLOR); } // 工具方法 public static int getRandomColor() { int r = 0; int g = 0; int b = 0; Random random = new Random(); for(int i=0; i<2; i++) { int t = random.nextInt(16); r = r * 16 + t; t = random.nextInt(16); g = g * 16 + t; t = random.nextInt(16); b = b * 16 + t; } return Color.rgb(r, g, b); } } |