How To Change Android SwipeRefreshLayout Refresh Behavior To Pulling From Left

This example will tell you how to create a subclass of SwipeRefreshLayout to change the default refresh behavior from pull down to pull to left or right. This example will also use RecyclerView. And the RecyclerView should be the direct child of the custom SwipeRefreshLayout object.

1. Change SwipeRefreshLayout Refresh Behavior Example Overview.

custom android swiperefreshlayout to change behavior to pulling from left example

There is a RecyclerView in the screen, it has 6 image view child. When pull to right from the beginning, it will show SwipeRefreshLayout indicator, after data load a new image will be added at the beginning. When you scroll to the end and pull to left, it will add a new image at the RecyclerView ending.

Below is the java files used in this example.

custom android swiperefreshlayout java files

You also need to add below dependency library in your build.gradle file.

compile 'com.android.support:appcompat-v7:26.+'
compile 'com.android.support:design:26.+'
compile 'com.android.support:cardview-v7:26.+'
compile 'com.android.support:recyclerview-v7:26.+'

2. Main Activity.

CustomSwipeRefreshLayoutActivity.java

package com.dev2qa.example.material_design.swipe_refresh_layout;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;

import com.dev2qa.example.R;

import java.util.ArrayList;
import java.util.List;

public class CustomSwipeRefreshLayoutActivity extends AppCompatActivity {

    private RecyclerView recyclerView = null;

    private CustomSwipeRecyclerViewDataAdapter recyclerViewDataAdapter = null;

    public List<CustomSwipeRecyclerViewItem> recyclerViewItemList = null;

    private CustomSwipeRefreshLayout customSwipeRefreshLayout = null;

    public Handler uiUpdateHandler = null;

    public int MESSAGE_UPDATE_RECYCLER_VIEW = 1;

    public String MESSAGE_KEY_SCROLL_TO_BEGINNING = "MESSAGE_KEY_SCROLL_TO_BEGINNING";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_custom_swipe_refresh_layout);

        setTitle("dev2qa.com - Android Custom Swipe Refresh Layout Example.");

        initControls();

        CustomSwipeRefreshLoadMoreListener loadMoreListener = new CustomSwipeRefreshLoadMoreListener(this);

        customSwipeRefreshLayout.setLoadMoreListener(loadMoreListener);
    }


    private void initControls()
    {
        if(recyclerView==null)
        {
            // Get RecyclerView.
            recyclerView = (RecyclerView)findViewById(R.id.custom_swipe_refresh_layout_recycler_view);

            // Create the RecyclerView items list.
            recyclerViewItemList = new ArrayList<CustomSwipeRecyclerViewItem>();
            recyclerViewItemList.add(new CustomSwipeRecyclerViewItem(R.drawable.car_audi));
            recyclerViewItemList.add(new CustomSwipeRecyclerViewItem(R.drawable.car_benz));
            recyclerViewItemList.add(new CustomSwipeRecyclerViewItem(R.drawable.car_bmw));
            recyclerViewItemList.add(new CustomSwipeRecyclerViewItem(R.drawable.car_future));
            recyclerViewItemList.add(new CustomSwipeRecyclerViewItem(R.drawable.car_land_rover));
            recyclerViewItemList.add(new CustomSwipeRecyclerViewItem(R.drawable.car_jeep));

            // Create the linear layout manager.
            LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
            linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
            // Use above layout manager for RecyclerView..
            recyclerView.setLayoutManager(linearLayoutManager);

            // Create recycler view data adapter with item list.
            recyclerViewDataAdapter = new CustomSwipeRecyclerViewDataAdapter(recyclerViewItemList);
            // Set RecyclerView data adapter.
            recyclerView.setAdapter(recyclerViewDataAdapter);
        }

        if(customSwipeRefreshLayout==null)
        {
            customSwipeRefreshLayout = (CustomSwipeRefreshLayout)findViewById(R.id.custom_swipe_refresh_layout);
        }

        if(uiUpdateHandler == null)
        {
            uiUpdateHandler = new Handler()
            {
                @Override
                public void handleMessage(Message msg) {
                    // If the message want to refresh list view.
                    if(msg.what == MESSAGE_UPDATE_RECYCLER_VIEW)
                    {
                        // Refresh list view after add item data.
                        recyclerViewDataAdapter.notifyDataSetChanged();

                        Bundle bundle = msg.getData();
                        boolean scrollToBeginning = bundle.getBoolean(MESSAGE_KEY_SCROLL_TO_BEGINNING);
                        if(scrollToBeginning)
                        {
                            recyclerView.scrollToPosition(0);
                        }else
                        {
                            recyclerView.scrollToPosition(recyclerViewItemList.size() - 1);
                        }
                    }
                    // Stop showing the swipe refresh layout.
                    customSwipeRefreshLayout.setRefreshing(false);
                    customSwipeRefreshLayout.setLoading(false);
                }
            };
        }
    }
}

