上一篇《Android自定义组件系列【6】——进阶实践(3)》中补充了关于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的意思是上面三种状态改变时回调,回调顺序如下:

  1. 第1次:scrollState=SCROLL_STATE_TOUCH_SCROLL(1)正在滚动
  2. 第2次:scrollState=SCROLL_STATE_FLING(2)手指做了抛的动作(手指离开屏幕前,用力滑了一下)
  3. 第3次:scrollState=SCROLL_STATE_IDLE(0)停止滚动
  4. 上面的OnScrollStateChanged方法中在滚动停止后再次布局(绘制)了列表的头。在onScroll方法中主要是为了调用前面提到的refreshHeader()方法去回调并刷新列表头。
  5. 四、如何处理下面列表头将上面列表头顶上去?
  6.     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()方法中可以看到,先判断上面的是不是多个列表头如果是则重新设置下面列表头的位置到“标准位置”,这样就感觉有一种顶上去的感觉了。
  7. 三、如何展开收缩列表
  8.     @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中的事件分发函数中有如下代码:
  9. if (y >= mHeaderView.getTop() && y <= mHeaderView.getBottom()) 
    限制高度(在列表头位置)
  10. if (isGroupExpanded(groupPosition)) {                        collapseGroup(groupPosition);                    } else {                        expandGroup(groupPosition);                    }
    如果点击则展开或闭合。


先分析到这里吧,差不多完了。。。。。。














更多相关文章

  1. [置顶] Android(安卓)ButterKnife
  2. Android中间层c语言log打印方法
  3. Android设置程序最小运行的堆内存
  4. android NumberPicker 全面解析
  5. Android(安卓)倒计时实现,显示剩余时分秒
  6. android打开系统相册的一些方法
  7. android studio 中报Error:Execution failed for task ':app:mer
  8. Android数据库中查找一条数据使用的方法 query详解
  9. Android(安卓)App 退出整个应用

随机推荐

  1. Android(安卓)API 中文 (5) —— 使用平台
  2. Android利用RecyclerView实现列表倒计时
  3. Android使用ViewPager实现左右循环滑动及
  4. Android中常出现的内存泄漏情况分析
  5. 利用Canvas实现在屏幕随机位置绘制10个大
  6. iOS、Android开发应用设计十建议
  7. Android(安卓)升级服务,哪家厂商做得最好?
  8. android APP性能优化总结
  9. Android(安卓)内存管理的相关知识
  10. android跳转小程序并返回遇到的坑点和解