Android UI开发第二十七篇——实现左右划出菜单

       年前就想写左右滑动菜单,苦于没有时间,一直拖到现在,这篇代码实现参考了网上流行的SlidingMenu,使用的FrameLayout布局,不是扩展的HorizontalScrollView。

       程序中自定义了菜单view:SlidingView,继承自ViewGroup,使用FrameLayout布局。重写了onInterceptTouchEvent(MotionEvent ev)方法实现ontouch的分发拦截,重写了onTouchEvent(MotionEvent ev)方法,实现左右滑动。

 

public class SlidingView extends ViewGroup {

	private FrameLayout mContainer;
	private Scroller mScroller;
	private VelocityTracker mVelocityTracker;
	private int mTouchSlop;
	private float mLastMotionX;
	private float mLastMotionY;
	private static final int SNAP_VELOCITY = 1000;
	private View mLeftView;
	private View mRightView;

	public SlidingView(Context context) {
		super(context);
		init();
	}

	public SlidingView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}

	public SlidingView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init();
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		mContainer.measure(widthMeasureSpec, heightMeasureSpec);
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		final int width = r - l;
		final int height = b - t;
		mContainer.layout(0, 0, width, height);
	}

	private void init() {
		mContainer = new FrameLayout(getContext());
		mContainer.setBackgroundColor(0xff000000);
		mScroller = new Scroller(getContext());
		mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
		super.addView(mContainer);
	}

	public void setView(View v) {
		if (mContainer.getChildCount() > 0) {
			mContainer.removeAllViews();
		}
		mContainer.addView(v);
	}

	@Override
	public void scrollTo(int x, int y) {
		super.scrollTo(x, y);
		postInvalidate();
	}

	@Override
	public void computeScroll() {
		if (!mScroller.isFinished()) {
			if (mScroller.computeScrollOffset()) {
				int oldX = getScrollX();
				int oldY = getScrollY();
				int x = mScroller.getCurrX();
				int y = mScroller.getCurrY();
				if (oldX != x || oldY != y) {
					scrollTo(x, y);
				}
				// Keep on drawing until the animation has finished.
				invalidate();
			} else {
				clearChildrenCache();
			}
		} else {
			clearChildrenCache();
		}
	}

	private boolean mIsBeingDragged;

	
    /**
     * 实现了ontouch的分发拦截
     */
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {

		final int action = ev.getAction();
		final float x = ev.getX();
		final float y = ev.getY();

		switch (action) {
		case MotionEvent.ACTION_DOWN:
			mLastMotionX = x;
			mLastMotionY = y;
			mIsBeingDragged = false;
			break;

		case MotionEvent.ACTION_MOVE:
			final float dx = x - mLastMotionX;
			final float xDiff = Math.abs(dx);
			final float yDiff = Math.abs(y - mLastMotionY);
			if (xDiff > mTouchSlop && xDiff > yDiff) {
				mIsBeingDragged = true;
				mLastMotionX = x;
			}
			Log.d("Sliding", "SlidingView_Touch:"+x+"|"+y);
			Log.d("Sliding", "SlidingView_Touch:"+xDiff+"|"+mTouchSlop+"|"+yDiff+"|"+mLastMotionY);
			Log.d("Sliding", "SlidingView_Touch:"+mIsBeingDragged);
			break;

		}
		return mIsBeingDragged;
	}

	@Override
	public boolean onTouchEvent(MotionEvent ev) {

		if (mVelocityTracker == null) {
			mVelocityTracker = VelocityTracker.obtain();
		}
		mVelocityTracker.addMovement(ev);

		final int action = ev.getAction();
		final float x = ev.getX();
		final float y = ev.getY();

		switch (action) {
		case MotionEvent.ACTION_DOWN:
			if (!mScroller.isFinished()) {
				mScroller.abortAnimation();
			}
			mLastMotionX = x;
			mLastMotionY = y;
			if (getScrollX() == -getLeftMenuWidth()
					&& mLastMotionX < getLeftMenuWidth()) {
				return false;
			}

			if (getScrollX() == getRightMenuWidth()
					&& mLastMotionX > getLeftMenuWidth()) {
				return false;
			}

			break;
		case MotionEvent.ACTION_MOVE:
			if (mIsBeingDragged) {
				enableChildrenCache();
				final float deltaX = mLastMotionX - x;
				mLastMotionX = x;
				float oldScrollX = getScrollX();
				float scrollX = oldScrollX + deltaX;

				if (deltaX < 0 && oldScrollX < 0) { // left view
					final float leftBound = 0;
					final float rightBound = -getLeftMenuWidth();
					if (scrollX > leftBound) {
						scrollX = leftBound;
					} else if (scrollX < rightBound) {
						scrollX = rightBound;
					}
				} else if (deltaX > 0 && oldScrollX > 0) { // right view
					final float rightBound = getRightMenuWidth();
					final float leftBound = 0;
					if (scrollX < leftBound) {
						scrollX = leftBound;
					} else if (scrollX > rightBound) {
						scrollX = rightBound;
					}
				}

				scrollTo((int) scrollX, getScrollY());
				if (scrollX > 0) {
					mLeftView.setVisibility(View.GONE);
					mLeftView.clearFocus();
					mRightView.setVisibility(View.VISIBLE);
					mRightView.requestFocus();
				} else {
					mLeftView.setVisibility(View.VISIBLE);
					mLeftView.requestFocus();
					mRightView.setVisibility(View.GONE);
					mRightView.clearFocus();
				}
			}
			break;
		case MotionEvent.ACTION_CANCEL:
		case MotionEvent.ACTION_UP:
			if (mIsBeingDragged) {
				final VelocityTracker velocityTracker = mVelocityTracker;
				velocityTracker.computeCurrentVelocity(1000);
				int velocityX = (int) velocityTracker.getXVelocity();
				velocityX = 0;
				int oldScrollX = getScrollX();
				int dx = 0;
				if (oldScrollX < 0) {
					// 左边
					if (oldScrollX < -getLeftMenuWidth() / 2
							|| velocityX > SNAP_VELOCITY) {
						// 左侧页面划出
						dx = -getLeftMenuWidth() - oldScrollX;

					} else if (oldScrollX >= -getLeftMenuWidth() / 2
							|| velocityX < -SNAP_VELOCITY) {
						// 左侧页面关闭
						dx = -oldScrollX;
					}
				} else {
					// 右边
					if (oldScrollX > getRightMenuWidth() / 2
							|| velocityX < -SNAP_VELOCITY) {
						// 右侧页面划出
						dx = getRightMenuWidth() - oldScrollX;

					} else if (oldScrollX <= getRightMenuWidth() / 2
							|| velocityX > SNAP_VELOCITY) {
						// 右侧页面关闭
						dx = -oldScrollX;
					}
				}

				smoothScrollTo(dx);
				clearChildrenCache();

			}

			break;

		}
		if (mVelocityTracker != null) {
			mVelocityTracker.recycle();
			mVelocityTracker = null;
		}
		return true;
	}

	private int getLeftMenuWidth() {
		if (mLeftView == null) {
			return 0;
		}
		return mLeftView.getWidth();
	}

	private int getRightMenuWidth() {
		if (mRightView == null) {
			return 0;
		}
		return mRightView.getWidth();
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
	}

	public View getRightView() {
		return mRightView;
	}

	public void setRightView(View mRightView) {
		this.mRightView = mRightView;
	}

	public View getMenuView() {
		return mLeftView;
	}

	public void setLeftView(View mLeftView) {
		this.mLeftView = mLeftView;
	}

	void toggle() {
		int menuWidth = mLeftView.getWidth();
		int oldScrollX = getScrollX();
		if (oldScrollX == 0) {
			smoothScrollTo(-menuWidth);
		} else if (oldScrollX == -menuWidth) {
			smoothScrollTo(menuWidth);
		}
	}

	/**
	 * 打开(关闭)左侧页面
	 */
	public void showLeftView() {
		mLeftView.setVisibility(View.VISIBLE);
		mRightView.setVisibility(View.GONE);
		int menuWidth = mLeftView.getWidth();
		int oldScrollX = getScrollX();
		if (oldScrollX == 0) {
			smoothScrollTo(-menuWidth);
		} else if (oldScrollX == -menuWidth) {
			smoothScrollTo(menuWidth);
		}
	}

	/**
	 * 打开(关闭)右侧页面
	 */
	public void showRightView() {
		mLeftView.setVisibility(View.GONE);
		mLeftView.clearFocus();
		mRightView.setVisibility(View.VISIBLE);
		mRightView.requestFocus();
		int menuWidth = mRightView.getWidth();
		int oldScrollX = getScrollX();
		if (oldScrollX == 0) {
			smoothScrollTo(menuWidth);
		} else if (oldScrollX == menuWidth) {
			smoothScrollTo(-menuWidth);
		}
	}

	/**
	 * 显示中间页面
	 */
	public void showCenterView() {
		int menuWidth = mRightView.getWidth();
		int oldScrollX = getScrollX();
		if (oldScrollX == menuWidth) {
			showRightView();
		} else if (oldScrollX == -menuWidth) {
			showLeftView();
		}
	}

	void smoothScrollTo(int dx) {
		int duration = 500;
		int oldScrollX = getScrollX();
		mScroller.startScroll(oldScrollX, getScrollY(), dx, getScrollY(),
				duration);
		invalidate();
	}

	void enableChildrenCache() {
		final int count = getChildCount();
		for (int i = 0; i < count; i++) {
			final View layout = (View) getChildAt(i);
			layout.setDrawingCacheEnabled(true);
		}
	}

	void clearChildrenCache() {
		final int count = getChildCount();
		for (int i = 0; i < count; i++) {
			final View layout = (View) getChildAt(i);
			layout.setDrawingCacheEnabled(false);
		}
	}

}


