当前位置: 移动技术网 > 移动技术>移动开发>Android > Android自定义控件实现底部菜单(上)

Android自定义控件实现底部菜单(上)

2019年07月24日  | 移动技术网移动技术  | 我要评论

今天我们封装一个底部的菜单栏,这个大多数的应用都会用到,因此我们来自定义,方便以后项目的使用。

该控件的实现将分上下篇来介绍,先来看一个菜单栏的子控件–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。
全部代码已托管到开源中国的码云上,欢迎下载,地址:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网