【问题标题】:Horizontal recyclerview inside vertical recyclerview scrolling perfomance水平 recyclerview 内垂直 recyclerview 滚动性能
【发布时间】:2016-11-09 06:57:32
【问题描述】:

我几乎有这个:https://github.com/RyanHurst/TvProgramRecyclerView。水平 recyclerviews 作为垂直 recyclerview 的一个项目。每个水平 recyclerview 滚动都是同步的(仅可见项目)。

水平滚动很流畅,但垂直滚动真的很糟糕。当在水平滚动的位置 0 滚动时,它运行得很好,但是向右滚动的次数越多,它变得越慢。我试图不在 onBinViewHolder 中设置回收器适配器,并为每个水平回收器使用一个通用的 recyclerviewpool,什么也没有。

【问题讨论】:

    标签: android android-layout android-recyclerview


    【解决方案1】:

    对于外部垂直的RecyclerView,使用这个扩展类:

    public class BetterRecyclerView extends RecyclerView{
      private static final int INVALID_POINTER = -1;
      private int mScrollPointerId = INVALID_POINTER;
      private int mInitialTouchX, mInitialTouchY;
      private int mTouchSlop;
      public BetterRecyclerView(Context context) {
        this(context, null);
      }
    
      public BetterRecyclerView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
      }
    
      public BetterRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        final ViewConfiguration vc = ViewConfiguration.get(getContext());
        mTouchSlop = vc.getScaledTouchSlop();
      }
    
      @Override
      public void setScrollingTouchSlop(int slopConstant) {
        super.setScrollingTouchSlop(slopConstant);
        final ViewConfiguration vc = ViewConfiguration.get(getContext());
        switch (slopConstant) {
          case TOUCH_SLOP_DEFAULT:
            mTouchSlop = vc.getScaledTouchSlop();
            break;
          case TOUCH_SLOP_PAGING:
            mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(vc);
            break;
          default:
            break;
        }
      }
    
      @Override
      public boolean onInterceptTouchEvent(MotionEvent e) {
        final int action = MotionEventCompat.getActionMasked(e);
        final int actionIndex = MotionEventCompat.getActionIndex(e);
    
        switch (action) {
          case MotionEvent.ACTION_DOWN:
            mScrollPointerId = MotionEventCompat.getPointerId(e, 0);
            mInitialTouchX = (int) (e.getX() + 0.5f);
            mInitialTouchY = (int) (e.getY() + 0.5f);
            return super.onInterceptTouchEvent(e);
    
          case MotionEventCompat.ACTION_POINTER_DOWN:
            mScrollPointerId = MotionEventCompat.getPointerId(e, actionIndex);
            mInitialTouchX = (int) (MotionEventCompat.getX(e, actionIndex) + 0.5f);
            mInitialTouchY = (int) (MotionEventCompat.getY(e, actionIndex) + 0.5f);
            return super.onInterceptTouchEvent(e);
    
          case MotionEvent.ACTION_MOVE: {
            final int index = MotionEventCompat.findPointerIndex(e, mScrollPointerId);
            if (index < 0) {
              return false;
            }
    
            final int x = (int) (MotionEventCompat.getX(e, index) + 0.5f);
            final int y = (int) (MotionEventCompat.getY(e, index) + 0.5f);
            if (getScrollState() != SCROLL_STATE_DRAGGING) {
              final int dx = x - mInitialTouchX;
              final int dy = y - mInitialTouchY;
              final boolean canScrollHorizontally = getLayoutManager().canScrollHorizontally();
              final boolean canScrollVertically = getLayoutManager().canScrollVertically();
              boolean startScroll = false;
              if (canScrollHorizontally && Math.abs(dx) > mTouchSlop && (Math.abs(dx) >= Math.abs(dy) || canScrollVertically)) {
                startScroll = true;
              }
              if (canScrollVertically && Math.abs(dy) > mTouchSlop && (Math.abs(dy) >= Math.abs(dx) || canScrollHorizontally)) {
                startScroll = true;
              }
              return startScroll && super.onInterceptTouchEvent(e);
            }
            return super.onInterceptTouchEvent(e);
          }
    
          default:
            return super.onInterceptTouchEvent(e);
        }
      }
    }
    

    对于内部水平 RecyclerView,使用这个扩展类:

    public class FeedRootRecyclerView extends BetterRecyclerView{  
      public FeedRootRecyclerView(Context context) {
        this(context, null);
      }
    
      public FeedRootRecyclerView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
      }
    
      public FeedRootRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
      }
    
      @Override
      public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
     ``   /* do nothing */
      }
    }
    

    【讨论】:

    • 很好的参考,但你的答案是错误的 - 两者都适用于外部垂直回收器视图。
    • @Mick 我借用了这篇文章,并为我的用例做了一些更改。 IIRC,内部 recyclerview 的滚动存在一个小问题。我在我的应用程序中使用了上述两个类,并且效果很好。
    【解决方案2】:

    尝试在父级 RecyclerView 上设置 setNestedScrollingEnabled(false)

    【讨论】: