In fact, as early as last July, my friends in the group let me share this. But I wasn’t very good at it. The code is buggy or something. I didn’t write it down. Now it feels like it’s all sorted out. Just write it out for everyone to see, and discuss and solve problems together.

Swiperefreshlayout, SuperSwiperefreshlayout, XRecyclerView, etc. It’s much older, and I’m still saying, whatever it is, we need to know how it works.

Start framing

What’s the first thing that comes to mind about the refresh load implementation? Do I use swiperefresh and then add a different type to the bottom of recyclerView? Or is it event interception? It must be event blocking, although swiperefreshLayout is very popular now, basically many apps can see it. But there’s nothing you can do about the company that says refresh with your own logo. For.. Okay, I feel like I’ve offended a lot of companies, so let’s move on.

If you’ve been reading my blog for a long time, you’ll know that I’ve written about incident blocking in one of my previous posts. Yes, it isAnalyze NestedScrolling for NestedScrolling from the source

For those who do not know nestedscrolling, please continue below.

Let’s take a look at our renderings:



There’s nothing wrong with him. Here’s how to do it.

The drop-down refresh

First we give the following parameters, followed by:


    private NestedScrollingParentHelper helper = null;
    private boolean IsRefresh = true;
    private boolean IsLoad = true;
    // Total sliding distance
    private int totalY = 0;
    private LinearLayout headerLayout = null;
    private MyRecyclerView myRecyclerView = null;
    private LinearLayout footerLayout = null;Copy the code

Since it’s refresh, we must scroll before the parent view. So we need to put in the onNestedPreScroll method the x and y values that we need to change. We need to block it with the parent view. We need to determine if the value of dy is greater than 0, because greater than 0 is a refresh operation and less than 0 is a load operation. Then we need to determine whether recyclerView is vertical rather than horizontal.

public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
        if (IsRefresh) {
            if (dy > 0) {
                if (myRecyclerView.isOrientation(0)) {
                    totalY += dy;
                    if ((totalY / 2) < =0) {
                        scrollTo(0, totalY / 2);
                        consumed[1] = dy;
                    } else {
                        scrollTo(0.0);
                        consumed[1] = 0; }}return; }}Copy the code

Pull on loading

I also said that onNestedPreScroll is a method that says dy<0 is the load operation. So in summary, the code looks like this:

  public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
        if (totalY < 0 && myRecyclerView.isOrientation(0) || totalY > 0 && myRecyclerView.isOrientation(1)) {
            isfling = true;
        }
        if (IsRefresh) {
            if (dy > 0) {
                if (myRecyclerView.isOrientation(0)) {
                    totalY += dy;
                    if ((totalY / 2) < =0) {
                        scrollTo(0, totalY / 2);
                        consumed[1] = dy;
                    } else {
                        scrollTo(0.0);
                        consumed[1] = 0; }}return; }}if (IsLoad) {
            if (dy < 0) {
                if (myRecyclerView.isOrientation(1)) {
                    totalY += dy;
                    if ((totalY / 2) > =0) {
                        scrollTo(0, totalY / 2);
                        consumed[1] = dy;
                    } else {
                        scrollTo(0.0);
                        consumed[1] = 0; }}return; }}}Copy the code

Finally, we need to do the following after the child view is finished sliding:

  // The child view slides to end the call
    //dyUnconsumed < 0 rolls down
    //dyUnconsumed > 0 rolls up
    public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        if(dyUnconsumed ! =0) {
            totalY += dyUnconsumed;
            scrollTo(0, totalY / 2); }}Copy the code

In fact, the two main methods have been solved, and there is nothing else. Here, I put the functions of nestedscrolling’s 8 interfaces and custom recyclerView. Has changed for your reference. Hopefully, everyone can do their own reload. Farewell swiperefreshlayout.

Add headers and footers

So here we refer to the AddHeaderView and addFooterView that come with listView. The code is as follows:

 public void addHeaderView(View headerView, int headerHeight) {
        this.headerLayout.removeAllViews();
        this.headerLayout.addView(headerView);
        LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, headerHeight);
        layoutParams.topMargin = -headerHeight;
        this.headerLayout.setLayoutParams(layoutParams);
    }

    public void addFooterView(View footerView, int footerHeight) {
        this.footerLayout.removeAllViews();
        this.footerLayout.addView(footerView);
        this.footerLayout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, footerHeight));
    }Copy the code

