Android 滑动侧边栏(Sliding Menu)第一种实现 - 1 手动滚动+自动滚动


    之前的分析与一种解决方案,当前例子未充分考虑处理Touch事件,之后会接着完善例子。

《Android 滑动侧边栏(Sliding Menu)实现分析》

《Android 滑动侧边栏(Sliding Menu)第一种实现 - 1 手动滚动+自动滚动》 (本篇文章)

《Android 滑动侧边栏(Sliding Menu)第一种实现 - 2 手动滚动+自动滚动 + 事件处理》

《Android 滑动侧边栏(Sliding Menu)第二种实现方式1》



一、 先来看看效果图




二、实现展示


方案具体使用可参考之前Demo
布局ViewGroup(左测绿色视图和右侧蓝色视图分别是其子View)《自定义ViewGrup》
手动滚动ViewGroup.layout(left, top, right, bottom); 《layout方法官方文档》
自动滚动 Scroller 和 ViewGroup.layout();《Scroller Demo》 


三、伪代码

1. 布局上面的Demo中可以找到相关Demo

2  手动滚动和自动滚动都是在onTouchEvent中进行控制,先看下源码,不喜欢贴大段的完整代码,最后会提供完整代码下载

public class SlidingMenus extends ViewGroup {

	private View mRightView;
	private View mLeftView;
	
	// 记录一次移动位置,用于计算移动偏移量
	private int mLastX;
	
	// 按下时记录,用于判断当前滚动时向左还是向右
	private int mMotionX;
	
	......
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		
		final int x = (int) event.getX();
		
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			mLastX = x;
			mMotionX = x;
			
			boolean inRegion = canSliding(event);
			
			return inRegion;

		case MotionEvent.ACTION_MOVE:
			
			scrollIfNeed(x);
			return true;
			
		case MotionEvent.ACTION_UP:
			
			autoScrollIfNeed(x);
			
			break;
		}
		
		return true;
	}


	......

	
}


3. canSliding进行判断,仅右侧视图可以滚动,左侧视图不能滚动

	/**
	 * 只有右侧视图可以移动
	 * 
	 * @param event
	 * @return true 可以滚动
	 */
	private boolean canSliding(MotionEvent event) {
		int[] location = new int[2];
		// 获取右侧视图相对于屏幕坐标值
		mRightView.getLocationOnScreen(location);
		RectF region = new RectF();
		region.set(location[0] , location[1] ,
				location[0] + mRightView.getWidth(),
				location[1] + mRightView.getHeight());
		
		// 当前手指点击位置是否在右侧视图区域内
		boolean inRegion = region.contains(event.getRawX(), event.getRawY());
		return inRegion;
	}



4. 右侧视图随手指移动,具体实现方法在scrollIfNeed

	private void scrollIfNeed(final int x) {
		// 计算与上次的偏移量
		int deltaX = x - mLastX;
		
		// 减少移动次数
		if (x != mLastX) {
			int l = mRightView.getLeft();
			int t = mRightView.getTop();
			int b = mRightView.getBottom();
			
			// 右侧视图的滑动区域,只能在左侧视图范围内滑动
			int rightViewLeft = Math.max(mLeftView.getLeft(), l + deltaX);
			rightViewLeft = Math.min(mLeftView.getRight(), rightViewLeft);
			
			// 控制随手指滑动
			mRightView.layout(rightViewLeft, t, rightViewLeft + mRightView.getWidth(), b);
		}
		
		// 记录当前值供下次计算
		mLastX = x;
	}

5. 手指抬起后,视图随手指自动滚动具体实现在autoScrollIfNeed

	private void autoScrollIfNeed(final int x) {
		mScrollRunnable = new ScrollRunnable();
		
		// 用于判断滑动方向
		final int deltaX = x - mMotionX;
		// x轴向右是依次递增与手指落下点差值,小于0说明是手指向左滑动
		boolean moveLeft = deltaX <= 0;
		
		// 滑动距离超过左侧视图一半,才会沿着手指方向滚动
		final int distance = Math.abs(deltaX);
		if (distance < mLeftView.getWidth() / 2) {
			// 从哪来回哪去
			moveLeft = !moveLeft;
		}
		
		// 启动自动滚动
		mScrollRunnable.startScroll(moveLeft);
	}
	
	
	private class ScrollRunnable implements Runnable {
		// 滚动辅助类,提供起始位置,移动偏移,移动总时间,可以获取每次滚动距离
		private Scroller mScroller = new Scroller(getContext());
		
		@Override
		public void run() {
			final Scroller scroller = mScroller;
			// 计算滚动偏移,返回是否可以接着滚动
			boolean more = scroller.computeScrollOffset();
			// 计算后获取需要滚动到的位置
			final int x = scroller.getCurrX();
			
			if (more) {
				// 与手动滚动调用的方法相同
				scrollIfNeed(x);
				// 当前子线程已经执行完,但是需要接着滚动
				// 所以把当前Runnable再次添加到消息队列中
				post(this);
			} else {
				// 不需要滚动
				endScroll();
			}
			
		}
		
		
		private void startScroll(boolean moveLeft) {
			// 滚动前设置初始值
			mLastX = mRightView.getLeft();
			
			int dx = 0;
			
			// 计算移动总距离
			if (moveLeft) {
				// 当前到左视图左侧边界距离
				dx = mLeftView.getLeft() - mRightView.getLeft();
			} else {
				// 到右侧边界
				dx = mLeftView.getRight() - mRightView.getLeft();
			}
			
			// 开始滚动
			mScroller.startScroll(mRightView.getLeft(), 0, dx, 0, 300);
			// 把当前Runnable添加到消息队列中
			post(this);
		}
		
		private void endScroll() {
			// 从消息队列中把当前Runnable删除,即停止滚动
			removeCallbacks(this);
		}
		
	}





四、完整源码下载

源码下载连接



原文地址:http://blog.csdn.net/love_world_/article/details/8657125







  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值