Android自定义控件系列(四)—底部菜单(下)
转载请注明出处:http://www.cnblogs.com/landptf/p/6290862.html
在app中经常会用到底部菜单的控件,每次都需要写好多代码,今天我们用到了前几篇博客里的控件来进一步封装底部菜单。先看效果图:
主要包括以下功能:
1 设置icon以及点击之后的icon
2 设置文字
3 设置文字颜色以及点击之后的文字颜色
4 设置未读数量、更多以及new
我们先看如何使用,然后再看如何实现的
1 在布局文件中引用MenuM
1 <com.landptf.view.MenuM 2 android:id="@+id/mm_bottom" 3 android:layout_width="match_parent" 4 android:layout_height="56dp" 5 android:layout_alignParentBottom="true" 6 landptf:backColor="@color/content" 7 landptf:textColor="@color/text" 8 landptf:textColorPress="@color/colorPrimary" 9 landptf:count="4" 10 />
这里主要说一下count属性,表示菜单项的个数。
2 在Activity中初始化
1 final MenuM mmBottom = (MenuM) findViewById(R.id.mm_bottom); 2 mmBottom.setText(text); 3 mmBottom.setIconDrawable(iconDrawable); 4 mmBottom.setIconDrawablePress(iconDrawablePress); 5 //设置默认选中第一项 6 mmBottom.setPressState(0, MotionEvent.ACTION_DOWN); 7 mmBottom.setOnItemClickListener(new MenuM.OnItemClickListener() { 8 @Override 9 public void onItemClick(int position) { 10 Toast.makeText(MenuMTestActivity.this, mmBottom.getText(position), Toast.LENGTH_SHORT).show(); 11 } 12 }); 13 14 mmBottom.setUnReadCount(0, 100); 15 mmBottom.setUnReadCount(1, 15); 16 mmBottom.setVisibilityMore(2, View.VISIBLE); 17 mmBottom.setVisibilityNew(3, View.VISIBLE);
有以下几个全局变量
1 text = new String[]{"首页", "通讯录", "发现", "我"}; 2 //为了演示方便我只找了两张icon,在实际开发中一般需要从网络上下载,然后在设置 3 Drawable drawable = getResources().getDrawable(R.drawable.icon_home_page); 4 Drawable drawablePress = getResources().getDrawable(R.drawable.icon_home_page_press); 5 iconDrawable = new Drawable[]{drawable, drawable, drawable, drawable}; 6 iconDrawablePress = new Drawable[]{drawablePress, drawablePress, drawablePress, drawablePress};
以上就是全部代码是不是很方便呢!!!
接下来我们来看下如何实现的
1 在style里定义了几个属性这里就不贴出来了,大家可以查看源码,在本文的最后会给出全部源码的下载地址
2 MenuM.java
1 package com.landptf.view; 2 3 import android.content.Context; 4 import android.content.res.ColorStateList; 5 import android.content.res.TypedArray; 6 import android.graphics.drawable.Drawable; 7 import android.support.annotation.Nullable; 8 import android.util.AttributeSet; 9 import android.util.Log; 10 import android.view.MotionEvent; 11 import android.view.View; 12 import android.view.ViewGroup; 13 import android.widget.LinearLayout; 14 import android.widget.RelativeLayout; 15 16 import com.landptf.R; 17 18 import java.util.ArrayList; 19 import java.util.List; 20 21 /** 22 * Created by landptf on 2017/01/15. 23 * 菜单,可用于底部导航菜单,以及内容区的菜单列表 24 */ 25 public class MenuM extends LinearLayout { 26 private static final String TAG = MenuM.class.getSimpleName(); 27 28 private Context mContext; 29 private List<MenuItemM> menuList; 30 private List<RelativeLayout> rlList; 31 private OnItemClickListener mOnItemClickListener; 32 private int count = 0; 33 34 public MenuM(Context context) { 35 this(context, null, 0); 36 } 37 38 public MenuM(Context context, AttributeSet attrs) { 39 this(context, attrs, 0); 40 } 41 42 public MenuM(Context context, AttributeSet attrs, int defStyle) { 43 super(context, attrs, defStyle); 44 mContext = context; 45 init(attrs, defStyle); 46 } 47 48 private void init(AttributeSet attrs, int defStyle) { 49 setOrientation(LinearLayout.HORIZONTAL); 50 TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.menuM, defStyle, 0); 51 if (a != null) { 52 //初始化菜单数量 53 count = a.getInteger(R.styleable.menuM_count, 0); 54 if (count > 0) { 55 initControl(); 56 } 57 //设置背景色 58 ColorStateList colorList = a.getColorStateList(R.styleable.menuM_backColor); 59 if (colorList != null) { 60 int backColor = colorList.getColorForState(getDrawableState(), 0); 61 if (backColor != 0) { 62 setBackColor(backColor); 63 } 64 } 65 //设置文字的颜色 66 ColorStateList textColorList = a.getColorStateList(R.styleable.menuM_textColor); 67 if (textColorList != null) { 68 int textColor = textColorList.getColorForState(getDrawableState(), 0); 69 if (textColor != 0) { 70 setTextColor(textColor); 71 } 72 } 73 //记录View被按下时文字的颜色 74 ColorStateList textColorPressList = a.getColorStateList(R.styleable.menuM_textColorPress); 75 if (textColorPressList != null) { 76 int textColorPress = textColorPressList.getColorForState(getDrawableState(), 0); 77 if (textColorPress != 0) { 78 setTextColorPress(textColorPress); 79 } 80 } 81 //设置文本字体大小 82 float textSize = a.getFloat(R.styleable.menuM_textSize, 0); 83 if (textSize != 0) { 84 setTextSize(textSize); 85 } 86 a.recycle(); 87 } 88 } 89 90 /** 91 * 由于MenuItemM是有ButtonExtendM扩展而来,为了适应上下左右不同的样式 92 * 需要在MenuItemM外层嵌套一层RelativeLayout,暂时没有找到更好的替代方案 93 */ 94 private void initControl() { 95 rlList = new ArrayList<>(count); 96 menuList = new ArrayList<>(count); 97 for (int i = 0; i < count; i++) { 98 RelativeLayout rlPanel = new RelativeLayout(mContext); 99 LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT); 100 lp.weight = 1; 101 rlPanel.setLayoutParams(lp); 102 final MenuItemM menuItem = new MenuItemM(mContext); 103 RelativeLayout.LayoutParams lpR = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 104 lpR.addRule(RelativeLayout.CENTER_IN_PARENT); 105 menuItem.setLayoutParams(lpR); 106 menuItem.setOnClickListener(new MenuItemM.OnClickListener() { 107 @Override 108 public void onClick(View v) { 109 //此处需要根据view获取position 110 MenuM.this.onClick(getPosition(menuItem)); 111 } 112 }); 113 rlPanel.addView(menuItem); 114 menuList.add(menuItem); 115 rlList.add(rlPanel); 116 addView(rlPanel); 117 } 118 } 119 120 /** 121 * 设置View的背景色 122 * 123 * @param backColor 124 */ 125 public void setBackColor(int backColor) { 126 if (backColor == 0) return; 127 if (!checkCount()) { 128 return; 129 } 130 for (RelativeLayout item : rlList) { 131 item.setBackgroundColor(backColor); 132 } 133 for (MenuItemM item : menuList) { 134 item.setBackColor(backColor); 135 } 136 } 137 138 /** 139 * 设置文字的颜色 140 * 141 * @param textColor 142 */ 143 public void setTextColor(int textColor) { 144 if (textColor == 0) return; 145 if (!checkCount()) { 146 return; 147 } 148 for (MenuItemM item : menuList) { 149 item.setTextColor(textColor); 150 } 151 } 152 153 /** 154 * 设置View被按下时文字的颜色 155 * 156 * @param textColorPress 157 */ 158 public void setTextColorPress(int textColorPress) { 159 if (textColorPress == 0) return; 160 if (!checkCount()) { 161 return; 162 } 163 for (MenuItemM item : menuList) { 164 item.setTextColorPress(textColorPress); 165 } 166 } 167 168 /** 169 * 设置icon的图片 170 * 171 * @param iconDrawable 172 */ 173 public void setIconDrawable(Drawable[] iconDrawable) { 174 if (count != iconDrawable.length) { 175 Log.e(TAG, "the iconDrawable length do not equals count"); 176 return; 177 } 178 for (int i = 0; i < count; i++) { 179 if (iconDrawable[i] != null) { 180 menuList.get(i).setIconDrawable(iconDrawable[i]); 181 } 182 } 183 } 184 185 /** 186 * 设置icon的图片 187 * 188 * @param iconDrawable 189 */ 190 public void setIconDrawable(List<Drawable> iconDrawable) { 191 if (count != iconDrawable.size()) { 192 Log.e(TAG, "the iconDrawable length do not equals count"); 193 return; 194 } 195 for (int i = 0; i < count; i++) { 196 if (iconDrawable.get(i) != null) { 197 menuList.get(i).setIconDrawable(iconDrawable.get(i)); 198 } 199 } 200 } 201 202 /** 203 * 设置View被按下时的icon的图片 204 * 205 * @param iconDrawablePress 206 */ 207 public void setIconDrawablePress(Drawable[] iconDrawablePress) { 208 if (count != iconDrawablePress.length) { 209 Log.e(TAG, "the iconDrawablePress length do not equals count"); 210 return; 211 } 212 for (int i = 0; i < count; i++) { 213 if (iconDrawablePress[i] != null) { 214 menuList.get(i).setIconDrawablePress(iconDrawablePress[i]); 215 } 216 } 217 } 218 219 /** 220 * 设置View被按下时的icon的图片 221 * 222 * @param iconDrawablePress 223 */ 224 public void setIconDrawablePress(List<Drawable> iconDrawablePress) { 225 if (count != iconDrawablePress.size()) { 226 Log.e(TAG, "the iconDrawablePress length do not equals count"); 227 return; 228 } 229 for (int i = 0; i < count; i++) { 230 if (iconDrawablePress.get(i) != null) { 231 menuList.get(i).setIconDrawablePress(iconDrawablePress.get(i)); 232 } 233 } 234 } 235 236 /** 237 * 设置显示的文本内容 238 * 239 * @param text 240 */ 241 public void setText(CharSequence[] text) { 242 for (int i = 0; i < count; i++) { 243 menuList.get(i).setText(text[i]); 244 } 245 } 246 247 /** 248 * 设置显示的文本内容 249 * 250 * @param text 251 */ 252 public void setText(List<CharSequence> text) { 253 if (count != text.size()) { 254 Log.e(TAG, "the text length do not equals count"); 255 return; 256 } 257 for (int i = 0; i < count; i++) { 258 menuList.get(i).setText(text.get(i)); 259 } 260 } 261 262 /** 263 * 获取显示的文本 264 * 265 * @return 266 */ 267 public String getText(int index) { 268 if (!checkIndex(index)) { 269 return ""; 270 } 271 return menuList.get(index).getText(); 272 } 273 274 /** 275 * 设置文本字体大小 276 * 277 * @param size 278 */ 279 public void setTextSize(float size) { 280 if (!checkCount()) { 281 return; 282 } 283 for (MenuItemM item : menuList) { 284 item.setTextSize(size); 285 } 286 } 287 288 /** 289 * 设置更多提示是否显示 290 * 如果显示则先重置new和未读数量图标 291 * 292 * @param visibleMore 293 */ 294 public void setVisibilityMore(int index, int visibleMore) { 295 if (!checkIndex(index)) { 296 return; 297 } 298 menuList.get(index).setVisibilityMore(visibleMore); 299 } 300 301 /** 302 * 设置New提示是否显示 303 * 如果显示则先重置更多和未读数量图标 304 * 305 * @param visibleNew 306 */ 307 public void setVisibilityNew(int index, int visibleNew) { 308 if (!checkIndex(index)) { 309 return; 310 } 311 menuList.get(index).setVisibilityNew(visibleNew); 312 } 313 314 /** 315 * 设置未读数量 316 * 如果小于等于0,表示隐藏 317 * 如果大于99,则将其隐藏,同时显示更多的提示 318 * 如果在0-99区间,则隐藏更多和new图标 319 * 320 * @param unReadCount 321 */ 322 public void setUnReadCount(int index, int unReadCount) { 323 if (!checkIndex(index)) { 324 return; 325 } 326 menuList.get(index).setUnReadCount(unReadCount); 327 } 328 329 /** 330 * 设置为被选中状态 331 * 332 * @param index 333 * @param state in MotionEvent.ACTION_DOWN or MotionEvent.ACTION_UP 334 */ 335 public void setPressState(int index, int state) { 336 if (!checkIndex(index)) { 337 return; 338 } 339 menuList.get(index).setPressState(state); 340 } 341 342 /** 343 * 设置菜单点击事件 344 * 345 * @param listener 346 */ 347 public void setOnItemClickListener(@Nullable OnItemClickListener listener) { 348 mOnItemClickListener = listener; 349 } 350 351 private void onClick(int position) { 352 for (int i = 0; i < count; i++) { 353 if (i == position) { 354 setPressState(i, MotionEvent.ACTION_DOWN); 355 } else { 356 setPressState(i, MotionEvent.ACTION_UP); 357 } 358 } 359 mOnItemClickListener.onItemClick(position); 360 } 361 362 /** 363 * 获取点击菜单项的位置 364 * @param item 365 * @return 366 */ 367 private int getPosition(MenuItemM item) { 368 for (int i = 0; i < count; i++) { 369 if (item == menuList.get(i)) { 370 return i; 371 } 372 } 373 return -1; 374 } 375 376 /** 377 * 检查是否设置了Count参数 378 * 379 * @return 380 */ 381 private boolean checkCount() { 382 if (count == 0) { 383 Log.e(TAG, "You must set the count first"); 384 return false; 385 } 386 return true; 387 } 388 389 /** 390 * 校验输入参数是否合法 391 * 392 * @param index 393 * @return 394 */ 395 private boolean checkIndex(int index) { 396 if (!checkCount()) { 397 return false; 398 } 399 if (index < 0 || index >= count) { 400 Log.e(TAG, "the index is wrong"); 401 return false; 402 } 403 return true; 404 } 405 406 public interface OnItemClickListener { 407 void onItemClick(int position); 408 } 409 }
代码比较简单,相信大家看一遍都可以理解,这里面使用了MenuItemM自定义控件,有不了解的可以参考以前的博客http://www.cnblogs.com/landptf/p/6290841.html或者查看源码。
拖了两个多月终于完成了,身体是革命的本钱,各位早点休息,多锻炼!!!
全部代码已托管到开源中国的码云上,欢迎下载,地址:https://git.oschina.net/landptf/landptf.git