3. Custom SwipeRefreshLayout Java File.

CustomSwipeRefreshLayout.java

package com.dev2qa.example.material_design.swipe_refresh_layout;

import android.content.Context;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;

/**
 * Created by Jerry on 3/21/2018.
 */

public class CustomSwipeRefreshLayout extends SwipeRefreshLayout {

    // Save X position in pixels when user touch press down.
    private float pressDownX;
    // Save X position in pixels when user touch release up.
    private float pressUpX;

    private int scaledTouchSlop = 0;

    private RecyclerView recyclerView = null;

    private boolean loading = false;

    private CustomSwipeRefreshLoadMoreListener loadMoreListener;

    public boolean isLoading() {
        return loading;
    }

    public void setLoading(boolean loading) {
        this.loading = loading;
        if(this.loading)
        {
            // Show progress dialog.
            this.setRefreshing(true);
        }else
        {
            // Hide progress dialog
            this.setRefreshing(false);

            // Clear old press X value.
            pressUpX = 0;
            pressDownX = 0;
        }
    }

    public CustomSwipeRefreshLoadMoreListener getLoadMoreListener() {
        return loadMoreListener;
    }

    public void setLoadMoreListener(CustomSwipeRefreshLoadMoreListener loadMoreListener) {
        this.loadMoreListener = loadMoreListener;
    }

    public CustomSwipeRefreshLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        // Get ViewConfiguration object.
        ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
        // Get minimum distance for touch move action.
        scaledTouchSlop = viewConfiguration.getScaledTouchSlop();
    }
    
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        if(recyclerView == null)
        {
            int childCount = getChildCount();
            if(childCount > 0)
            {
                for( int i=0;i<childCount;i++) {
                    View firstChild = getChildAt(i);
                    if (firstChild instanceof RecyclerView) {
                        recyclerView = (RecyclerView) firstChild;
                        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                            @Override
                            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                                super.onScrollStateChanged(recyclerView, newState);
                                if (canLoadMoreData()) {
                                    loadMoreData();
                                }
                            }
                        });
                        break;
                    }
                }
            }
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        int pressAction = ev.getAction();
        float xPosition = ev.getX();

        if(pressAction == MotionEvent.ACTION_UP)
        {
            // If press action up.
            pressUpX = xPosition;
        }else if(pressAction == MotionEvent.ACTION_DOWN)
        {
            // If press action down.
            pressDownX = xPosition;
        }else if(pressAction == MotionEvent.ACTION_MOVE)
        {
            // If press action move.
            if(canLoadMoreData())
            {
                loadMoreData();
            }
        }

        return super.dispatchTouchEvent(ev);
    }

    private boolean canLoadMoreData()
    {
        boolean ret = false;

        // If just loading, then can not load more data again.
        if(loading)
        {
            ret = false;
        }else
        {
            float deltaX = pressDownX - pressUpX;

            LinearLayoutManager recyclerViewLayoutManager = null;
            RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
            if(layoutManager instanceof LinearLayoutManager)
            {
                recyclerViewLayoutManager = (LinearLayoutManager)layoutManager;
            }

            int firstCompleteVisibleItemPosition = recyclerViewLayoutManager.findFirstCompletelyVisibleItemPosition();
            int lastCompleteVisibleItemPosition = recyclerViewLayoutManager.findLastCompletelyVisibleItemPosition();

            int recyclerViewItemCount = recyclerView.getAdapter().getItemCount();

            float deltaXAbs = Math.abs(deltaX);

            if(deltaXAbs > scaledTouchSlop)
            {
                if(deltaX > 0) {
                    // If scroll from right to left at RecyclerView endding.
                    if(lastCompleteVisibleItemPosition==(recyclerViewItemCount - 1))
                    {
                        ret = true;
                    }

                }else
                {
                    // If scroll from left to right at RecyclerView beginning.
                    if (firstCompleteVisibleItemPosition == 0) {
                        ret = true;
                    }
                }
            }

        }

        return ret;
    }

    private void loadMoreData() {
        if (loadMoreListener != null) {
            setLoading(true);

            boolean insertBeginning = true;

            if(pressDownX > pressUpX)
            {
                insertBeginning = false;
            }
            loadMoreListener.loadMoreData(insertBeginning);
        }
    }
}

