Solve the display and sliding problem of ScrollView nested RecyclerView

It is often necessary to embed one or more RecyclerViews in a ScrollView in a project. This approach usually leads to the following problems

  • Page swipe stuck
  • ScrollView height is not displayed properly
  • RecyclerView content is not displayed completely

This paper will use a variety of ways to solve the above problems


Sliding stuck solution

If there is only the problem of sliding stuck, the following two simple methods can be used to quickly solve the problem

The first: use the internal method of RecyclerView

recyclerView.setHasFixedSize(true);
recyclerView.setNestedScrollingEnabled(false);

Among them, the setHasFixedSize(true) method enables the RecyclerView to fix its own size and is not affected by the adapter change; and the setNestedScrollingeEnabled(false) method further calls the setNestedScrollingeEnabled(false) method of the NestedScrollingChildHelper object inside the RecyclerView, as follows

public void setNestedScrollingEnabled(boolean enabled) {
    getScrollingChildHelper().setNestedScrollingEnabled(enabled);
}
Furthermore, the NestedScrollingChildHelper object closes the nested sliding feature of RecyclerView through this method, as follows
public void setNestedScrollingEnabled(boolean enabled) {
    if (mIsNestedScrollingEnabled) {
        ViewCompat.stopNestedScroll(mView);
    }
    mIsNestedScrollingEnabled = enabled;
}
 
 

In this way, the sliding of RecyclerView itself is limited, and the sliding of the entire page is only realized by ScrollView, which can solve the problem of sliding stuck.

The second method: rewrite LayoutManager
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this) {
    @Override
    public boolean canScrollVertically() {
        return false;
    }
};
recycler.setLayoutManager (linearLayoutManager);

Comprehensive solution

If you need to comprehensively solve the above three problems, you can use the following methods

Insert LinearLayout/RelativeLayout

Insert a layer of LinearLayout/RelativeLayout into the original layout to form the following layout

Override LayoutManager

The core idea of ​​this method is to override the onMeasure() method in LayoutManager, that is

@Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
    super.onMeasure(recycler, state, widthSpec, heightSpec);
}

Reimplement the calculation of the height of RecyclerView so that it can show the correct height in ScrollView. For the specific rewriting method, please refer to this article

http://www.cnblogs.com/tianzh...

Override ScrollView

The core idea of ​​this method is to intercept the sliding event by rewriting the onInterceptTouchEvent(MotionEvent ev) method of ScrollView, so that the sliding event can be directly passed to the RecyclerView. For the specific rewriting method, please refer to the following

/**
 * Created by YH on 2017/10/10.
 */
 
public class RecyclerScrollView extends ScrollView {
    private int slop;
    private int touch;
 
    public RecyclerScrollView(Context context) {
        super(context);
        setSlop(context);
    }
 
    public RecyclerScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setSlop(context);
    }
 
    public RecyclerScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setSlop(context);
    }
 
    /**
     * 是否intercept当前的触摸事件
     * @param ev 触摸事件
     * @return true:调用onMotionEvent()方法,并完成滑动操作
     */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //  保存当前touch的纵坐标值
                touch = (int) ev.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                //  滑动距离大于slop值时,返回true
                if (Math.abs((int) ev.getRawY() - touch) > slop) return true;
                break;
        }
 
        return super.onInterceptTouchEvent(ev);
    }
 
    /**
     * 获取相应context的touch slop值(即在用户滑动之前,能够滑动的以像素为单位的距离)
     * @param context ScrollView对应的context
     */
    private void setSlop(Context context) {
        slop = ViewConfiguration.get(context).getScaledTouchSlop();
    }
}

In fact, although we can solve a series of problems caused by ScrollView nesting RecyclerView in a variety of ways, because the above solutions will make RecyclerView display all content at one time during page loading, so when there are too many items under RecyclerView , will affect the operating efficiency of the entire application. Based on this, in this case, we should try to avoid the layout of ScrollView nested RecyclerView



Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326347049&siteId=291194637