解决 RecyclerView 使用 paddingTop & clipToPadding = false 时,上方透明区域 Touch 事件无法下传

a2

解决办法相对比较简单,正好今天有人问到这个问题,所以把我的做法分享出来,即做一下手势分发即可,对此我继承 RecyclerView 做了 dispatchTouchEvent() 方法的重写,我使用了 Kotlin 编程语言,阅读起来应该不是什么问题,读者有需要的话,我已经增加了 Java 版本了,其他的可以自行修改。

原理就是当检测到有设置 clipToPadding = false 的时候,进行触摸点位置判断,在 dispatchTouchEvent() 方法返回 false 即表示对当前触摸事件不感兴趣,事件可将手势往下层传递,全部的代码下面会附上。

这篇文章可以说,让 RecyclerView 离无所不能真正又近了一步,从此可以不再搞什么 add header view 来设置头部内容了。当你突发奇想像我那么做(可以结合 CollapsingToolbarLayout 效果更好)的时候,遇到我所遇到的问题,这篇文章应该能够受益匪浅:D

Kotlin 版本:

public class GenerousRecyclerView : RecyclerView {

    public var mScrollY: Int = 0
    private var mEating = false

    public constructor(context: Context) : this(context, null)

    public constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)

    public constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {

        addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                mScrollY += dy
            }

            override fun onScrollStateChanged(recyclerView: RecyclerView?, newState: Int) {
                super.onScrollStateChanged(recyclerView, newState)
                when(newState) {
                    RecyclerView.SCROLL_STATE_IDLE -> mEating = false

                    RecyclerView.SCROLL_STATE_DRAGGING -> mEating = true
                }
            }
        })
    }

    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
        return if (!mEating && !getClipToPaddingCompat() && mScrollY < paddingTop && ev.y <
                paddingTop) {
            false
        } else {
            super.dispatchTouchEvent(ev)
        }
    }

    /**
     * @return false, if sdk_int < 21. else return getClipToPadding();
     */
    private fun getClipToPaddingCompat(): Boolean {
        if (Build.VERSION.SDK_INT < 21) {
            return layoutManager != null && layoutManager.clipToPadding
        } else {
            return clipToPadding
        }
    }
}

Java 版本:

public class GenerousRecyclerView extends RecyclerView {

    public int mScrollY = 0;
    private boolean mEating = false;


    public GenerousRecyclerView(Context context) {
        this(context, null);
    }


    public GenerousRecyclerView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }


    public GenerousRecyclerView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        addOnScrollListener(new OnScrollListener() {
            @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                switch (newState) {
                    case SCROLL_STATE_IDLE:
                        mEating = false;
                        break;
                    case SCROLL_STATE_DRAGGING:
                        mEating = true;
                        break;
                }
            }


            @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                mScrollY += dy;
            }
        });
    }


    @Override public boolean dispatchTouchEvent(MotionEvent ev) {
        if (!mEating && !getClipToPaddingCompat() && ev.getY() + mScrollY < getPaddingTop()
                && ev.getY() < getPaddingTop()) {
            return false;
        }
        else {
            return super.dispatchTouchEvent(ev);
        }
    }


    /**
     * @return false, if sdk_int < 21. else return getClipToPadding();
     */
    private boolean getClipToPaddingCompat() {
        if (Build.VERSION.SDK_INT < 21) {
            return getLayoutManager() != null && getLayoutManager().getClipToPadding();
        }
        else {
            return getClipToPadding();
        }
    }
}

GitHUb 源代码:https://github.com/drakeet/GenerousRecyclerView

  1. 我上次让一个viewpager藏在一个listview第一个透明item的后面并且高度等于listView的第一个item,所以listview总是把事件响应了,后来我也是用这种方法解决的。

  2. Pingback: Java重写方法与初始化的隐患-UNVPN.COM

  3. 你说recyclerView不需要设置header,没看懂[衰] 是不是可以把header放到collapseToolbarLayout中? 但是这样的话 ,你的clippadding是解决了什么问题???

  4. Pingback: Java 重写方法与初始化的隐患 | 解学渊博客

  5. Pingback: طراحی وب سایت آکان

  6. Pingback: search engine optimiser Melbourne

  7. Pingback: mira esto

  8. Pingback: Motogolf

  9. Pingback: Find Businesses in Australia

  10. Pingback: PureLocal.com.au - Australia's Business Directory

  11. Pingback: Weirder the Better Reviews & Contact Details

  12. Pingback: Reviews & Contact Details

  13. Pingback: Trisha on Times of India

  14. Pingback: para para dinle

  15. Pingback: information security architect

  16. Pingback: rhodium

  17. Pingback: joe de saram

  18. Pingback: thinning hair shampoo

  19. Pingback: bio-ethanol haard kopen

  20. Pingback: orderprimo.net

  21. Pingback: computer kopen winterswijk

  22. Pingback: LGBT adoption

  23. Pingback: roidsmall

  24. Pingback: kjoler

  25. Pingback: outlet ullared

  26. Pingback: M88

  27. Pingback: economics tuition

  28. Pingback: kimsin sen

  29. Pingback: arnaque

  30. Pingback: esculap

  31. Pingback: http://britlock.com.au

  32. Pingback: http://www.mckenzieandwillis.co.nz/

  33. Pingback: click here to find a lawyer

  34. Pingback: basement

  35. Pingback: celtic silver jewelry

  36. Pingback: http://www.godwinsremovals.co.uk/international-removals/northern-ireland

  37. Pingback: waterproofing