转载请注明出处:http://www.cnblogs.com/landptf/p/6290841.html
今天我们封装一个底部的菜单栏,这个大多数的应用都会用到,因此我们来自定义,方便以后项目的使用。
该控件的实现将分上下篇来介绍,先来看一个菜单栏的子控件–MenuItemM,这个控件有什么用呢?我们来看下一些主流app上的一些控件,如:
以上三张图片分别来自微信,今日头条和去哪儿,接下来我们将看到如何通过一个控件来实现不同的效果。
首先看下我写的一个deme
可以看到标题栏的消息控件,以及底部三个菜单项都是通过MenuItemM来实现的
这里面只是演示菜单栏的子控件,我们将在下一篇博客中完成底部菜单栏的封装,这个控件里使用了上一篇博客介绍的一个控件ButtonExtendM,可以先看一下
http://www.cnblogs.com/landptf/p/6290810.html
接下来看下实现过程
1 定义属性
1 <declare-styleable name="MenuItemM"> 2 <attr name="backColor" /> 3 <attr name="textColor" /> 4 <attr name="textColorPress" /> 5 <attr name="iconDrawable" /> 6 <attr name="iconDrawablePress" /> 7 <attr name="text" /> 8 <attr name="textSize" /> 9 <attr name="unReadCount" format="integer" /> 10 <attr name="visibleMore"> 11 <enum name="visible" value="0x00000000" /> 12 <enum name="gone" value="0x00000008" /> 13 </attr> 14 <attr name="visibleNew"> 15 <enum name="visible" value="0x00000000" /> 16 <enum name="gone" value="0x00000008" /> 17 </attr> 18 </declare-styleable>
这里面重点看一下visibleMore和visibleNew里面的两个枚举值,这里面与View源码中的visible和gone保持一致。关于如何定义属性以及使用,可以参考我之前的博客。
2 布局文件view_menu_item_m.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:landptf="http://schemas.android.com/apk/res-auto" 4 android:layout_width="wrap_content" 5 android:layout_height="wrap_content" 6 android:layout_gravity="center"> 7 8 <com.landptf.view.ButtonExtendM 9 android:id="@+id/bem_menu" 10 android:layout_width="match_parent" 11 android:layout_height="match_parent" 12 android:layout_marginRight="8dp" 13 landptf:style="iconUp" /> 14 15 <ImageView 16 android:id="@+id/iv_more" 17 android:layout_width="wrap_content" 18 android:layout_height="wrap_content" 19 android:layout_gravity="top|right" 20 android:background="@drawable/icon_more" 21 android:visibility="gone" /> 22 23 <ImageView 24 android:id="@+id/iv_new" 25 android:layout_width="wrap_content" 26 android:layout_height="wrap_content" 27 android:layout_gravity="top|right" 28 android:background="@drawable/icon_new" 29 android:visibility="gone" /> 30 31 <com.landptf.view.ButtonM 32 android:id="@+id/btm_unread_count" 33 android:layout_width="20dp" 34 android:layout_height="20dp" 35 android:layout_gravity="top|right" 36 android:textSize="12sp" 37 android:visibility="gone" 38 landptf:backColor="#ff0000" 39 landptf:fillet="true" 40 landptf:shape="oval" 41 landptf:textColor="@android:color/white" /> 42 43 </FrameLayout>
这里面使用了FrameLayout,主要使用了ButtonExtendM上下结构的控件加上右上角的三种提示信息,数量提示,more提示,new提示
3 MenuItemM.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.util.AttributeSet; 8 import android.util.Log; 9 import android.view.Gravity; 10 import android.view.LayoutInflater; 11 import android.view.MotionEvent; 12 import android.view.View; 13 import android.widget.FrameLayout; 14 import android.widget.ImageView; 15 16 import com.landptf.R; 17 18 /** 19 * Created by landptf on 2016/11/07. 20 * 菜单按钮,例如底部菜单的item或者消息控件 21 */ 22 public class MenuItemM extends FrameLayout { 23 24 private static final String TAG = MenuItemM.class.getSimpleName(); 25 26 /** 27 * 定义控件 28 */ 29 private ButtonExtendM bemMenu; 30 private ImageView ivMore; 31 private ImageView ivNew; 32 private ButtonM btmUnReadCount; 33 34 private OnClickListener onClickListener = null; 35 36 public interface OnClickListener { 37 void onClick(View v); 38 } 39 40 /** 41 * 设置View的Click事件 42 * 43 * @param l 44 */ 45 public void setOnClickListener(OnClickListener l) { 46 this.onClickListener = l; 47 //拦截ButtonExtendM控件的点击事件,使其指向this.onclick 48 bemMenu.setOnClickListener(new ButtonExtendM.OnClickListener() { 49 @Override 50 public void onClick(View v) { 51 onClickListener.onClick(v); 52 } 53 }); 54 } 55 56 public MenuItemM(Context context) { 57 super(context); 58 } 59 60 public MenuItemM(Context context, AttributeSet attrs) { 61 this(context, attrs, 0); 62 } 63 64 public MenuItemM(Context context, AttributeSet attrs, int defStyleAttr) { 65 super(context, attrs, defStyleAttr); 66 init(context, attrs, defStyleAttr); 67 } 68 69 private void init(Context context, AttributeSet attrs, int defStyle) { 70 //加载布局 71 LayoutInflater.from(context).inflate(R.layout.view_menu_item_m, this, true); 72 //初始化控件 73 bemMenu = (ButtonExtendM) findViewById(R.id.bem_menu); 74 ivMore = (ImageView) findViewById(R.id.iv_more); 75 ivNew = (ImageView) findViewById(R.id.iv_new); 76 btmUnReadCount = (ButtonM) findViewById(R.id.btm_unread_count); 77 btmUnReadCount.setGravity(Gravity.CENTER); 78 TypedArray a = getContext().obtainStyledAttributes( 79 attrs, R.styleable.MenuItemM, defStyle, 0); 80 if (a != null) { 81 //设置背景色 82 ColorStateList colorList = a.getColorStateList(R.styleable.MenuItemM_backColor); 83 if (colorList != null) { 84 int backColor = colorList.getColorForState(getDrawableState(), 0); 85 if (backColor != 0) { 86 setBackColor(backColor); 87 } 88 } 89 //设置icon 90 Drawable iconDrawable = a.getDrawable(R.styleable.MenuItemM_iconDrawable); 91 if (iconDrawable != null) { 92 setIconDrawable(iconDrawable); 93 } 94 //记录View被按下时的icon的图片 95 Drawable iconDrawablePress = a.getDrawable(R.styleable.MenuItemM_iconDrawablePress); 96 if (iconDrawablePress != null) { 97 setIconDrawablePress(iconDrawablePress); 98 } 99 //设置文字的颜色 100 ColorStateList textColorList = a.getColorStateList(R.styleable.MenuItemM_textColor); 101 if (textColorList != null) { 102 int textColor = textColorList.getColorForState(getDrawableState(), 0); 103 if (textColor != 0) { 104 setTextColor(textColor); 105 } 106 } 107 //记录View被按下时文字的颜色 108 ColorStateList textColorPressList = a.getColorStateList(R.styleable.MenuItemM_textColorPress); 109 if (textColorPressList != null) { 110 int textColorPress = textColorPressList.getColorForState(getDrawableState(), 0); 111 if (textColorPress != 0) { 112 setTextColorPress(textColorPress); 113 } 114 } 115 //设置显示的文本内容 116 String text = a.getString(R.styleable.MenuItemM_text); 117 if (text != null) { 118 setText(text); 119 } 120 //设置文本字体大小 121 float textSize = a.getFloat(R.styleable.MenuItemM_textSize, 0); 122 if (textSize != 0) { 123 setTextSize(textSize); 124 } 125 //设置更多提示是否显示 126 int visibleMore = a.getInt(R.styleable.MenuItemM_visibleMore, -1); 127 if (visibleMore != -1){ 128 setVisibilityMore(visibleMore); 129 } 130 //设置new提示是否显示 131 int visibleNew = a.getInt(R.styleable.MenuItemM_visibleNew, -1); 132 if (visibleNew != -1){ 133 setVisibilityNew(visibleNew); 134 } 135 //设置消息未读数量 136 int unReadCount = a.getInt(R.styleable.MenuItemM_unReadCount, -1); 137 if (unReadCount != -1){ 138 setUnReadCount(unReadCount); 139 } 140 a.recycle(); 141 } 142 143 setOnClickListener(new View.OnClickListener() { 144 @Override 145 public void onClick(View v) { 146 if (onClickListener != null) { 147 onClickListener.onClick(v); 148 } 149 } 150 }); 151 } 152 153 /** 154 * 设置为被选中状态 155 * @param state in MotionEvent.ACTION_DOWN or MotionEvent.ACTION_UP 156 */ 157 public void setPressState(int state){ 158 if (state != MotionEvent.ACTION_DOWN && state != MotionEvent.ACTION_UP){ 159 Log.w(TAG, "无效参数"); 160 return; 161 } 162 bemMenu.setPressState(state); 163 } 164 165 /** 166 * 设置View的背景色 167 * 168 * @param backColor 169 */ 170 public void setBackColor(int backColor) { 171 bemMenu.setBackColor(backColor); 172 } 173 174 /** 175 * 设置icon的图片 176 * 177 * @param iconDrawable 178 */ 179 public void setIconDrawable(Drawable iconDrawable) { 180 bemMenu.setIconDrawable(iconDrawable); 181 } 182 183 /** 184 * 设置View被按下时的icon的图片 185 * 186 * @param iconDrawablePress 187 */ 188 public void setIconDrawablePress(Drawable iconDrawablePress) { 189 bemMenu.setIconDrawablePress(iconDrawablePress); 190 } 191 192 /** 193 * 设置文字的颜色 194 * 195 * @param textColor 196 */ 197 public void setTextColor(int textColor) { 198 if (textColor == 0) return; 199 bemMenu.setTextColor(textColor); 200 } 201 202 /** 203 * 设置View被按下时文字的颜色 204 * 205 * @param textColorPress 206 */ 207 public void setTextColorPress(int textColorPress) { 208 if (textColorPress == 0) return; 209 bemMenu.setTextColorPress(textColorPress); 210 } 211 212 /** 213 * 设置显示的文本内容 214 * 215 * @param text 216 */ 217 public void setText(CharSequence text) { 218 bemMenu.setText(text); 219 } 220 221 /** 222 * 获取显示的文本 223 * 224 * @return 225 */ 226 public String getText() { 227 return bemMenu.getText(); 228 } 229 230 /** 231 * 设置文本字体大小 232 * 233 * @param size 234 */ 235 public void setTextSize(float size) { 236 bemMenu.setTextSize(size); 237 } 238 239 /** 240 * 设置更多提示是否显示 241 * 如果显示则先重置new和未读数量图标 242 * @param visibleMore 243 */ 244 public void setVisibilityMore(int visibleMore) { 245 if (visibleMore == VISIBLE) { 246 resetTip(); 247 } 248 ivMore.setVisibility(visibleMore); 249 } 250 251 /** 252 * 设置New提示是否显示 253 * 如果显示则先重置更多和未读数量图标 254 * @param visibleNew 255 */ 256 public void setVisibilityNew(int visibleNew) { 257 if (visibleNew == VISIBLE) { 258 resetTip(); 259 } 260 ivNew.setVisibility(visibleNew); 261 } 262 263 /** 264 * 设置未读数量 265 * 如果小于等于0,表示隐藏 266 * 如果大于99,则将其隐藏,同时显示更多的提示 267 * 如果在0-99区间,则隐藏更多和new图标 268 * @param unReadCount 269 */ 270 public void setUnReadCount(int unReadCount){ 271 if (unReadCount <= 0){ 272 btmUnReadCount.setVisibility(GONE); 273 //如果先设置100(此时会显示ivMore),再设置0,因此此处应将ivMore同时置为GONE 274 if (ivMore.getVisibility() == VISIBLE){ 275 ivMore.setVisibility(GONE); 276 } 277 return; 278 } 279 if (unReadCount > 99){ 280 setVisibilityMore(VISIBLE); 281 return; 282 } 283 resetTip(); 284 btmUnReadCount.setVisibility(VISIBLE); 285 btmUnReadCount.setText(unReadCount + ""); 286 } 287 288 /** 289 * 重置提示信息 290 */ 291 private void resetTip(){ 292 setVisibilityMore(GONE); 293 setVisibilityNew(GONE); 294 setUnReadCount(0); 295 } 296 297 }
代码有点长,逻辑比较简单,本身自定义控件的过程都是类似的,比较多的是对外提供的接口。
特别要注意的是使用时大小要设置为自定义,如果指定了大小或者match_parent,则子控件将居于左上角,无法居中。
4 最后简单看下如何使用
1 <com.landptf.view.MenuItemM 2 android:id="@+id/mim_home_page" 3 android:layout_width="wrap_content" 4 android:layout_height="wrap_content" 5 android:layout_centerVertical="true" 6 android:layout_marginLeft="32dp" 7 landptf:iconDrawable="@drawable/icon_home_page" 8 landptf:iconDrawablePress="@drawable/icon_home_page_press" 9 landptf:textColor="#696969" 10 landptf:textColorPress="#303f9f" 11 landptf:text="首页" 12 />
这里面主要使用了以下四个属性,分别表示默认图标和按下后显示的图标,以及文字颜色和按下后的文字颜色
1 landptf:iconDrawable="@drawable/icon_home_page" 2 landptf:iconDrawablePress="@drawable/icon_home_page_press" 3 landptf:textColor="#696969" 4 landptf:textColorPress="#303f9f"
1 final MenuItemM mimHomePage = (MenuItemM) findViewById(R.id.mim_home_page); 2 if (mimHomePage != null){ 3 //默认为选中状态 4 mimHomePage.setPressState(MotionEvent.ACTION_DOWN); 5 mimHomePage.setVisibilityMore(View.VISIBLE); 6 mimHomePage.setOnClickListener(new MenuItemM.OnClickListener() { 7 @Override 8 public void onClick(View v) { 9 //按下后隐藏提示信息 10 mimHomePage.setVisibilityMore(View.GONE); 11 } 12 }); 13 }
好了,就介绍到这里了,更多的使用方法可以参考源码MenuItemMTestActivity.java。
全部代码已托管到开源中国的码云上,欢迎下载,地址:https://git.oschina.net/landptf/landptf.git