4. Custom RecyclerView Load More Listener.

CustomSwipeRefreshLoadMoreListener.java

package com.dev2qa.example.material_design.swipe_refresh_layout;

import android.os.Bundle;
import android.os.Message;

import com.dev2qa.example.R;

/**
 * Created by Jerry on 3/21/2018.
 */

public class CustomSwipeRefreshLoadMoreListener {

    private CustomSwipeRefreshLayoutActivity customSwipeRefreshLayoutActivity;

    public CustomSwipeRefreshLoadMoreListener(CustomSwipeRefreshLayoutActivity customSwipeRefreshLayoutActivity) {
        this.customSwipeRefreshLayoutActivity = customSwipeRefreshLayoutActivity;
    }

    public void loadMoreData(final boolean insertBeginning)
    {
        // Start a child thread to load data from server.
        new Thread()
        {
            @Override
            public void run() {
                try
                {
                    // Emulate read data from server which will cost some times.
                    Thread.sleep(3000);

                    CustomSwipeRecyclerViewItem newItem = new CustomSwipeRecyclerViewItem(R.drawable.car_future);

                    if(insertBeginning)
                    {
                        customSwipeRefreshLayoutActivity.recyclerViewItemList.add(0, newItem);
                    }else {
                        customSwipeRefreshLayoutActivity.recyclerViewItemList.add(newItem);
                    }

                    // Create a message object.
                    Message message = new Message();
                    // Set message purpose.
                    message.what = customSwipeRefreshLayoutActivity.MESSAGE_UPDATE_RECYCLER_VIEW;
                    // Add new item insert position info.
                    Bundle bundle = new Bundle();
                    bundle.putBoolean(customSwipeRefreshLayoutActivity.MESSAGE_KEY_SCROLL_TO_BEGINNING, insertBeginning);
                    message.setData(bundle);
                    // Send the message to main thread Handler to process.
                    customSwipeRefreshLayoutActivity.uiUpdateHandler.sendMessage(message);
                }catch(InterruptedException ex)
                {
                    ex.printStackTrace();
                }
            }
        }.start();
    }
}

5. RecyclerView Data Adapter.

CustomSwipeRecyclerViewDataAdapter.java

package com.dev2qa.example.material_design.swipe_refresh_layout;

import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.dev2qa.example.R;

import java.util.List;

/**
 * Created by Jerry on 3/21/2018.
 */

