android 多个listView/recycleView 公用一个headerView的处理方式

之前又不止一次的碰到类似的需求,之前为了图方便,都是选择的重写listView的onMeasure方法

@Override 
	public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 

		int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); 
		super.onMeasure(widthMeasureSpec, expandSpec); 
	} 

但是这种方法跟提前计算设置好listView的高度一样,我们的ListView的复用机制就失效了。如果listView多几个,再上拉加载几次 很容易就OOM了。

也可以采用只使用一个ListView 每次切换tab的时候给listView的adapter刷新数据。这样倒是能解决服用的问题,但是这样getView()中的方法太过复杂,而且切换时候的用户体验并不好。话不多说,直接上正餐!


我们都知道ViewGroup 中跟触摸有关的回调函数有三个dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent,其中dispatchTouchEvent是用于分发触摸事件的,onInterceptTouchEvent是用于拦截touch事件的,onTouchEvent是用于处理touch事件的。而View中没有onInterceptTouchEvent,而要解决我们的问题,则需要用到onInterceptTouchEvent,onTouchEvent这两个回调函数。

用户手指触碰屏幕的时候首先会出发onInterceptTouchEvent 的ACTION_DOWN ,这时候我们只需把touch事件放行并记录相关数据即可。此处有一个小tips,如果子控件对于ACTION_DOWN事件也没有进行消费的话,系统会认为touch事件无效。后面的ACTION_MOVE就不会有了。listView的onTouchEvent对于ACTION_DOWN事件是有进行消费的。而其他的一些控件诸如TextView则没有进行消费,这时候就需要我们手动进行消费了。

重头戏来了!

ACTION_MOVE 事件的处理才是我们这篇文章的精髓!

首先,记录下这次move的相关数据

float y = ev.getY(), x = ev.getX();
			float diff, oppositeDiff, absDiff;
			diff = y - mLastMotionY;
			oppositeDiff = x - mLastMotionX;
			absDiff = Math.abs(diff);

然后根据滑动的方向,listView的位置来判断是放行还是拦截

首先我们需要区分是左右滑动还是上下滑动,这里简单比较上下的偏移和左右的便宜的大小。如果是上下滑动,再判断是否为点击事件,判断点击事件还是滑动事件的临界值,可以这样获取

mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop()

如果是滑动事件,再根据listView的滑动位置(在顶部/底部)和手指滑动的方向来决定是否放行。

1: listView在底部,手指向下滑动,放行,把滑动事件交给listView的onTouchEvent。

2:listView在顶部,手指想上滑动,同上。

3:由于我们有headerView的存在,所以需要把headerView考虑进去,具体代码在下面贴出来了。

if (absDiff >= 0 && absDiff >= Math.abs(oppositeDiff)) {
				if (isBottom) {
					//listView在底部了
					if (absDiff >= mTouchSlop) {
						if (diff >= 1f) {
							//往上滑
							mIsBeingDragged = false;
						}else{
							mIsBeingDragged = true;
						}
					}else{
						mIsBeingDragged = false;
					}
				}else{
					if (absDiff >= mTouchSlop) {
						if (isTop) {
							if(diff <= -1f && getScrollY() < headViewHeight){
								//listView 在顶部 这时候往上滑
								mIsBeingDragged = true;
							}else if(diff >= 1f && getScrollY() <= headViewHeight){
								//listView在顶部 这时候往下滑
								mIsBeingDragged = true;
							}else{
								mIsBeingDragged = false;
							}
						}
					}else if(absDiff <= mTouchSlop){ 
						//移动的位置在-8 ~ 8之间视为点击事件 
						mIsBeingDragged = false;
					}
				}
			}

ACTION_UP 的时候只需吧mIsBeingDragged置为false即可。

接下来处理move事件 重写onTouchEvent方法,这里就不做多解释了,相信都能看得懂,直接贴代码了

@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_MOVE: {
			mLastMotionY = event.getY();
			mLastMotionX = event.getX();
			if (mIsBeingDragged) {
				pullEvent();
				return true;
			}
			break;
		}
		default:
			break;
		}
		return false;
	}

	private void pullEvent() {
		int scrollY = (int) (mInitialMotionY - mLastMotionY + currScrollY);
		scrollY = scrollY > 0 ? (scrollY < headViewHeight ? scrollY : headViewHeight) : 0;
		scrollTo(0, scrollY);
	}

关键代码都贴出来了,如代码有问题,欢迎各位同学指正大笑

完整代码链接:http://download.csdn.net/download/qq_24265937/10246213 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值