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高度的计算规则就知道了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值