public class CustomSwipeRecyclerViewDataAdapter extends RecyclerView.Adapter<CustomSwipeRecyclerViewHolder> {

    private List<CustomSwipeRecyclerViewItem> recyclerViewItemList;

    public CustomSwipeRecyclerViewDataAdapter(List<CustomSwipeRecyclerViewItem> recyclerViewItemList) {
        this.recyclerViewItemList = recyclerViewItemList;
    }

    @Override
    public CustomSwipeRecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        // Get LayoutInflater object.
        LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
        // Inflate the RecyclerView item layout xml.
        final View itemView = layoutInflater.inflate(R.layout.activity_custom_swipe_refresh_layout_recycler_view_item, parent, false);

        // Create and return custom swipe refresh layout Recycler View Holder object.
        CustomSwipeRecyclerViewHolder ret = new CustomSwipeRecyclerViewHolder(itemView);
        return ret;
    }

    @Override
    public void onBindViewHolder(CustomSwipeRecyclerViewHolder holder, int position) {
        if(recyclerViewItemList!=null) {
            // Get item dto in list.
            CustomSwipeRecyclerViewItem viewItem = recyclerViewItemList.get(position);

            if(viewItem != null) {
                // Set car image resource id.
                holder.getItemImageView().setImageResource(viewItem.getItemImageId());
            }
        }
    }

    @Override
    public int getItemCount() {
        int ret = 0;
        if(recyclerViewItemList!=null)
        {
            ret = recyclerViewItemList.size();
        }
        return ret;
    }
}

6. RecyclerView View Holder.

CustomSwipeRecyclerViewHolder.java

package com.dev2qa.example.material_design.swipe_refresh_layout;

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;

import com.dev2qa.example.R;

/**
 * Created by Jerry on 3/21/2018.
 */

public class CustomSwipeRecyclerViewHolder extends RecyclerView.ViewHolder {

    private ImageView itemImageView = null;

    public CustomSwipeRecyclerViewHolder(View itemView) {
        super(itemView);

        if(itemView != null)
        {
            itemImageView = (ImageView)itemView.findViewById(R.id.custom_swipe_refresh_layout_recycler_view_item_image_view);
        }
    }

    public ImageView getItemImageView() {
        return itemImageView;
    }
}

7. RecyclerView View Item.

CustomSwipeRecyclerViewItem.java

package com.dev2qa.example.material_design.swipe_refresh_layout;

/**
 * Created by Jerry on 3/21/2018.
 */

public class CustomSwipeRecyclerViewItem {

    private int itemImageId;

    public CustomSwipeRecyclerViewItem(int itemImageId) {
        this.itemImageId = itemImageId;
    }

    public int getItemImageId() {
        return itemImageId;
    }

    public void setItemImageId(int itemImageId) {
        this.itemImageId = itemImageId;
    }
}

8. Main Activity Layout Xml File.

Use the custom swipe refresh layout class in the activity definition layout xml file as below.

READ :   Android Recyclerview Horizontal Scroll Example

activity_custom_swipe_refresh_layout.xml

<com.dev2qa.example.material_design.swipe_refresh_layout.CustomSwipeRefreshLayout
    android:id="@+id/custom_swipe_refresh_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:foregroundGravity="center_vertical">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/custom_swipe_refresh_layout_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</com.dev2qa.example.material_design.swipe_refresh_layout.CustomSwipeRefreshLayout>

9. RecyclerView Item Layout Xml File.

activity_custom_swipe_refresh_layout_recycler_view_item.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="8dp"
    app:cardCornerRadius="10dp"
    app:cardElevation="8dp">

    <ImageView
        android:id="@+id/custom_swipe_refresh_layout_recycler_view_item_image_view"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:scaleType="centerCrop"/>

</android.support.v7.widget.CardView>

Reference

  1. Android Swipe Refresh Layout Example
  2. Android RecyclerView Example
(Visited 1,024 times, 7 visits today)

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.