欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2023-12-22 08:06:52
今天我们封装一个底部的菜单栏,这个大多数的应用都会用到,因此我们来自定义,方便以后项目的使用。 该控件的实现将分上下篇来介绍,先来看一个菜单栏的子控件–menuitemm...

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

该控件的实现将分上下篇来介绍,先来看一个菜单栏的子控件–menuitemm,这个控件有什么用呢?我们来看下一些主流app上的一些控件,如:

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

以上三张图片分别来自微信,今日头条和去哪儿,接下来我们将看到如何通过一个控件来实现不同的效果。
首先看下我写的一个deme

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

可以看到标题栏的消息控件,以及底部三个菜单项都是通过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。
全部代码已托管到开源中国的码云上,欢迎下载,地址:

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

上一篇:

下一篇: