上一篇《》中补充了关于Android中事件分发的过程知识,这一篇我们接着来分析任老师的《可下拉的PinnedHeaderExpandableListView的实现》。
一、StickyLayout中的OnGiveUpTouchEventListener接口的作用是什么?
public interface OnGiveUpTouchEventListener { public boolean giveUpTouchEvent(MotionEvent event); }在StickyLayout中还提供了设置监听的方法如下:
public void setOnGiveUpTouchEventListener(OnGiveUpTouchEventListener l) { mGiveUpTouchEventListener = l; }这种方式其实是一种钩子方法,在OnGiveUpTouchEventListener中定义了一个抽象方法(未具体实现)giveUpTouchEvent.,然后通过MainActivity继承OnGiveUpTouchEventListener接口来实现具体逻辑。
@Override public boolean giveUpTouchEvent(MotionEvent event) { if (expandableListView.getFirstVisiblePosition() == 0) { View view = expandableListView.getChildAt(0); if (view != null && view.getTop() >= 0) { return true; } } return false; }这个方法中的逻辑:取到ExpandableListView中的第一个可见项,如果是它的子View中的第一个则说明现在首先应该滑动上面的Header部分(让其展开)。
这里返回的true和false有什么不同呢?向下看
@Override public boolean onInterceptTouchEvent(MotionEvent event) { int intercepted = 0; int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { mLastXIntercept = x; mLastYIntercept = y; mLastX = x; mLastY = y; intercepted = 0; break; } case MotionEvent.ACTION_MOVE: { int deltaX = x - mLastXIntercept; int deltaY = y - mLastYIntercept; if (mStatus == STATUS_EXPANDED && deltaY <= -mTouchSlop) { intercepted = 1; } else if (mGiveUpTouchEventListener != null) { if (mGiveUpTouchEventListener.giveUpTouchEvent(event) && deltaY >= mTouchSlop) { intercepted = 1; } } break; } case MotionEvent.ACTION_UP: { intercepted = 0; mLastXIntercept = mLastYIntercept = 0; break; } default: break; } Log.d(TAG, "intercepted=" + intercepted); return intercepted != 0; }在StickyLayout类中的事件拦截方法的ACTION_MOVE中有这么几句代码:
if (mStatus == STATUS_EXPANDED && deltaY <= -mTouchSlop) { intercepted = 1; } else if (mGiveUpTouchEventListener != null) { if (mGiveUpTouchEventListener.giveUpTouchEvent(event) && deltaY >= mTouchSlop) { intercepted = 1; } }现在应该明白了吧,呵呵。STATUS_EXPANDED是一个状态值,意思是现在Header部分是展开的,如果Header部分是收起的则会判断giveUpTouchEvent的返回值,如果giveUpTouchEvent返回true说明列表全部被拉下来了,此时应该将Header部分展开。如果返回false则应该下滑列表而不是展开Header部分。
二、PinnedHeaderExpandableListView对OnScrollLister的实现
@Override public void onScrollStateChanged(AbsListView view, int scrollState) { if (mHeaderView != null && scrollState == SCROLL_STATE_IDLE) { int firstVisiblePos = getFirstVisiblePosition(); if (firstVisiblePos == 0) { mHeaderView.layout(0, 0, mHeaderWidth, mHeaderHeight); } } if (mScrollListener != null) { mScrollListener.onScrollStateChanged(view, scrollState); } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if (totalItemCount > 0) { refreshHeader(); } if (mScrollListener != null) { mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); } }OnScrollListener是ListView的滚动事件。
在onScrollStateChanged(AbsListView view, int scrollState)中,scrollState有三种状态,分别是:
1、SCROLL_STATE_FLING:开始滚动
2、SCROLL_STATE_TOUCH_SCROLL:正在滚动
3、SCROLL_STATE_IDLE:已经停止
onScroll()方法在列表滚动时一直回调,知道滚动停止才停止回调,另外单击时也回调一次。而OnScrollStateChanged的意思是上面三种状态改变时回调,回调顺序如下:
protected void refreshHeader() { if (mHeaderView == null) { return; } int firstVisiblePos = getFirstVisiblePosition(); int pos = firstVisiblePos + 1; int firstVisibleGroupPos = getPackedPositionGroup(getExpandableListPosition(firstVisiblePos)); int group = getPackedPositionGroup(getExpandableListPosition(pos)); if (group == firstVisibleGroupPos + 1) { View view = getChildAt(1); if (view.getTop() <= mHeaderHeight) { int delta = mHeaderHeight - view.getTop(); mHeaderView.layout(0, -delta, mHeaderWidth, mHeaderHeight - delta); } } else { mHeaderView.layout(0, 0, mHeaderWidth, mHeaderHeight); } if (mHeaderUpdateListener != null) { mHeaderUpdateListener.updatePinnedHeader(firstVisibleGroupPos); } }refreshHeader()方法中可以看到,先判断上面的是不是多个列表头如果是则重新设置下面列表头的位置到“标准位置”,这样就感觉有一种顶上去的感觉了。
@Override public boolean dispatchTouchEvent(MotionEvent ev) { int x = (int) ev.getX(); int y = (int) ev.getY(); Log.d(TAG, "dispatchTouchEvent"); int pos = pointToPosition(x, y); if (y >= mHeaderView.getTop() && y <= mHeaderView.getBottom()) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { mActionDownHappened = true; } else if (ev.getAction() == MotionEvent.ACTION_UP) { int groupPosition = getPackedPositionGroup(getExpandableListPosition(pos)); if (groupPosition != INVALID_POSITION && mActionDownHappened) { if (isGroupExpanded(groupPosition)) { collapseGroup(groupPosition); } else { expandGroup(groupPosition); } mActionDownHappened = false; } } return true; } return super.dispatchTouchEvent(ev); }可以看到PinnedHeaderExpandableListView中的事件分发函数中有如下代码:
if (y >= mHeaderView.getTop() && y <= mHeaderView.getBottom())限制高度(在列表头位置)
if (isGroupExpanded(groupPosition)) { collapseGroup(groupPosition); } else { expandGroup(groupPosition); }如果点击则展开或闭合。
Android自定义组件系列【7】——进阶实践(4),布布扣,bubuko.com
原文:http://blog.csdn.net/dawanganban/article/details/25888941