Android PopupWindow重写系统菜单(转载)

转自:http://www.eefocus.com/bbs/article_867_188597.html

个人感觉系统的菜单不是很好看,所以每次在应用添加菜单的时候总是自己用PopupWindow重写一个菜单,于是乎,写多了,自已想把它整理出来,以后可以重用。今天贴出来,与大家共享,写的不好的地方请指正。另外效率及扩展性方面还不够好,只是将平常用到的总结在一起,仅供参考。

先上图:

下面贴代码:
下面是整个菜单,主要是控制菜单的显示和消失,另外对文字和图片(大小最好都一样,否则最后效果有点难看)分别做了适配,其中对文字的长度进行了处理。相对于前一篇文章android PopupWindow模拟Windows开始菜单显示消失效果(http://www.linuxidc.com/Linux/2011-11/47440.htm)又介绍了PopupWindow的一些用法。另外还对菜单的高度的值进行了修正,因为菜单里面是用GridView进行适配的,如果GridView的高度比整个菜单的高度小那么就会出现滑动,很不好看,这里要注意一下,分别用H屏的和W屏的模拟器用图片、文字、图片+文字测试过,都没有问题。大家有什么更好的方法可以在下面留言。
Android PopupWindow重写系统菜单demo下载:
免费下载地址在 http://linux.linuxidc.com/
用户名与密码都是www.linuxidc.com
具体下载目录在 /pub/Android源码集锦/2011年/11月/Android PopupWindow重写系统菜单/
 
package com.jacp.menu.view;  
  
import java.util.ArrayList;  
  
import Android.content.Context;  
import android.content.res.Resources;  
import android.graphics.Bitmap;  
import android.graphics.BitmapFactory;  
import android.graphics.Color;  
import android.graphics.Paint;  
import android.graphics.Point;  
import android.graphics.Rect;  
import android.util.DisplayMetrics;  
import android.view.Gravity;  
import android.view.KeyEvent;  
import android.view.MotionEvent;  
import android.view.View;  
import android.view.View.OnKeyListener;  
import android.view.View.OnTouchListener;  
import android.view.ViewGroup;  
import android.widget.AdapterView;  
import android.widget.AdapterView.OnItemClickListener;  
import android.widget.GridView;  
import android.widget.LinearLayout;  
import android.widget.PopupWindow;  
  
/** 
 * 自定义菜单 
 * @author maylian7700@126.com 
 *  
 */  
public class MenuView  
{  
  
    private PopupWindow mPopup;  
    private Context mContext;  
      
    /** 
     * 图片资源 
     */  
    private int[] mImgRes = new int[0];  
      
    /** 
     * 文字资源 
     */  
    private String[] mTexts = new String[0];  
      
    /** 
     * 菜单背景 
     */  
    private int mBg;  
      
    /** 
     * 菜单显示消失的动画 
     */  
    private int mAnimStyle;  
      
    /** 
     * 文字大小 
     */  
    private float mTxtSize = -1;  
      
    /** 
     * 文字颜色 
     */  
    private int mTxtColor = -1;  
      
    /** 
     * 文本相对图片的对齐方式 
     */  
    private int mAlign = MenuItem.TEXT_BOTTOM;  
      
    /** 
     * 菜单项选中的效果 
     */  
    private int mSelector = -1;  
      
    /** 
     * 菜单的宽 
     */  
    private int mWidth;  
      
    /** 
     * 菜单的高 
     */  
    private int mHeight;  
      
    /** 
     * 存放菜单项 
     */  
    private GridView mGridView;  
      
    /** 
     * 设置文字的最大长度,超过则会以"..."替代 
     */  
    private int mMaxStrLength = 4;  
      
    /** 
     * 菜单项点击事件 
     */  
    private OnMenuItemClickListener mListener;  
      
    /** 
     * 是否对过长字符串采取优化 
     */  
    private boolean mIsOptimizeTxt = true;  
      
    /** 
     * 保存菜单项 
     */  
    private ArrayList<MenuItem> mMenuItems = new ArrayList<MenuItem>();  
      
    public MenuView(Context context)  
    {  
        if (null == context)  
        {  
            throw new IllegalArgumentException();  
        }  
          
        mContext = context;  
    }  
      
    /** 
     * 设置图片资源 
     * @param imgRes 
     */  
    public void setImageRes(int[] imgRes)  
    {  
        if (null != imgRes)  
        {  
            mImgRes = imgRes;  
        }  
    }  
      
    /** 
     * 设置菜单背景 
     * @param bgRes 
     */  
    public void setBackgroundResource(int bgRes)  
    {  
        mBg = bgRes;  
    }  
      
    /** 
     * 设置菜单项的文字 
     * @param txtRes 资源数组 
     */  
    public void setText(int[] txtRes)  
    {  
        if (null == txtRes)  
        {  
            return;  
        }  
          
        final Resources res = mContext.getResources();  
        final int length = txtRes.length;  
        mTexts = new String[length];  
        for (int i = 0; i < length; i++)  
        {  
            mTexts[i] = res.getString(txtRes[i]);  
        }  
    }  
      
    /** 
     * 设置菜单项的文字 
     * @param txtRes 
     */  
    public void setText(String[] texts)  
    {  
        mTexts = texts;  
    }  
      
    /** 
     * 设置文字大小 
     * @param txtSize 
     */  
    public void setTextSize(float txtSize)  
    {  
        mTxtSize = txtSize;  
    }  
      
    /** 
     * 设置文字颜色 
     * @param color 
     */  
    public void setTextColor(int color)  
    {  
        mTxtColor = color;  
    }  
      
    /** 
     * 设置文本相对图片的对齐方式 
     * @param align 
     */  
    public void setTextAlign(int align)  
    {  
        mAlign = align;  
    }  
      
    /** 
     * 允许文本的最大长度 
     * @param length 
     */  
    public void setMaxTextLength(int length)  
    {  
        mMaxStrLength = length;  
    }  
      
    /** 
     * 设置是否对过长文本进行优化 
     * @param isOptimize 
     */  
    public void isOptimizeText(boolean isOptimize)  
    {  
        mIsOptimizeTxt = isOptimize;  
    }  
      
    /** 
     * 设置菜单动画 
     * @param animStyle 
     */  
    public void setAnimStyle(int animStyle)  
    {  
        mAnimStyle = animStyle;  
    }  


/**
* 设置菜单的宽度
* @param width
*/
public void setWidth(int width)
{
mWidth = width;
}

/**
* 设置菜单的高度
* @param height
*/
public void setHeight(int height)
{
mHeight = height;
}

/**
* 设置菜单被项被选中的效果
* @param selector
*/
public void setSelector(int selector)
{
mSelector = selector;
}

/**
* 设置装载菜单内容的载体
* @param view
*/
public void setMenuConentView(GridView view)
{
mGridView = view;
}

/**
* 显示菜单
* @return 显示成功返回true, 失败返回false
*/
public boolean show()
{
if (hide())
{
return false;
}

final Context context = mContext;
final int length = mImgRes.length;
final int txtLength = mTexts.length;
Point point = new Point();
if (length != 0 && txtLength != 0)
{
Point p1 = getTextMaxDimenstion(mTexts);
Point p2 = getImageMaxDimension(mImgRes);
switch (mAlign)
{
case MenuItem.TEXT_BOTTOM:
case MenuItem.TEXT_TOP:
point.x = Math.max(p1.x, p2.x);
point.y = p1.y + p2.y;
break;
case MenuItem.TEXT_LEFT:
case MenuItem.TEXT_RIGHT:
point.x = p1.x + p2.x;
point.y = Math.max(p1.y, p2.y);
break;
}
}
else
{
if (length != 0)
{
point = getImageMaxDimension(mImgRes);
}
else if (txtLength != 0)
{
point = getTextMaxDimenstion(mTexts);
}
}

DisplayMetrics metrics = context.getResources().getDisplayMetrics();
int width = mWidth == 0 ? metrics.widthPixels : mWidth;
float density = metrics.density;
int imgWidth = point.x;
int height = point.y;
// 除去5dp的间距一行所能摆放图片的个数
int columns = (int) ((width - 5 * density) / (imgWidth + 5 * density));

int leng = length != 0 ? length : txtLength;
int rows = columns == 0 ? 0 : leng / columns;
if (columns * rows < leng)
{
rows += 1;
}

final LinearLayout layout = initLayout(context);
GridView gridView = mGridView;
if (null == gridView)
{
gridView = getContentView(context, columns);
}
else
{
setContentViewListener(gridView);
}

layout.addView(gridView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

// TODO 对高度进行修正
int h = 0;
if (mAlign == MenuItem.TEXT_LEFT || mAlign == MenuItem.TEXT_RIGHT)
{
h = (int) (height * rows + 5 * density);
}
else if (mAlign == MenuItem.TEXT_BOTTOM || mAlign == MenuItem.TEXT_TOP)
{
h = (int) ((height + 5 * density) * rows);
}
if (txtLength != 0)
{
h += 6 * density;
}

mPopup = new PopupWindow(context);
mPopup.setWidth(width);
mPopup.setHeight(mHeight == 0 ? h : mHeight);
mPopup.setContentView(layout);
mPopup.setFocusable(true);
mPopup.setOutsideTouchable(true);
mPopup.setTouchable(true);
// 设置背景为null,就不会出现黑色背景,按返回键PopupWindow就会消失
mPopup.setBackgroundDrawable(null);
if (mAnimStyle != 0)
{
mPopup.setAnimationStyle(mAnimStyle);
}
mPopup.showAtLocation(layout, Gravity.BOTTOM | Gravity.CENTER, 0, 0);
return true;
}

private LinearLayout initLayout(Context context)
{
LinearLayout layout = new LinearLayout(context);
layout.setOrientation(LinearLayout.VERTICAL);
layout.setFadingEdgeLength(0);
layout.setGravity(Gravity.CENTER);

layout.setOnTouchListener(new OnTouchListener()
{
@Override
public boolean onTouch(View v, MotionEvent event)
{
if (event.getAction() == MotionEvent.ACTION_DOWN)
{
hide();
}
return false;
}

});

return layout;
}

/**
* 初始数据,将数据加载到对应的View中
*/
private void initData()
{
MenuItem item = new MenuItem(mContext);
item.setTextAlign(mAlign);
item.setTextColor(mTxtColor);
item.setTextSize(mTxtColor);
int txtLength = mTexts.length;
int imgLength = mImgRes.length;
if (txtLength != 0 && imgLength != 0) // 图片和文字同时存在的情况
{
for (int i = 0; i < imgLength; i++)
{
MenuItem menuItem = new MenuItem(mContext, item);
menuItem.setImageRes(mImgRes[i]);
menuItem.setText(mTexts[i]);
mMenuItems.add(menuItem);
}

}
else
{
if (txtLength != 0) // 只有文字的情况
{
for (int i = 0; i < txtLength; i++)
{
MenuItem menuItem = new MenuItem(mContext, item);
menuItem.setText(mTexts[i]);
mMenuItems.add(menuItem);
}
}
else if (imgLength != 0) // 只有图片的情况
{
for (int i = 0; i < imgLength; i++)
{
MenuItem menuItem = new MenuItem(mContext, item);
menuItem.setImageRes(mImgRes[i]);
mMenuItems.add(menuItem);
}
}
}
}

/**
* 初始化菜单内容组件
* @param context
* @param columns 菜单的列数
* @return
*/
private GridView getContentView(Context context, int columns)
{
if (mMenuItems.isEmpty())
{
initData();
}

if (null != mGridView)
{
return mGridView;
}
GridView gridView = new GridView(context);
gridView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
gridView.setAdapter(new MenuAdapter(mMenuItems));
gridView.setVerticalSpacing(0);
gridView.setNumColumns(columns);
gridView.setGravity(Gravity.CENTER);
gridView.setVerticalScrollBarEnabled(false);
if (mBg != 0)
{
gridView.setBackgroundResource(mBg);
}
if (mSelector != -1)
{
gridView.setSelector(mSelector);
}
gridView.setHorizontalScrollBarEnabled(false);
setContentViewListener(gridView);
return gridView;
}

/**
* 注册事件
* @param gridView
*/
private void setContentViewListener(GridView gridView)
{
if (null == gridView.getOnItemClickListener())
{
gridView.setOnItemClickListener(new OnItemClickListener()
{
@Override
public void onItemClick(AdapterView parent, View view,
int position, long id)
{
if (null != mListener)
{
mListener.onMenuItemClick(parent, view, position);
}
hide();
}

});
}

gridView.setOnKeyListener(new OnKeyListener()
{
@Override
public boolean onKey(View v, int keyCode, KeyEvent event)
{
if (event.getAction() == KeyEvent.ACTION_DOWN)
{
switch (keyCode)
{
case KeyEvent.KEYCODE_BACK:
case KeyEvent.KEYCODE_MENU:
hide();
break;
}
}
return false;
}

});
}

/**
* 获取所有图片的最大的宽和高
* @param imgRes
* @return
*/
private Point getImageMaxDimension(int[] imgRes)
{
final Point point = new Point();
for (int i = 0, length = imgRes.length; i < length; i++)
{
Bitmap tmp = BitmapFactory.decodeResource(mContext.getResources(), imgRes[i]);
int width = tmp.getWidth();
int height = tmp.getHeight();
tmp.recycle();
tmp = null;
if (point.x < width)
{
point.x = width;
}
if (point.y < height)
{
point.y = height;
}
}

return point;
}

/**
* 计算文本的最大长度
* @param txts
* @return
*/
private Point getTextMaxDimenstion(String[] txts)
{
final Point point = new Point();
final Rect bounds = new Rect();
final Paint paint = new Paint();
float size = mTxtSize != -1 ? mTxtSize : mContext.getResources().getDisplayMetrics().density * 16;
paint.setTextSize(size);
paint.setColor(mTxtColor != -1 ? mTxtColor : Color.BLACK);
if (mIsOptimizeTxt) // 对文字长度进行优化
{
for (int i = 0, length = txts.length; i < length; i++)
{
String str = txts[i];
if (null == str)
{
str = "";
}
else if (str.length() > mMaxStrLength)
{
// 对字符串长度进行控制
str = new StringBuilder().append(str.substring(0, mMaxStrLength)).append("...").toString();
}

txts[i] = str;
paint.getTextBounds(str, 0, str.length(), bounds);
compareDimension(point, bounds.width(), bounds.height());
}
}
else // 对文字长度不做优化,此时要注意图片和文字同时存在时最终宽度的问题
{
for (int i = 0, length = txts.length; i < length; i++)
{
String str = txts[i];
if (null == str)
{
str = "";
}

txts[i] = str;
paint.getTextBounds(str, 0, str.length(), bounds);
compareDimension(point, bounds.width(), bounds.height());
}
}
return point;
}

/**
* 比较并改变最大尺寸
* @param point 保存最大尺寸的对象
* @param width 宽
* @param height 高
*/
private void compareDimension(Point point, int width, int height)
{
if (point.x < width)
{
point.x = width;
}

if (point.y < height)
{
point.y = height;
}
}

/**
* 隐藏菜单
* @return 隐藏成功返回true,失败返回false
*/
public boolean hide()
{
if (null != mPopup && mPopup.isShowing())
{
mPopup.dismiss();
mPopup = null;
if (null != mListener)
{
mListener.hideMenu();
}
return true;
}
return false;
}

public void dismiss()
{
mMenuItems.clear();
mGridView = null;
mTexts = new String[0];
mImgRes = new int[0];
mWidth = 0;
mHeight = 0;
}

/**
* 设置菜单项被选中监听器
* @param listener
*/
public void setOnMenuItemClickListener(OnMenuItemClickListener listener)
{
mListener = listener;
}

/**
* 菜单项目选中监听器
* @author maylian.mei
*
*/
public interface OnMenuItemClickListener
{
/**
* 菜单项被点击的会调用的方法
* @param parent
* @param view
* @param position
*/
public void onMenuItemClick(AdapterView parent, View view, int position);

/**
* 菜单隐藏会调用的方法
*/
public void hideMenu();
}
}

转载于:https://www.cnblogs.com/joey-home/archive/2012/07/02/2573844.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值