Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android--側滑菜單應用的實現

Android--側滑菜單應用的實現

編輯:關於Android編程

側滑菜單應用現在非常多,而且實現方式也多種多樣。通過在網上的多方查找,我找到郭霖少俠的這篇文章:http://blog.csdn.net/guolin_blog/article/details/8744400,研究之後收獲頗多。同時記得以前看過一篇講Scroller實現滑屏的文章:http://www.cnblogs.com/wanqieddy/archive/2012/05/05/2484534.html。

那為何不用scroller來實現以下側滑菜單?閒的蛋疼,那就試試吧,在這裡先感謝以上兩篇博文給我的啟發。

原理:通過scrollBy和scrollTo來移動右側的content布局,實際上整個過程中,左側的menu布局未發生滾動,這樣出來的效果是右側content布局覆蓋住左側menu布局。當然scroll的方式也可以實現menu和content同時平移的效果,這個只需要在布局文件上動動手腳就行了,在此先按下不表。

下面是本文的實現效果

\

activity_main.xml文件:

首先放入menu布局,因為是RelativeLayout布局因此先放入的會被覆蓋,然後是滑動布局,在滑動布局中加入content布局,因為content布局會隨滑動布局一起移動。



    
    
    
        
        
    
    

menu.xml和conent_diary.xml這兩個布局文件就不用講了,大家跟著感覺走,想放什麼放什麼吧。

SlideLayout.java文件:大部分代碼都很簡單,看注釋就能懂。這裡只說幾個要點,我也是調試過之後才明白的:

1. getScrollX()得到的是當前View的最左邊所在的X坐標。程序初始化後此值為0,View向右滑動後,相當於屏幕坐標系向負方向移動了一段,因此此時此值為負數;反之則相反。

2. Scroller實際上只是保存和提供自動滑動時所需的數值,真正完成滑動的還是scrollTo和scrollBy兩個函數。

3. 我寫的SlideLayout繼承自RelativeLayout,其實也可以繼承自ViewGroup,但是就需要自己重寫onMeasure和onLayout函數,來布局子控件。這個實現中沒有特殊的布局要求,所以用RelatiLayout就可以啦。

package com.noter.layout;

import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.RelativeLayout;
import android.widget.Scroller;

public class SlideLayout extends RelativeLayout {
	private static String TAG = "SlideMenuLayout";
	
	private Context mContext;
	private Scroller mScroller;    //Android 提供的滑動輔助類
	private int mTouchSlop = 0 ;    //在被判定為滾動之前用戶手指可以移動的最大值
	private VelocityTracker mVelocityTracker;    //用於計算手指滑動的速度
	public static final int SNAP_VELOCITY = 200;    //滾動顯示和隱藏左側布局時,手指滑動需要達到的速度:每秒200個像素點
	private int mMaxScrollX = 0;    //最大滾動距離,等於menu的寬度
	public void setMaxScrollX(int maxScrollX) {
		this.mMaxScrollX = maxScrollX;
	}

	private float mDownX;    //一次按下抬起的動作中,按下時的X坐標,用於和抬起時的X比較,判斷移動距離。少於mTouchSlop則判定為原地點擊
	private float mLastX;    //記錄滑動過程中的X坐標
	
	private boolean isMenuOpen = false;    //菜單界面是否被打開,只有完全打開才為true
	public boolean isMenuOpen() {
		return isMenuOpen;
	}

	private View mContent;
	
	public SlideLayout(Context context, AttributeSet attrs) {
		super(context, attrs);
		mContext = context;
		init();
	}
	
	private void init() {
		Log.v(TAG, "init start");
		mScroller = new Scroller(mContext);
		mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
	}

	@Override
	public void computeScroll() {
		if (mScroller.computeScrollOffset()) {
			scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
			postInvalidate();
		}
	}
	
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		super.onLayout(changed, l, t, r, b);
		if(changed){
			mContent = getChildAt(0);
		}
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		createVelocityTracker(event);
		int curScrollX = getScrollX();
		// 檢查觸摸點是否在滑動布局(內容content)中,如果不是則返回false,即本View不處理該事件
		if (mContent != null) {
			Rect rect = new Rect();
			mContent.getHitRect(rect);
			if (!rect.contains((int)event.getX() + curScrollX, (int)event.getY())) {
				return false;
			}
		}

		float x = event.getX();    //取得本次event的X坐標
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			mDownX = x;
			mLastX = x;
			break;
		case MotionEvent.ACTION_MOVE:
			int deltaX = (int)(mLastX - x);
			if((curScrollX + deltaX) < -mMaxScrollX) {
				deltaX = -mMaxScrollX - curScrollX;
			}
			if((curScrollX + deltaX) > 0){
				deltaX = -curScrollX;
			}
			
			if (deltaX != 0) {
				scrollBy(deltaX, 0);
			}
			mLastX = x;
			break;
		case MotionEvent.ACTION_UP:
			int velocityX = getScrollVelocity();
			int offsetX = (int) (x - mDownX);
			
			//成立表明移動距離已經達到被判斷為滑動的最低標准
			//不成立表明不被判斷為滑動,則認為是單一的點擊,則關閉menu
			if(Math.abs(offsetX) >= mTouchSlop) {
				
				//成立表明手指移動速度達標,則進行自動滑動;
				//不成立表明速度不達標,但仍然需要判斷當前SlideLayout的位置
				//如果已經超過一半,則繼續自動完成剩下的滑動,如果沒有超過一半,則反向滑動
				if(Math.abs(velocityX) >= SNAP_VELOCITY) {
					if(velocityX > 0){
						openMenu();
					} else if(velocityX < 0) {
						closeMenu();
					}
				} else {
					if (curScrollX >= -mMaxScrollX / 2) {
						closeMenu();
					} else {
						openMenu();
					}
				}
			} else {
				closeMenu();
			}

			recycleVelocityTracker();
			break;
		}
		return true;
	}
	
	private void createVelocityTracker(MotionEvent event) {
		if (mVelocityTracker == null) {
			mVelocityTracker = VelocityTracker.obtain();
		}
		mVelocityTracker.addMovement(event);
	}
	
	//獲取手指在View上的滑動速度,以每秒鐘移動了多少像素值為單位
	private int getScrollVelocity() {
		mVelocityTracker.computeCurrentVelocity(1000);
		return (int) mVelocityTracker.getXVelocity();
	}
	
	private void recycleVelocityTracker() {
		mVelocityTracker.recycle();
		mVelocityTracker = null;
	}
	
	//打開Menu布局
	public void openMenu() {
		int curScrollX = getScrollX();
		scrollToDestination(-mMaxScrollX - curScrollX);
		isMenuOpen = true;
	}
	
	//關閉Menu布局
	public void closeMenu() {
		int curScrollX = getScrollX();
		scrollToDestination(-curScrollX);
		isMenuOpen = false;
	}
	
	private void scrollToDestination(int x) {
		if (x == 0)
			return;

		mScroller.startScroll(getScrollX(), 0, x, 0, Math.abs(x));
		invalidate();
	}
}


最後是代碼下載,Enjoy it!

側滑菜單實例

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved