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



     之前做过《Android 滑动侧边栏(Sliding Menu)实现分析》,今天尝试选择一种解决方案来实现效果。

     这一周工作都比较忙,今天先实现了布局+随手指移动,但是发现选择的方案有问题,先来看个效果图后面再介绍解决方案和不足之处。

    

一、效果图

Android 滑动侧边栏(Sliding Menu)第二种实现方式 1_第1张图片


二、选择的解决方案


方案 具体使用 可参考之前Demo
布局 ViewGroup(左测绿色视图和右侧蓝色视图分别是其子View) 《自定义ViewGrup》
随手指移动 View.mScrollX,scrollTo() ,scrollBy() 《scrollBy使用》


1. 布局使用ViewGroup没有问题,从上图中就可以看到绿和蓝两个视图可以叠加在一起,也可以错开。

2. 但是使用mScrollX不行,虽然上图中看到了达到滚动的效果,但是效果实现其实很雷人,并不符合Android框架的设计。

    选择使用mScrollX的目的是因为可以提高效率,因为其仅重新调用onDraw不会调用onMeasure,onLayout方法。《具体分析》

    既然有些限制,不用着急换其他解决方案,毕竟写这些效果也是学习的目的,多尝试下总没有坏处,基于这种目的之后来看看如何绕过这个问题达到想要的滚动效果。   


三、为什么Sliding Menu不能使用mScrollX来处理滚动?


1. mScrollX,mScrollY是用来控制父视图中的子视图滚动,这样随来也没什么问题啊?反正是控制滚动。但是这种滚动却不是想要的效果,如果想让视图滚动并需在其父视图调用scrollTo或scrollBy方法 ,但是这样会导致绿色子视图和蓝色子视图一起滚动。具体解释在《Android View.scrollTo, View.scrollBy控制视图滚动原理》 

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


	private void initSlidingMenu(Context context) {
		// 为了使用mScrollX滚动,并且仅滚动右侧
		// 只能把右侧视图单独放入一个独立的ViewGruop中
		mRightViewGroup = new LinearLayout(context);
		mRightViewGroup.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
		addView(mRightViewGroup);
	}

	/**
	 * 提供右侧显示视图
	 * 
	 * @param rightView
	 */
	public void addRightView(View rightView) {
		// 此ViewGroup是包裹在右侧蓝色视图外的ViewGroup
		mRightViewGroup.addView(rightView);
		
		// 设置Touch事件
		mRightView.setOnTouchListener(new RightViewTouchEvent());
	}

	/**
	 *	右侧视图可以随手指移动
	 */
	private class RightViewTouchEvent implements OnTouchListener {

		private int mMotionX;
		
		
		@Override
		public boolean onTouch(View view, MotionEvent event) {
			
			final int x = (int) event.getX();
			int deltaX;
			
			switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				mMotionX = x;
				Log.e("Test", "ACTION_DOWN");
				return true;

			case MotionEvent.ACTION_MOVE:
				deltaX = x - mMotionX;
				mRightViewGroup.scrollBy(-deltaX, 0);
				
				Log.e("Test", "ACTION_MOVE "
						+ " , mMotionX = " + mMotionX
						+ " , x = " + x
						+ " , deltaX = " + deltaX
						+ " , mX = " + mRightViewGroup.getScrollX());
				return true;
				
			case MotionEvent.ACTION_UP:
				mMotionX = 0;
				Log.e("Test", "ACTION_UP");
				break;
			}
			
			return false;
		}
		
	}


    从上面的代码可以看出,既然scrollTo有上面提到的要求,但是可以通过把需要滚动的蓝色视图单独放入一个ViewGroup,这样可以使蓝色视图达到滚动效果。

    在上面的代码中可以看到onTouch事件中添加了LOG,也是通过LOG才发现一个问题。


四、touch事件问题

    这个问题也是由mScrollX引起的,因为解决上面三的问题,所以把蓝色视图放入一个独立的ViewgGroup,如果想让其滚动,需要滚动需要覆写此独立ViewGroup的onTouchEvent,这样做本身是符合逻辑的,但是从打印的LOG中发现出现问题。

ACTION_DOWN
ACTION_MOVE  , mMotionX = 66 , x = 66 , deltaX = 0 , mX = 1
ACTION_MOVE  , mMotionX = 66 , x = 66 , deltaX = 0 , mX = 1
ACTION_MOVE  , mMotionX = 66 , x = 73 , deltaX = 7 , mX = -6
ACTION_MOVE  , mMotionX = 66 , x = 69 , deltaX = 3 , mX = -9
ACTION_MOVE  , mMotionX = 66 , x = 68 , deltaX = 2 , mX = -11
ACTION_MOVE  , mMotionX = 66 , x = 70 , deltaX = 4 , mX = -15
ACTION_MOVE  , mMotionX = 66 , x = 69 , deltaX = 3 , mX = -18
ACTION_MOVE  , mMotionX = 66 , x = 68 , deltaX = 2 , mX = -20
ACTION_MOVE  , mMotionX = 66 , x = 69 , deltaX = 3 , mX = -23
ACTION_MOVE  , mMotionX = 66 , x = 68 , deltaX = 2 , mX = -25
ACTION_MOVE  , mMotionX = 66 , x = 67 , deltaX = 1 , mX = -26
ACTION_UP

    上面的LOG是在蓝色视图区域横向向右滑动,按照预期应该是x值从66逐渐递增,但是从上面LOG可以看出x值得变化规律是 66, 73,69,68 , 70 , 69。

    图上效果正常是因为错误的使用,计算的deltaY是当前点与Action_Down按下时点的差值,而scrollBy的参数是相对上次移动的值。


    为什么即使手指在蓝色区域内向右滑动,其获取的event.getX()的值还是基本没什么变化呢? 原因是点击在蓝色区域内,getX()获取的是当前手指与蓝色区域左侧的距离,因为蓝色区域所手指移动,所以获取到的值也没什么变化。《Android Touch事件rawX,rawY与x,y的区别》

    当然这个问题也可以通过获取getRawX来解决,但是感觉没必要再接着处理因使用mScrollX引出的问题,因为其在View当中已经说明,是针对父视图中内容滚动支持提供的参数。


五、源码

源码下载

   

    为什么这个解决方案不是想要的效果还要写出来,并且提供源码下载? 感觉这是一个尝试的过程,尝试有可能直接成功也可能失败,但是我也没感觉这是失败,毕竟是学习的从这个解决方案中加深了对mScrollX进行滚动的了解。



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








你可能感兴趣的:(Android 滑动侧边栏(Sliding Menu)第二种实现方式 1)