Android自定义控件实现底部菜单(上)
今天我们封装一个底部的菜单栏,这个大多数的应用都会用到,因此我们来自定义,方便以后项目的使用。
该控件的实现将分上下篇来介绍,先来看一个菜单栏的子控件–menuitemm,这个控件有什么用呢?我们来看下一些主流app上的一些控件,如:
以上三张图片分别来自微信,今日头条和去哪儿,接下来我们将看到如何通过一个控件来实现不同的效果。
首先看下我写的一个deme
可以看到标题栏的消息控件,以及底部三个菜单项都是通过menuitemm来实现的
这里面只是演示菜单栏的子控件,我们将在下一篇博客中完成底部菜单栏的封装,这个控件里使用了上一篇博客介绍的一个控件buttonextendm,可以先看一下
接下来看下实现过程
1 定义属性
<declare-styleable name="menuitemm"> <attr name="backcolor" /> <attr name="textcolor" /> <attr name="textcolorpress" /> <attr name="icondrawable" /> <attr name="icondrawablepress" /> <attr name="text" /> <attr name="textsize" /> <attr name="unreadcount" format="integer" /> <attr name="visiblemore"> <enum name="visible" value="0x00000000" /> <enum name="gone" value="0x00000008" /> </attr> <attr name="visiblenew"> <enum name="visible" value="0x00000000" /> <enum name="gone" value="0x00000008" /> </attr> </declare-styleable>
这里面重点看一下visiblemore和visiblenew里面的两个枚举值,这里面与view源码中的visible和gone保持一致。关于如何定义属性以及使用,可以参考我之前的博客。
2 布局文件view_menu_item_m.xml
<?xml version="1.0" encoding="utf-8"?> <framelayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:landptf="http://schemas.android.com/apk/res-auto" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center"> <com.landptf.view.buttonextendm android:id="@+id/bem_menu" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginright="8dp" landptf:style="iconup" /> <imageview android:id="@+id/iv_more" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="top|right" android:background="@drawable/icon_more" android:visibility="gone" /> <imageview android:id="@+id/iv_new" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="top|right" android:background="@drawable/icon_new" android:visibility="gone" /> <com.landptf.view.buttonm android:id="@+id/btm_unread_count" android:layout_width="20dp" android:layout_height="20dp" android:layout_gravity="top|right" android:textsize="12sp" android:visibility="gone" landptf:backcolor="#ff0000" landptf:fillet="true" landptf:shape="oval" landptf:textcolor="@android:color/white" /> </framelayout>
这里面使用了framelayout,主要使用了buttonextendm上下结构的控件加上右上角的三种提示信息,数量提示,more提示,new提示
3 menuitemm.java
package com.landptf.view; import android.content.context; import android.content.res.colorstatelist; import android.content.res.typedarray; import android.graphics.drawable.drawable; import android.util.attributeset; import android.util.log; import android.view.gravity; import android.view.layoutinflater; import android.view.motionevent; import android.view.view; import android.widget.framelayout; import android.widget.imageview; import com.landptf.r; /** * created by landptf on 2016/11/07. * 菜单按钮,例如底部菜单的item或者消息控件 */ public class menuitemm extends framelayout { private static final string tag = menuitemm.class.getsimplename(); /** * 定义控件 */ private buttonextendm bemmenu; private imageview ivmore; private imageview ivnew; private buttonm btmunreadcount; private onclicklistener onclicklistener = null; public interface onclicklistener { void onclick(view v); } /** * 设置view的click事件 * * @param l */ public void setonclicklistener(onclicklistener l) { this.onclicklistener = l; //拦截buttonextendm控件的点击事件,使其指向this.onclick bemmenu.setonclicklistener(new buttonextendm.onclicklistener() { @override public void onclick(view v) { onclicklistener.onclick(v); } }); } public menuitemm(context context) { super(context); } public menuitemm(context context, attributeset attrs) { this(context, attrs, 0); } public menuitemm(context context, attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); init(context, attrs, defstyleattr); } private void init(context context, attributeset attrs, int defstyle) { //加载布局 layoutinflater.from(context).inflate(r.layout.view_menu_item_m, this, true); //初始化控件 bemmenu = (buttonextendm) findviewbyid(r.id.bem_menu); ivmore = (imageview) findviewbyid(r.id.iv_more); ivnew = (imageview) findviewbyid(r.id.iv_new); btmunreadcount = (buttonm) findviewbyid(r.id.btm_unread_count); btmunreadcount.setgravity(gravity.center); typedarray a = getcontext().obtainstyledattributes( attrs, r.styleable.menuitemm, defstyle, 0); if (a != null) { //设置背景色 colorstatelist colorlist = a.getcolorstatelist(r.styleable.menuitemm_backcolor); if (colorlist != null) { int backcolor = colorlist.getcolorforstate(getdrawablestate(), 0); if (backcolor != 0) { setbackcolor(backcolor); } } //设置icon drawable icondrawable = a.getdrawable(r.styleable.menuitemm_icondrawable); if (icondrawable != null) { seticondrawable(icondrawable); } //记录view被按下时的icon的图片 drawable icondrawablepress = a.getdrawable(r.styleable.menuitemm_icondrawablepress); if (icondrawablepress != null) { seticondrawablepress(icondrawablepress); } //设置文字的颜色 colorstatelist textcolorlist = a.getcolorstatelist(r.styleable.menuitemm_textcolor); if (textcolorlist != null) { int textcolor = textcolorlist.getcolorforstate(getdrawablestate(), 0); if (textcolor != 0) { settextcolor(textcolor); } } //记录view被按下时文字的颜色 colorstatelist textcolorpresslist = a.getcolorstatelist(r.styleable.menuitemm_textcolorpress); if (textcolorpresslist != null) { int textcolorpress = textcolorpresslist.getcolorforstate(getdrawablestate(), 0); if (textcolorpress != 0) { settextcolorpress(textcolorpress); } } //设置显示的文本内容 string text = a.getstring(r.styleable.menuitemm_text); if (text != null) { settext(text); } //设置文本字体大小 float textsize = a.getfloat(r.styleable.menuitemm_textsize, 0); if (textsize != 0) { settextsize(textsize); } //设置更多提示是否显示 int visiblemore = a.getint(r.styleable.menuitemm_visiblemore, -1); if (visiblemore != -1){ setvisibilitymore(visiblemore); } //设置new提示是否显示 int visiblenew = a.getint(r.styleable.menuitemm_visiblenew, -1); if (visiblenew != -1){ setvisibilitynew(visiblenew); } //设置消息未读数量 int unreadcount = a.getint(r.styleable.menuitemm_unreadcount, -1); if (unreadcount != -1){ setunreadcount(unreadcount); } a.recycle(); } setonclicklistener(new view.onclicklistener() { @override public void onclick(view v) { if (onclicklistener != null) { onclicklistener.onclick(v); } } }); } /** * 设置为被选中状态 * @param state in motionevent.action_down or motionevent.action_up */ public void setpressstate(int state){ if (state != motionevent.action_down && state != motionevent.action_up){ log.w(tag, "无效参数"); return; } bemmenu.setpressstate(state); } /** * 设置view的背景色 * * @param backcolor */ public void setbackcolor(int backcolor) { bemmenu.setbackcolor(backcolor); } /** * 设置icon的图片 * * @param icondrawable */ public void seticondrawable(drawable icondrawable) { bemmenu.seticondrawable(icondrawable); } /** * 设置view被按下时的icon的图片 * * @param icondrawablepress */ public void seticondrawablepress(drawable icondrawablepress) { bemmenu.seticondrawablepress(icondrawablepress); } /** * 设置文字的颜色 * * @param textcolor */ public void settextcolor(int textcolor) { if (textcolor == 0) return; bemmenu.settextcolor(textcolor); } /** * 设置view被按下时文字的颜色 * * @param textcolorpress */ public void settextcolorpress(int textcolorpress) { if (textcolorpress == 0) return; bemmenu.settextcolorpress(textcolorpress); } /** * 设置显示的文本内容 * * @param text */ public void settext(charsequence text) { bemmenu.settext(text); } /** * 获取显示的文本 * * @return */ public string gettext() { return bemmenu.gettext(); } /** * 设置文本字体大小 * * @param size */ public void settextsize(float size) { bemmenu.settextsize(size); } /** * 设置更多提示是否显示 * 如果显示则先重置new和未读数量图标 * @param visiblemore */ public void setvisibilitymore(int visiblemore) { if (visiblemore == visible) { resettip(); } ivmore.setvisibility(visiblemore); } /** * 设置new提示是否显示 * 如果显示则先重置更多和未读数量图标 * @param visiblenew */ public void setvisibilitynew(int visiblenew) { if (visiblenew == visible) { resettip(); } ivnew.setvisibility(visiblenew); } /** * 设置未读数量 * 如果小于等于0,表示隐藏 * 如果大于99,则将其隐藏,同时显示更多的提示 * 如果在0-99区间,则隐藏更多和new图标 * @param unreadcount */ public void setunreadcount(int unreadcount){ if (unreadcount <= 0){ btmunreadcount.setvisibility(gone); //如果先设置100(此时会显示ivmore),再设置0,因此此处应将ivmore同时置为gone if (ivmore.getvisibility() == visible){ ivmore.setvisibility(gone); } return; } if (unreadcount > 99){ setvisibilitymore(visible); return; } resettip(); btmunreadcount.setvisibility(visible); btmunreadcount.settext(unreadcount + ""); } /** * 重置提示信息 */ private void resettip(){ setvisibilitymore(gone); setvisibilitynew(gone); setunreadcount(0); } }
代码有点长,逻辑比较简单,本身自定义控件的过程都是类似的,比较多的是对外提供的接口。
特别要注意的是使用时大小要设置为自定义,如果指定了大小或者match_parent,则子控件将居于左上角,无法居中。
4 最后简单看下如何使用
<com.landptf.view.menuitemm android:id="@+id/mim_home_page" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centervertical="true" android:layout_marginleft="32dp" landptf:icondrawable="@drawable/icon_home_page" landptf:icondrawablepress="@drawable/icon_home_page_press" landptf:textcolor="#696969" landptf:textcolorpress="#303f9f" landptf:text="首页" />
这里面主要使用了以下四个属性,分别表示默认图标和按下后显示的图标,以及文字颜色和按下后的文字颜色
landptf:icondrawable="@drawable/icon_home_page" landptf:icondrawablepress="@drawable/icon_home_page_press" landptf:textcolor="#696969" landptf:textcolorpress="#303f9f"
final menuitemm mimhomepage = (menuitemm) findviewbyid(r.id.mim_home_page); if (mimhomepage != null){ //默认为选中状态 mimhomepage.setpressstate(motionevent.action_down); mimhomepage.setvisibilitymore(view.visible); mimhomepage.setonclicklistener(new menuitemm.onclicklistener() { @override public void onclick(view v) { //按下后隐藏提示信息 mimhomepage.setvisibilitymore(view.gone); } }); }
好了,就介绍到这里了,更多的使用方法可以参考源码menuitemmtestactivity.java。
全部代码已托管到开源中国的码云上,欢迎下载,地址:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。