個人感覺系統的菜單不是很好看,所以每次在應用添加菜單的時候總是自己用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 [email protected]
- *
- */
- 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();
- }
- }