首页 > 代码库 > Android侧滑菜单完整详细示例(精装版)

Android侧滑菜单完整详细示例(精装版)

MainActivity如下:
package cn.patience7;

import android.os.AsyncTask;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnPreDrawListener;
import android.widget.RelativeLayout;
import android.app.Activity;
import android.content.Context;

/**
 * Demo描述: 
 * 滑动菜单SlidingMenu完整详细示例
 * 
 * 布局文件:
 * 采用相对布局,两个界面是重叠在一起的,分别为aboveView和belowView.
 * 
 * 实现原理:
 * 对aboveView的Touch事件进行监听
 * 即mBboveView.setOnTouchListener(new TouchListenerImpl())
 * 在TouchListenerImpl中:
 * 1 ACTION_UP时将aboveView弹回到屏幕的左右两侧
 * 2 除ACTION_UP之外的Action交给手势GestureDetector处理
 * 
 * 所以通过aboveView的移动来遮掩或者显示belowView,从而达到 侧滑菜单的效果
 * 
 * 
 * 备注说明:
 * 该Demo与前面两个侧滑菜单实现原理是差不多但在代码实现上使用了GestureDetector
 */
public class MainActivity extends Activity {
	private View mAboveView;
	private View mBelowView;
	private float scrollX = 0;
	private Context mContext;
	private int screenWidth = 0;
	private boolean isMeasured = false;
	private int MAX_SCROLL_DISTANCE = 0;
	private GestureDetector mGestureDetector;
	private GestureListenerImpl mGestureListenerImpl;
	private SlowlyMoveAsyncTask mSlowlyMoveAsyncTask;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		initView();
	}

	private void initView() {
		mContext = this;
		mGestureListenerImpl = new GestureListenerImpl();
		mGestureDetector = new GestureDetector(mContext, mGestureListenerImpl);
		mGestureDetector.setIsLongpressEnabled(false);
		mAboveView = findViewById(R.id.aboveLinearLayout);
		mAboveView.setOnTouchListener(new TouchListenerImpl());
		mBelowView = findViewById(R.id.belowLinearLayout);
		initData();
	}

	/**
	 * 1 将aboveView的宽度设置为屏幕的宽度,从而完全遮掩belowView
	 * 2 MAX_SCROLL_DISTANCE为aboveView向屏幕左侧的最大滑动距离
	 */
	private void initData() {
		ViewTreeObserver viewTreeObserver = mAboveView.getViewTreeObserver();
		viewTreeObserver.addOnPreDrawListener(new OnPreDrawListener() {
			@Override
			public boolean onPreDraw() {
				if (!isMeasured) {
					screenWidth = getWindowManager().getDefaultDisplay().getWidth();
					RelativeLayout.LayoutParams aboveViewLayoutParams
					=(RelativeLayout.LayoutParams) mAboveView.getLayoutParams();
					aboveViewLayoutParams.width = screenWidth;
					mAboveView.setLayoutParams(aboveViewLayoutParams);
					MAX_SCROLL_DISTANCE = mBelowView.getWidth();
					isMeasured = true;
				}
				return true;
			}
		});
	}

	private class TouchListenerImpl implements OnTouchListener {
		@Override
		public boolean onTouch(View v, MotionEvent event) {
			if (event.getAction() == MotionEvent.ACTION_UP) {
				RelativeLayout.LayoutParams aboveViewLayoutParams
				=(RelativeLayout.LayoutParams) mAboveView.getLayoutParams();
				if (aboveViewLayoutParams.leftMargin > (-screenWidth / 2)) {
					// 手指往左滑时,未及屏幕一半时抬起.归位
					mSlowlyMoveAsyncTask = new SlowlyMoveAsyncTask();
					mSlowlyMoveAsyncTask.execute(20);
				} else {
					// 手指往左滑时,超过屏幕一半时抬起.归位
					mSlowlyMoveAsyncTask = new SlowlyMoveAsyncTask();
					mSlowlyMoveAsyncTask.execute(-20);
				}
			}
			return mGestureDetector.onTouchEvent(event);
		}
	}

	private class GestureListenerImpl implements GestureDetector.OnGestureListener {
		@Override
		public boolean onDown(MotionEvent arg0) {
			return true;
		}

		@Override
		public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2,float arg3) {
			return false;
		}

		@Override
		public void onLongPress(MotionEvent arg0) {
		}

		@Override
		public boolean onScroll(MotionEvent arg0, MotionEvent arg1,float distanceX, float distanceY) {
			scrollX = scrollX + distanceX;
			RelativeLayout.LayoutParams aboveViewLayoutParams
			=(RelativeLayout.LayoutParams) mAboveView.getLayoutParams();
			aboveViewLayoutParams.leftMargin = (int) (aboveViewLayoutParams.leftMargin - scrollX);
			// 手指往右边滑动的极限,防止越界
			if (aboveViewLayoutParams.leftMargin >= 0) {
				aboveViewLayoutParams.leftMargin = 0;
			}
			// 手指往左边滑动的极限,防止越界
			if (-aboveViewLayoutParams.leftMargin >= MAX_SCROLL_DISTANCE) {
				aboveViewLayoutParams.leftMargin = -MAX_SCROLL_DISTANCE;
			}
			mAboveView.setLayoutParams(aboveViewLayoutParams);
			return false;
		}

		@Override
		public void onShowPress(MotionEvent motionEvent) {

		}

		@Override
		public boolean onSingleTapUp(MotionEvent motionEvent) {
			return false;
		}
	}

	// 以下为异步任务,负责处理手指抬起时布局向屏幕左右两侧弹回
	private class SlowlyMoveAsyncTask extends AsyncTask<Integer, Integer, Void> {
		@Override
		protected Void doInBackground(Integer... params) {
			RelativeLayout.LayoutParams aboveViewLayoutParams
			= (RelativeLayout.LayoutParams) mAboveView.getLayoutParams();
			int leftMargin = aboveViewLayoutParams.leftMargin;
			// 需要移动的次数
			int move_times = 0;
			// 总共需要弹回的距离
			int all_move_distance = 0;
			// 每次弹回的距离
			int every_move_distance = Math.abs(params[0]);

			// 往屏幕右边移动
			if (params[0] > 0) {
				all_move_distance = Math.abs(leftMargin);
				// 往屏幕左边移动
			} else {
				all_move_distance = MAX_SCROLL_DISTANCE - Math.abs(leftMargin);
			}

			// 计算需要移动的次数
			if (all_move_distance % every_move_distance == 0) {
				move_times = all_move_distance / every_move_distance;
			} else {
				move_times = all_move_distance / every_move_distance + 1;
			}

			System.out.println("--> all_move_distance=" + all_move_distance);
			System.out.println("--> every_move_distance=" + every_move_distance);
			System.out.println("--> move_times=" + move_times);

			// 移动的过程
			for (int i = 0; i < move_times; i++) {
				publishProgress(params[0]);
				try {
					Thread.sleep(20);
				} catch (Exception e) {
				}
			}
			return null;
		}

		@Override
		protected void onProgressUpdate(Integer... values) {
			super.onProgressUpdate(values);
			int every_move_distance = values[0];
			RelativeLayout.LayoutParams aboveViewLayoutParams
			= (RelativeLayout.LayoutParams) mAboveView.getLayoutParams();
			if (every_move_distance > 0) {
				if (aboveViewLayoutParams.leftMargin < 0) {
					aboveViewLayoutParams.leftMargin += every_move_distance;
					// 处理最后一次滑动后可能越界的情况
					if (aboveViewLayoutParams.leftMargin > 0) {
						aboveViewLayoutParams.leftMargin = 0;
					}
					mAboveView.setLayoutParams(aboveViewLayoutParams);
				}
			} else {
				if (aboveViewLayoutParams.leftMargin > (-MAX_SCROLL_DISTANCE)) {
					aboveViewLayoutParams.leftMargin -= (-every_move_distance);
					// 处理最后一次滑动后可能越界的情况
					if (aboveViewLayoutParams.leftMargin < -MAX_SCROLL_DISTANCE) {
						aboveViewLayoutParams.leftMargin = -MAX_SCROLL_DISTANCE;
					}
					mAboveView.setLayoutParams(aboveViewLayoutParams);
				}
			}
		}
	}
}

main.xml如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <LinearLayout
        android:id="@+id/belowLinearLayout"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_marginLeft="50dip" >

        <ImageView
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:scaleType="fitXY"
            android:src=http://www.mamicode.com/"@drawable/a" />>

Android侧滑菜单完整详细示例(精装版)