在制做一個軟件的時候要用到側滑菜單(SlidMenu),而且,現在這個應用在軟件開發中應用很多!雖然網上有好多說是實現了這個功能,csdn上資源下載那裡也有好多提供下載,但當我一個一個的測試了之後,只能感歎一句“坑爹啊!”都是由bug的,想想還是自己來實現吧!
實現上主要就是一個自定義的MySlidView,在這個MySlidView裡邊去加載兩個你要顯示的View(mMenuView, mSlidView),即一個是滑動之後,左側的mSlidView,另一個就是關閉mMenuView之後的mSlidView!
而菜單的打開與關閉,實際上就是操作上層的mSlidView的滑動,當需要打開菜單時,讓mSlidView向右邊滑動,如果要關閉menu,就再讓它滑回來,
主要代碼就是自定義的類:
/**
* @author Administrator
*
*/
public class MySlidView extends RelativeLayout {
private View mMenuView;
private View mSlidView;
private RelativeLayout bgShade;
private Context mContext;
private float mTouchSlop;
private Scroller mScroller; // 滑動控制
private VelocityTracker mVelocityTracker; // 用於判斷甩動手勢
private static final int SNAP_VELOCITY = 100; // 滑動速度閥值
private float mLastMotionX;
private float mLastMotionY;
private float mFirstMotionX;
private int menuWidth; //側邊菜單slidmenu的寬度
public int menuState; //菜單狀態
private boolean mIsBeingDragged = true; // 是否在滑動
public MySlidView(Context context) {
super(context);
init(context);
}
public MySlidView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public MySlidView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
/**
* @param context
* 初始化
*/
private void init(Context context) {
mContext = context;
mScroller = new Scroller(context);
menuState = ConstantQuantity.MENU_STATE_CLOSE;
mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
bgShade = new RelativeLayout(context);
}
/**
* @param menu
* @param slid
*/
public void addViews(View menu, View slid) {
setMenuView(menu);
setSlidView(slid);
}
/**
* @see Android.view.View#computeScroll()
*/
@Override
public void computeScroll() {
if (!mScroller.isFinished()) {
if (mScroller.computeScrollOffset()) {
int oldX = mSlidView.getScrollX();
int x = mScroller.getCurrX();
if (oldX != x) {
if (mSlidView != null) {
mSlidView.scrollTo(mScroller.getCurrX(), 0);
bgShade.scrollTo(x + 10, 0);//
}
}
invalidate();
}
}
}
@Override
public void scrollTo(int x, int y) {
super.scrollTo(x, y);
postInvalidate();
}
/**
* @see android.view.ViewGroup#onInterceptTouchEvent(android.view.MotionEvent)
* 攔截手勢,在處理觸屏操作之前先攔截下觸屏事件進行判斷之後的操作!
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
menuWidth = getMenuViewWidth();
int action = event.getAction();
float x = event.getX();
float y = event.getY();
switch (action) {
case MotionEvent.ACTION_DOWN:
mFirstMotionX = x;
mLastMotionX = x;
mLastMotionY = y;
mIsBeingDragged = false;
break;
case MotionEvent.ACTION_MOVE:
float deltaX = mLastMotionX - x;
float deltaY = mLastMotionY - y;
if (Math.abs(deltaX) > mTouchSlop
&& Math.abs(deltaX) > Math.abs(deltaY)) {
float oldScrollX = mSlidView.getScrollX();
if (oldScrollX <= 0) {
mIsBeingDragged = true;
mLastMotionX = x;
} else {
if (deltaX < 0) {
mIsBeingDragged = true;
mLastMotionX = x;
}
}
}
if (menuState == ConstantQuantity.MENU_STATE_OPEN) {
System.out.println(mFirstMotionX + " ; "
+ mSlidView.getScrollX());
if (mFirstMotionX >= 0
&& mFirstMotionX < Math.abs(mSlidView.getScrollX())) {
mIsBeingDragged = false;
}
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (menuState == ConstantQuantity.MENU_STATE_OPEN) {
if(mFirstMotionX >= menuWidth && mLastMotionX >= menuWidth){
openMenuView();
}
}
break;
}
return mIsBeingDragged;
}
/**
* @see android.view.View#onTouchEvent(android.view.MotionEvent)
* 手勢處理
* 這裡去處理觸屏操作
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
float x = event.getX();
float y = event.getY();
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
mVelocityTracker.addMovement(event);
}
switch (action) {
case MotionEvent.ACTION_DOWN:
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
mLastMotionX = x;
mLastMotionY = y;
System.out.println("mSlidView-scrollX-->" + mSlidView.getScrollX());
System.out.println("mMenuView-Width-->" + getMenuViewWidth());
if (mSlidView.getScrollX() == -getMenuViewWidth()
&& mLastMotionX < getMenuViewWidth()) {
// return false;
}
break;
case MotionEvent.ACTION_MOVE:
if (mIsBeingDragged) {
float delateX = mLastMotionX - x;
mLastMotionX = x;
if (!(mSlidView.getScrollX() < 0)) {
if (delateX > 0) {
break;
}
}
if ((mSlidView.getScrollX() <= 0)
&& (mSlidView.getScrollX() >= -(ConstantQuantity.screenWidth - ConstantQuantity.screenDensity * 50))) {
mSlidView.scrollBy((int) delateX, 0);
}
System.out.println("delateX--->" + delateX);
System.out.println("mSlidView.ScrollX--->"
+ mSlidView.getScrollX());
}
if (mSlidView.getScrollX() >= 0) {
return false;
}
if (mSlidView != null) {
bgShade.scrollTo(mSlidView.getScrollX() + 10, 0);
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
int velocityX = 0;
if (mVelocityTracker != null) {
mVelocityTracker.addMovement(event);
mVelocityTracker.computeCurrentVelocity(1000);
velocityX = (int) mVelocityTracker.getXVelocity();
}
//當離開屏幕時根據滑動的速度來判斷菜單是否打開或關閉
showVelocityMenuView(velocityX);
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
break;
}
return true;
}
/**
* @param view
* 設置側邊菜單布局
*/
public void setMenuView(View view) {
LayoutParams behindParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.MATCH_PARENT);
addView(view, behindParams);
mMenuView = view;
}
/**
* @param view
* 設置中間滑動布局 設置中間滑動布局的同時,增加一個背景布局,用來顯示側邊陰影!增加層級立體效果
*/
public void setSlidView(View view) {
LayoutParams bgShadeParams = new LayoutParams(
ConstantQuantity.screenWidth, ConstantQuantity.screenHeight);
bgShadeParams.addRule(RelativeLayout.CENTER_IN_PARENT);
bgShade.setLayoutParams(bgShadeParams);
LayoutParams bgParams = new LayoutParams(ConstantQuantity.screenWidth,
ConstantQuantity.screenHeight - 48);
bgParams.addRule(RelativeLayout.CENTER_IN_PARENT);
View bgShadeContent = new View(mContext);
bgShadeContent.setBackgroundResource(R.drawable.view_left_bg);
bgShade.removeAllViews();
bgShade.addView(bgShadeContent, bgParams);
if (getChildCount() > 1) {
removeViewAt(1);
removeViewAt(1);
}
addView(bgShade, bgParams);
LayoutParams aboveParams = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
addView(view, aboveParams);
mSlidView = view;
mSlidView.bringToFront();
System.out.println(getChildCount());
}
/**
* @return 獲得菜單的寬度
*/
private int getMenuViewWidth() {
if (mMenuView == null) {
return 0;
}
return mMenuView.getWidth();
}
/**
* @param velocity
* 判斷菜單的打開或關閉
*/
private void showVelocityMenuView(int velocity) {
if (velocity > 0) {
if (velocity > SNAP_VELOCITY) {
smoothScrollTo(-(menuWidth + mSlidView.getScrollX()));
setMenuState();
} else {
if (mSlidView.getScrollX() > -ConstantQuantity.screenWidth / 2) {
smoothScrollTo(-mSlidView.getScrollX());
} else {
smoothScrollTo(-(menuWidth + mSlidView.getScrollX()));
setMenuState();
}
}
}
if (velocity < 0) {
if (velocity < -SNAP_VELOCITY) {
smoothScrollTo(-mSlidView.getScrollX());
setMenuState();
} else {
if (mSlidView.getScrollX() > -ConstantQuantity.screenWidth / 2) {
smoothScrollTo(-mSlidView.getScrollX());
} else {
smoothScrollTo(-(menuWidth + mSlidView.getScrollX()));
setMenuState();
}
}
}
if (velocity == 0) {
if (mSlidView.getScrollX() > -(ConstantQuantity.screenWidth - ConstantQuantity.screenDensity * 50) / 2) {
smoothScrollTo(-mSlidView.getScrollX());
} else {
smoothScrollTo(-(menuWidth + mSlidView.getScrollX()));
setMenuState();
}
}
}
/**
* 去打開或者關閉菜單界面
*/
public void openMenuView() {
menuWidth = getMenuViewWidth();
if (mSlidView.getScrollX() == 0) {
// mMenuView.setVisibility(View.VISIBLE);
smoothScrollTo(-menuWidth);
setMenuState();
} else if (mSlidView.getScrollX() == -menuWidth) {
smoothScrollTo(menuWidth);
setMenuState();
}
}
/**
* 真正的實現打開與關閉的滑動效果
* @param distanceX
*/
private void smoothScrollTo(int distanceX) {
mScroller.startScroll(mSlidView.getScrollX(), 0,
distanceX, 0, ConstantQuantity.DURATION_TIME);
invalidate();
}
/**
* 設置菜單打開或關閉狀態
*/
private void setMenuState() {
if (menuState == ConstantQuantity.MENU_STATE_CLOSE) {
menuState = ConstantQuantity.MENU_STATE_OPEN;
// mSlidView.setEnabled(false);
System.out.println("菜單將打開");
} else {
menuState = ConstantQuantity.MENU_STATE_CLOSE;
// mSlidView.setEnabled(true);
System.out.println("菜單將關閉");
}
}
}
本文DEMO源碼下載
------------------------------------------分割線------------------------------------------
免費下載地址在 http://linux.linuxidc.com/
用戶名與密碼都是www.linuxidc.com
具體下載目錄在 /2015年資料/2月/21日/Android自定義側滑菜單slidmenu/
下載方法見 http://www.linuxidc.com/Linux/2013-07/87684.htm
------------------------------------------分割線------------------------------------------
更多Android相關信息見Android 專題頁面 http://www.linuxidc.com/topicnews.aspx?tid=11