zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    线段树刷题版
    HDU 1011 Starship Troopers 树形+背包dp
    POJ1741 Tree 树分治模板
    POJ3744 Scout YYF I 概率DP+矩阵快速幂
    【bzoj1875】【JZYZOJ1354】[SDOI2009]HH去散步 矩阵快速幂 点边转换
    BZOJ 3231: [Sdoi2008]递归数列 (JZYZOJ 1353) 矩阵快速幂
    POJ 2778 DNA Sequence AC自动机+矩阵快速幂
    POJ2222 Keywords Search AC自动机模板
    Python 命名空间
    svn下目录说明
  • 原文地址:https://www.cnblogs.com/landptf/p/6290862.html
Copyright © 2011-2022 走看看