Implementation of several interfaces

  public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
        return true;
    }

    public void onNestedScrollAccepted(View child, View target, int axes) {
        helper.onNestedScrollAccepted(child, target, axes);
    }

    // The parent view intercepts the child view's scroll
    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
        if (totalY < 0 && myRecyclerView.isOrientation(0) || totalY > 0 && myRecyclerView.isOrientation(1)) {
            isfling = true;
        }
        if (IsRefresh) {
            if (dy > 0) {
                if (myRecyclerView.isOrientation(0)) {
                    totalY += dy;
                    if ((totalY / 2) < =0) {
                        scrollTo(0, totalY / 2);
                        consumed[1] = dy;
                    } else {
                        scrollTo(0.0);
                        consumed[1] = 0; }}return; }}if (IsLoad) {
            if (dy < 0) {
                if (myRecyclerView.isOrientation(1)) {
                    totalY += dy;
                    if ((totalY / 2) > =0) {
                        scrollTo(0, totalY / 2);
                        consumed[1] = dy;
                    } else {
                        scrollTo(0.0);
                        consumed[1] = 0; }}return; }}}// The child view slides to end the call
    //dyUnconsumed < 0 rolls down
    //dyUnconsumed > 0 rolls up
    public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        if(dyUnconsumed ! =0) {
            totalY += dyUnconsumed;
            scrollTo(0, totalY / 2); }}public void onStopNestedScroll(View child) {
        helper.onStopNestedScroll(child);
        if(onTouchUpListener ! =null) {
            isfling = false; onTouchUpListener.touchUp(); }}public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
        return isfling;
    }

    public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
        return isfling;
    }

    public int getNestedScrollAxes() {
        return helper.getNestedScrollAxes();
    }Copy the code

Custom recyclerview

Since is to write their own refresh loading framework, there can not be a custom layout in a recyclerView. It’s a hassle to create a custom one, put it in there, and then put a header and a footer so you don’t have to write a layout every time you refresh a page. Three layouts solve the whole project refresh and load. Without further ado, the code is as follows:

    private class MyRecyclerView extends RecyclerView {
        private StaggeredGridLayoutManager staggeredGridLayoutManager = null;
        private LinearLayoutManager linearLayoutManager = null;
        private GridLayoutManager gridLayoutManager = null;
        private boolean isScrollLoad = false;
        private boolean isScrollRefresh = false;

        public MyRecyclerView(Context context) {
            super(context);
            setVerticalFadingEdgeEnabled(false);
            setHorizontalFadingEdgeEnabled(false);
            setVerticalScrollBarEnabled(false);
            setHorizontalScrollBarEnabled(false);
            setOverScrollMode(OVER_SCROLL_NEVER);
            setItemAnimator(new DefaultItemAnimator());
        }

        private void setMyLayoutManager(LayoutManager layoutManager) {
            if (layoutManager instanceof StaggeredGridLayoutManager) {
                staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;
            } else if (layoutManager instanceof GridLayoutManager) {
                gridLayoutManager = (GridLayoutManager) layoutManager;
            } else if (layoutManager instanceof LinearLayoutManager) {
                linearLayoutManager = (LinearLayoutManager) layoutManager;
            }
            setLayoutManager(layoutManager);
            if(! isVertical()) {throw new NullPointerException("vertical!"); }}private boolean isOrientation(int orientation) {// Orientation,0 means down, 1 means up
            if (orientation == 0)
                return isCanPullDown();
            else if (orientation == 1)
                return isCanPullUp();
            return false;
        }

        private boolean isCanPullDown() {
            return! canScrollVertically(-1);
        }

        private boolean isCanPullUp() {
            return! canScrollVertically(1);
        }

// private int scrollLoad() {
// int lastItem = 0;
// int itemCount = 0;
// int spanCount = 1;
// if (staggeredGridLayoutManager ! = null) {
// lastItem = staggeredGridLayoutManager.findLastVisibleItemPositions(null)[0];
// itemCount = staggeredGridLayoutManager.getItemCount();
// spanCount = staggeredGridLayoutManager.getSpanCount();
// } else if (linearLayoutManager ! = null) {
// lastItem = linearLayoutManager.findLastVisibleItemPosition();
// itemCount = linearLayoutManager.getItemCount();
// spanCount = 1;
// } else if (gridLayoutManager ! = null) {
// lastItem = gridLayoutManager.findLastVisibleItemPosition();
// itemCount = gridLayoutManager.getItemCount();
// spanCount = gridLayoutManager.getSpanCount();
/ /}
// return ((itemCount - 1) / spanCount + 1) - (lastItem / spanCount + 1);
/ /}

        private boolean isVertical() {
            if(staggeredGridLayoutManager ! =null)
                return staggeredGridLayoutManager.getOrientation() == StaggeredGridLayoutManager.VERTICAL;
            else if(linearLayoutManager ! =null)
                return linearLayoutManager.getOrientation() == LinearLayoutManager.VERTICAL;
            else if(gridLayoutManager ! =null)
                return gridLayoutManager.getOrientation() == GridLayoutManager.VERTICAL;
            return false;
        }

// public void onScrolled(int dx, int dy) {
// if (dy > 0 && ! isScrollLoad) {
// if (oLior ! = null) {
// onScrollListener.scrollLoad(sc````````
`
``
llLoad());// Pass the scroll to the penultimate line
/ /}
/ /}
/ /}
    }Copy the code

This way we have implemented our own refresh loading framework, the code I have uploaded to github: github.com/sw950729/SW… As for the usage method: jCenter:


    compile 'com. Angel: SWPullRecyclerLayout: 1.0.0'Copy the code

Maven:

<dependency>
  <groupId>com.angel</groupId>
  <artifactId>SWPullRecyclerLayout</artifactId>
  <version>1.0.0</version>
  <type>pom</type>
</dependency>Copy the code

Tomorrow official work, before work to share this dry goods to everyone. The same two words. Whatever it is we need to know how it works. There is what do not understand put forward. We can discuss it together.