SmoothAppBarLayout排坑記錄

需求涉及到CoordinatorLayout\AppBarLayout這套組件,基本邏輯寫完後,發現滑動卡頓。多方查找後得知是所使用的support版本中控件本身問題,高版本中已解決,但實際情況是不可能升級support.design版本的,因此只能嘗試其他方案,最後在github上找到了庫smooth-app-bar-layout,雖然使用比原生複雜,但好歹能實現需求。不過在使用過程中遇到些問題,在此記錄。

1、SmoothAppBarLayout區域無法滑動
這個問題的解決辦法找了好久,最後在issues中找到了https://github.com/henrytao-me/smooth-app-bar-layout/issues/105,就是修改SmoothAppBarLayout的dispatchTouchEvent方法,代碼如下:

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {

    if (ev.getEdgeFlags() == CUSTOM_EDGE_FLAG) {
        return false;
    }

    boolean dispatched = super.dispatchTouchEvent(ev);
    if(ev.getAction() == MotionEvent.ACTION_DOWN) {
        downXValue = ev.getX();
        downYValue = ev.getY();
    }else{
        float currentX = ev.getX();
        float currentY = ev.getY();
        if (dispatched && ev.getAction() == MotionEvent.ACTION_MOVE) {
            if (Math.abs(downXValue - currentX) > Math.abs(downYValue - currentY)) {
                Log.d("Motion Type :","Horizantal");
            }else{
                Log.d("Motion Type :","Vertical");

                MotionEvent motionEvent = MotionEvent.obtain(ev);
                motionEvent.offsetLocation(getLeft(), getTop());
                motionEvent.setAction(MotionEvent.ACTION_DOWN);
                motionEvent.setEdgeFlags(CUSTOM_EDGE_FLAG);

                // getParent() cannot return null, since well - who would have called this method
                ((ViewGroup) getParent()).dispatchTouchEvent(motionEvent);
                return false;
            }
        }
    }
    return dispatched;
}

但是在ZUK手機上測試時,奇怪的問題發生了,SmoothAppBarLayout內控件點擊事件無效,調試後發現,實際的ACTION_UP變成了ACTION_MOVE,因此又做了些變動,最終代碼如下:

@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {

        // We need to check wether we have arrived from our own triggered motion dispatch,
        // There are no really appropriate fields on MotionEvents to store custom data, so we abuse edgeflags
        if (ev.getEdgeFlags() == CUSTOM_EDGE_FLAG) {
            return false;
        }

        boolean dispatched = super.dispatchTouchEvent(ev);
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            downXValue = ev.getX();
            downYValue = ev.getY();
        } else {
            float currentX = ev.getX();
            float currentY = ev.getY();
            if (dispatched
                    && ev.getAction() == MotionEvent.ACTION_MOVE
                    && (Math.abs(downXValue - currentX) > mTouchSlop || Math.abs(downYValue - currentY) > mTouchSlop)) {

                if (Math.abs(downXValue - currentX) > Math.abs(downYValue - currentY)) {
                    Log.d("Motion Type :", "Horizantal");
                } else {
                    Log.d("Motion Type :", "Vertical");

                    MotionEvent motionEvent = MotionEvent.obtain(ev);
                    motionEvent.offsetLocation(getLeft(), getTop());
                    motionEvent.setAction(MotionEvent.ACTION_DOWN);
                    motionEvent.setEdgeFlags(CUSTOM_EDGE_FLAG);

                    // getParent() cannot return null, since well - who would have called this method
                    ((ViewGroup) getParent()).dispatchTouchEvent(motionEvent);
                    return false;
                }
            }
        }
        return dispatched;
    }

2、ViewPager中有多個列表時,向上滑動其中一個列表,切換到另一個列表時,SmoothAppBarLayout會完全展示。
這個問題沒有什麼好的解決辦法,我只能嘗試讓其他列表跟着滑動,這樣切換過去後不會出現頁面跳動。大致代碼如下:

mAppBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
            @Override
            public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {

                RecyclerView recyclerView = mOtherFragment.getScrollTarget();
                if (recyclerView != null) {
                    recyclerView.scrollBy(0, verticalOffset - recyclerView.computeVerticalScrollOffset());
                }
                
            }
        });

3、RecyclerView中footer的高度
這個問題是最複雜也是耗時最長的。如果計算不對,有可能出現推不上去或推上去太多的問題。這個問題的解決視情況而定,這裏簡要介紹下我碰到的需求的實現思路。如圖:


爲了把AppBarLayout推上去,RecyclerView的高度要比實際高度多出AppBarLayout的高度,所以結果就是:
RVHeight + AppBarHeight = FooterHeight + lastVisibleItemBottom
考慮到lastVisibleItemBottom與RecyclerView的滑動距離有關,因此修正後爲
RVHeight + AppBarHeight = FooterHeight + lastVisibleItemBottom + scrollY
這樣Footer高度的計算規則就知道了

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