Android 自定义左右菜单

自定义一个Menu。

由3个组成基本视图。

        private FrameLayout middleMenu;
private FrameLayout leftMenu;
private FrameLayout rightMenu; 



再自定义滑动手势。

public boolean dispatchTouchEvent(MotionEvent ev)。




一。静态布局。

public class MainUI extends RelativeLayout {

	private Context context;
	private FrameLayout middleMenu;
	private FrameLayout leftMenu;
	private FrameLayout rightMenu;
	private Scroller mScroller;
	public static final int ID = 0xaabbcc;

	public MainUI(Context context) {
		super(context);
		initView(context);
	}

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

	private void initView(Context context) {

		//初始化 布局。
		this.context = context;

		mScroller = new Scroller(context,new DecelerateInterpolator());
		leftMenu = new FrameLayout(context);
		rightMenu = new FrameLayout(context);
		middleMenu = new FrameLayout(context);
		middleMenu.setBackgroundColor(0xff547093);
		rightMenu.setBackgroundColor(0xff673ab7);
		leftMenu.setBackgroundColor(0xffe51c23);
		rightMenu.setId(ID);
		addView(leftMenu);
		addView(middleMenu);
		addView(rightMenu);
		
	

	}

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

		// 三个布局的高宽。
		
		middleMenu.measure(widthMeasureSpec, heightMeasureSpec);// 中间布局是屏幕的高宽。
		// 左右菜单布局是0。8宽的屏幕, 高也是屏幕的高。
		int realWith = MeasureSpec.getSize(widthMeasureSpec); // 获取屏幕宽
		int tempWidth = MeasureSpec.makeMeasureSpec((int) (realWith * 0.8),
				MeasureSpec.EXACTLY);  // 屏幕宽*0.8
		leftMenu.measure(tempWidth, heightMeasureSpec);
		rightMenu.measure(tempWidth, heightMeasureSpec);
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		super.onLayout(changed, l, t, r, b);
		
		// 三个布局的定位。   l=left t=top r=right b=button  都是屏幕的上下左右。

		middleMenu.layout(l, t, r, b);
		leftMenu.layout(l - leftMenu.getMeasuredWidth(), t, l, b);
		rightMenu.layout(r, t, r + rightMenu.getMeasuredWidth(), b);
	}



二。滑动操作。


	private boolean isTestCompete;   //是否有屏幕操作   默认false
	private boolean isleftrightEvent;   //是否是左右滑动事件  默认false

	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {

		if (!isTestCompete) {
			getEventType(ev); // 判断滑动的具体方向
			return true;
		}
		if (isleftrightEvent) {
			// 如果是左右滑动,屏幕会做如下滚动(scroll)
			switch (ev.getActionMasked()) {
			case MotionEvent.ACTION_MOVE:
				super.dispatchTouchEvent(ev);
				
				int curScrollX = getScrollX(); // 屏幕滑动的距离
				int dis_x = (int) ev.getX() - point.x;  // 手滑动的距离
				int expectX = -dis_x + curScrollX;
				int finalX = 0;
				if (expectX < 0) {
					finalX = Math.max(expectX, -leftMenu.getMeasuredWidth());

				} else {
					finalX = Math.min(expectX, rightMenu.getMeasuredWidth());
				}
				scrollTo(finalX, 0);
				point.x = (int) ev.getX();
				break;

			case MotionEvent.ACTION_UP:
			case MotionEvent.ACTION_CANCEL:
				 curScrollX = getScrollX();
				 super.dispatchTouchEvent(ev);
				 
				 
				 // 如果滑动超过左右菜单的 一半,则自动滑出左右菜单,否则退回。
				 if (Math.abs(curScrollX)>(leftMenu.getMeasuredWidth()/2)) {
					if (curScrollX<0) {
						mScroller.startScroll(curScrollX, 0, -leftMenu.getMeasuredWidth()-curScrollX, 0);
					}else {
						mScroller.startScroll(curScrollX, 0, leftMenu.getMeasuredWidth()-curScrollX, 0);
					}
				}else {
					mScroller.startScroll(curScrollX, 0, -curScrollX, 0);
				}
				invalidate();  // 重绘view
				
				
				isleftrightEvent = false;
				isTestCompete = false;
				break;
			}
		}else {
			switch (ev.getActionMasked()) {
			case MotionEvent.ACTION_UP:
				super.dispatchTouchEvent(ev);
				isleftrightEvent = false;
				isTestCompete = false;
				break;

			default:
				break;
			}
		}

		return super.dispatchTouchEvent(ev);
	}
	@Override
	public void computeScroll() {
		
		// 滑动的回调方法。实现滑动所必须的方法。
		super.computeScroll();
		if (!mScroller.computeScrollOffset()		) {
			return ;
		}
		int tempX =mScroller.getCurrX();
		scrollTo(tempX, 0);
	}

	private Point point = new Point();
	private static final int TEST_DIS = 20;  //最小滑动距离

	private void getEventType(MotionEvent ev) { 
		//判断手势。

		switch (ev.getActionMasked()) {
		case MotionEvent.ACTION_DOWN:  // 按下时获取点
			point.x = (int) ev.getX();
			point.y = (int) ev.getY();
			super.dispatchTouchEvent(ev);

			break;

		case MotionEvent.ACTION_MOVE: // 移动时,判断方向

			int dx = Math.abs((int) ev.getX() - point.x);
			int dy = Math.abs((int) ev.getY() - point.y);
			super.dispatchTouchEvent(ev);

			if (dx >= TEST_DIS && dx > dy) {  // 左右滑动。(水平位移大于20dp,且水平滑动大于垂直滑动。)
				isleftrightEvent = true;
				isTestCompete = true;
				point.x = (int) ev.getX();
				point.y = (int) ev.getY();
			} else if (dy >= TEST_DIS && dy > dx) {  // 垂直滑动。(垂直位移大于20dp,且垂直滑动大于水平滑动)
				isleftrightEvent = false;
				isTestCompete = true;
				point.x = (int) ev.getX();
				point.y = (int) ev.getY();
			}
			break;
		case MotionEvent.ACTION_UP:
		case MotionEvent.ACTION_CANCEL: // 抬起,或者滑到屏幕边缘是,初始化isleftrightEvent isTestCompete
			
			super.dispatchTouchEvent(ev);
			isleftrightEvent = false;
			isTestCompete = false;
			break;

		default:
			break;
		}

	}

}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值