Android仿微信小程序和QQ頭部下拉展開更多佈局

仿微信小程序和QQ頭部下拉展開更多佈局項目,主要參考來源於Github項目PullLoadXiaochengxu
本項目改造主要是優化中間內容佈局是ListView、RecyclerView或ScrollView等可滾動view時與頭部或底部滑動存在的滑動衝突問題,以及參考QQ,處理頭部收起以及底部收起時的回彈效果。
效果演示如下:
在這裏插入圖片描述
關鍵點是確定事件攔截的臨界點,處理好事件分發,本人已在代碼中添加了詳細的註解說明,有興趣的同行可以Review查看,共同學習,有興趣的同行可以star學習一下,項目GitHub地址如下:
PullLoadMoreCopyWeixinAndQQ
事件攔截與消耗代碼處理,具體流程可以查看代碼中的Log說明,完整代碼可以下載demo查看

@Override
public final boolean onInterceptTouchEvent(MotionEvent event) {
        Log.d(TAG, "onInterceptTouchEvent");
        if (!isInterceptTouchEventEnabled()) {
            return false;
        }
        if (!isPullLoadEnabled() && !isPullRefreshEnabled()) {
            return false;
        }
        final int action = event.getAction();
        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
            mIsHandledTouchEvent = false;
            return false;
        }
        if (action != MotionEvent.ACTION_DOWN && mIsHandledTouchEvent) {
            return true;
        }
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                Log.d(TAG, "onInterceptTouchEvent,MotionEvent.ACTION_DOWN");
                mLastMotionX = event.getX();
                mLastMotionY = event.getY();
                mIsHandledTouchEvent = false;
                break;

            case MotionEvent.ACTION_MOVE:
                Log.d(TAG, "onInterceptTouchEvent,MotionEvent.ACTION_MOVE");
                final float deltaX = event.getX() - mLastMotionX;
                final float deltaY = event.getY() - mLastMotionY;
                final float absDiff = Math.abs(deltaY);
                // 位移差大於mTouchSlop,這是爲了防止快速拖動引發刷新
//                if ((absDiff > mTouchSlop)) {
                mLastMotionX = event.getX();
                mLastMotionY = event.getY();
                // 第一步,先處理處理是否處於橫滑狀態
                if (Math.abs(deltaX) >= Math.abs(deltaY)) {
                    Log.e(TAG, "onInterceptTouchEvent,MotionEvent.ACTION_MOVE,當前處於橫滑狀態,不攔截,交由父類去處理");
                    return false;
                }
                mPullDown = deltaY > 0;

                if (mPullDown) {
                    Log.d(TAG, "當前處於下拉操作");
                    //下拉需要考慮如下情況:
                    // 1、頭部處理
                    // 1)刷新View已到達頂部,判斷是否需要
                    if (isPullRefreshEnabled() && checkIsContentViewScrollToTop((int) event.getX(), (int) event.getY())) {
                        Log.d(TAG, "當前處於下拉操作,且內容view已到達頂部,攔截,自己消耗處理,展開頭部");
                        return true;
                    } else if (isPullLoadEnabled() && mFooterLayout.getState() == IExtendLayout.State.arrivedListHeight && checkIsContentViewScrollToBottom((int) event.getX(), (int) event.getY())) {
                        Log.d(TAG, "當前處於下拉操作,且內容view已底部且已是展開狀態,攔截,自己消耗處理,收縮底部");
                        return true;
                    } else {
                        Log.d(TAG, "當前處於下拉操作,且內容view沒有到達頂部/到達底部,不攔截,給子view進行處理,滾動列表");
                        return false;
                    }
                } else {
                    Log.d(TAG, "當前處於上拉操作");
                    if (isPullRefreshEnabled() && mHeaderLayout.getState() == IExtendLayout.State.arrivedListHeight && checkIsContentViewScrollToTop((int) event.getX(), (int) event.getY())) {
                        Log.d(TAG, "當前處於上拉操作,頭部已完全展開,且內容view已到達頂部,攔截,自己消耗處理,用於頭部收縮");
                        return true;
                    } else if (isPullLoadEnabled() && checkIsContentViewScrollToBottom((int) event.getX(), (int) event.getY())) {
                        Log.d(TAG, "當前處於上拉操作,內容view已到達底部,攔截,自己消耗處理,用於底部展開");
                        return true;
                    } else {
                        Log.d(TAG, "當前處於上拉操作,且內容view沒有到達頂部/到達底部,不攔截,給子view進行處理,滾動列表");
                        return false;
                    }
                }
//                }else{
//                    Log.d(TAG,"absDiff <= mTouchSlop,認爲不滾動,不處理");
//                }

            case MotionEvent.ACTION_UP:
                Log.d(TAG, "onInterceptTouchEvent,MotionEvent.ACTION_UP");
                break;

            default:
                break;
        }
        return super.onInterceptTouchEvent(event);
    }
    
    @Override
    public final boolean onTouchEvent(MotionEvent ev) {
        boolean handled = false;
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.d(TAG, "onTouchEvent,MotionEvent.ACTION_DOWN");
                mLastMotionY = ev.getY();
                mIsHandledTouchEvent = false;
                break;

            case MotionEvent.ACTION_MOVE:
                final float deltaY = ev.getY() - mLastMotionY;
                mLastMotionY = ev.getY();
                mPullDown = deltaY > 0;
                Log.d(TAG, "onTouchEvent,MotionEvent.ACTION_MOVE,deltaY = " + deltaY);
                if (isPullRefreshEnabled() && isReadyForPullDown(deltaY)) {
                    // 處理頭部滑動
                    Log.d(TAG, "onTouchEvent,MotionEvent.ACTION_MOVE,處理頭部滑動");
                    pullHeaderLayout(deltaY / mOffsetRadio);
                    handled = true;
                    if (null != mFooterLayout && 0 != mFooterHeight) {
                        mFooterLayout.setState(IExtendLayout.State.RESET);
                    }
                } else if (isPullLoadEnabled() && isReadyForPullUp(deltaY)) {
                    Log.d(TAG, "onTouchEvent,MotionEvent.ACTION_MOVE,處理底部滑動");
                    // 上拉
                    pullFooterLayout(deltaY / mOffsetRadio);
                    handled = true;
                    if (null != mHeaderLayout && 0 != mHeaderHeight) {
                        mHeaderLayout.setState(IExtendLayout.State.RESET);
                    }
                } else {
                    mIsHandledTouchEvent = false;
                }
                break;

            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                Log.d(TAG, "onTouchEvent,MotionEvent.ACTION_UP");
//                if (mIsHandledTouchEvent) {
//                    mIsHandledTouchEvent = false;
                // 當第一個顯示出來時
                if (isReadyForPullDown(0)) {
                    Log.d(TAG, "onTouchEvent,MotionEvent.ACTION_UP,resetHeaderLayout");
                    if (mPullDown) {
                        // 彈性展開頭部
                        resetHeaderLayout();
                    } else {
                        // 往上拉時,收縮頭部,不彈性會彈
                        collapseHeaderLayout();
                    }
                } else if (isReadyForPullUp(0)) {
                    Log.d(TAG, "onTouchEvent,MotionEvent.ACTION_UP,resetFooterLayout");
                    if (mPullDown) {
                        collapseFooterLayout();
                    } else {
                        resetFooterLayout();
                    }
                }
//                }
                break;

            default:
                break;
        }
        return handled;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章