SlidingMenu对SlidingView做了进一步封装处理:

 

 

public class SlidingMenu extends RelativeLayout {

	private SlidingView mSlidingView;
	private View mLeftView;
	private View mRightView;
	// menu width
	private int alignScreenWidth;

	public SlidingMenu(Context context) {
		super(context);
	}

	public SlidingMenu(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public SlidingMenu(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	public void setAlignScreenWidth(int alignScreenWidth) {
		this.alignScreenWidth = alignScreenWidth;
	}

	public void setLeftView(View view) {
		LayoutParams behindParams = new LayoutParams(alignScreenWidth,
				LayoutParams.MATCH_PARENT);
		addView(view, behindParams);
		mLeftView = view;
	}

	public void setRightView(View view) {
		LayoutParams behindParams = new LayoutParams(alignScreenWidth,
				LayoutParams.MATCH_PARENT);
		behindParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
		addView(view, behindParams);
		mRightView = view;
	}

	public void setCenterView(View view) {
		LayoutParams aboveParams = new LayoutParams(LayoutParams.MATCH_PARENT,
				LayoutParams.MATCH_PARENT);
		mSlidingView = new SlidingView(getContext());
		addView(mSlidingView, aboveParams);
		mSlidingView.setView(view);
		mSlidingView.invalidate();
		mSlidingView.setLeftView(mLeftView);
		mSlidingView.setRightView(mRightView);
	}

	public void showLeftView() {
		mSlidingView.showLeftView();
	}

	public void showRightView() {
		mSlidingView.showRightView();
	}

	public void showCenterView() {
		mSlidingView.showCenterView();
	}

}

 

SlidingMenu的使用代码

 

public class SlidingActivity extends Activity implements OnClickListener{
	SlidingMenu mSlidingMenu;

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


		DisplayMetrics dm = new DisplayMetrics();
		getWindowManager().getDefaultDisplay().getMetrics(dm);

		mSlidingMenu = (SlidingMenu) findViewById(R.id.slidingMenu);
		mSlidingMenu.setAlignScreenWidth((dm.widthPixels / 5) * 2);
		
		View leftView=getLayoutInflater().inflate(R.layout.left_menu, null);
		View rightView=getLayoutInflater().inflate(R.layout.right_menu, null);
		View centerView=getLayoutInflater().inflate(R.layout.center, null);
		
		mSlidingMenu.setLeftView(leftView);
		mSlidingMenu.setRightView(rightView);
		mSlidingMenu.setCenterView(centerView);
        
		Button showLeftMenu=(Button)centerView.findViewById(R.id.center_left_btn);
		showLeftMenu.setOnClickListener(this);
		Button showRightMenu=(Button)centerView.findViewById(R.id.center_right_btn);
		showRightMenu.setOnClickListener(this);
	}

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		switch (v.getId()) {
		case R.id.center_left_btn:
			mSlidingMenu.showLeftView();
			break;
        case R.id.center_right_btn:
        	mSlidingMenu.showRightView();
			break;
		default:
			break;
		}
	}
	
}

                                

 

代码:http://download.csdn.net/detail/xyz_lmn/5109965

 

 

/**
* @author 张兴业
*  iOS入门群:83702688
*  android开发进阶群:241395671
*  我的新浪微博:@张兴业TBOW
*  我的邮箱:xy-zhang#163.com#->@)
*/



posted @ 2013-08-09 10:19  张兴业  阅读(1146)  评论(1编辑  收藏  举报