RecyclerView series (two) pull-down refresh, pull-up loading, item click monitoring

RecyclerView pull-down refresh, pull-up loading, item click monitoring

Pull down to refresh, pull up to load more. It is recommended to use SmartRefreshLayout to
support various controls and customize the loading style...
Address: https://github.com/scwang90/SmartRefreshLayout

Effect picture:

Effect picture

Note: The item click effect is not added, so the demonstration is only the first item of Toast clicked, which is not visually visible. Children's shoes can copy the code and try the effect by themselves.

Implementation principle

  1. Pull-down refresh: SwipeRefreshLayout of Google's official v4 package is used for data pull-down refresh operation.
  2. Pull up to load more: adopt the method of adding FootView to RecyclerView in "RecyclerView Series (1)" , and then monitor whether the bottom position of the last visible item on the current screen is equal to the bottom position of RecyclerView. If it is equal, it means that it has Slide to the bottom, FootView is also visible. Therefore, more data is loaded.
  3. Item click event:
    (A) Construct a **OnItemClickListener interface in the Adapter used and set the method that the interface can implement void OnItemClick(View view, int position, String url);
    (B ) Generate item layout in onCreateViewHolder() Set the click listener setOnClickListener(this) for the view when viewing, and then let the Adapter implement the click event listener.
    (C) Set tag to holder.itemView in the onBindViewHolder() method to make it carry data. (D) Implement the internal method of setting OnItemClickListener in the OnClick(){} implementation.

Code list:

Adapter code content

package adapter;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.example.zpf.animmenu.R;

import java.util.ArrayList;

/**
 * 下拉刷新,上拉加载更多,ItemClickListener
 */

public class RvAdapterItemClick extends RecyclerView.Adapter<RvAdapterItemClick.ItemClickViewHolder>
        implements View.OnClickListener{
    
    

    private final int TYPE_FOOT = -1;
    private final int TYPE_ITEM = 0;
    /**
     * 规定每次加载更多返回数据为10条,如果数据count < 10则说明没有更多数据了,反之则有更多数据
     * */
    private final int COUNT_LOAD_MORE = 10;

    private Context mContext;
    private ArrayList<String> strings = new ArrayList<>();
    private OnItemClickListener listener;
    private View footView;
    /**
     * 用来记录RecyclerView是否正在加载数据,防止多次请求数据
     * */
    private boolean isLoading = false;
    /**
     * 记录是否还有更多数据,用来设置Foot——View显示与否
     * */
    private boolean hasMoreData = false;

    public RvAdapterItemClick(Context context) {

        this.mContext = context;
    }

    public boolean isLoading() {
        return isLoading;
    }

    public void setLoading(boolean loading) {
        isLoading = loading;
    }

    @Override
    public void onClick(View view) {

        if (listener != null) {

            listener.OnItemClick(view, (Integer) view.getTag(R.id.iv_item_head_foot),
                    (String) view.getTag(R.layout.item_head_foot_rv));
        }
    }


    public interface OnItemClickListener{
    
    

        void OnItemClick(View view, int position, String url);
    }

    public void setOnItemClickListener(OnItemClickListener listener) {

        this.listener = listener;
    }

    public void setModels(ArrayList<String> strings) {

        if (strings != null && !strings.isEmpty()) {

            this.strings = strings;
            hasMoreData = !(strings.size() < COUNT_LOAD_MORE);
            notifyDataSetChanged();
        }
    }

    public void appendModels(ArrayList<String> strings) {

        if (strings != null && !strings.isEmpty()) {

            this.strings.addAll(strings);
            hasMoreData = !(strings.size() < COUNT_LOAD_MORE);

        } else
            hasMoreData = false;

        setFootView(hasMoreData);

        notifyDataSetChanged();
    }

    @Override
    public int getItemViewType(int position) {
        return position == strings.size() ? TYPE_FOOT : TYPE_ITEM;
    }

    @Override
    public ItemClickViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {

        View view;
        if (viewType == TYPE_FOOT) {

            view = footView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_foot_rv, viewGroup, false);
            setFootView(hasMoreData);

        } else {

            view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_head_foot_rv, viewGroup, false);
            view.setOnClickListener(this);

        }
        return new ItemClickViewHolder(view, viewType);
    }

    @Override
    public void onBindViewHolder(ItemClickViewHolder holder, int position) {

        if (getItemViewType(position) == TYPE_FOOT)
            return;

        String url = strings.get(position);
        //通过setTag将该item对应的url信息保存,用于item点击事件Toast显示
        holder.itemView.setTag(R.layout.item_head_foot_rv, url);
        holder.itemView.setTag(R.id.iv_item_head_foot, position);
        holder.tv.setText(url);

    }

    @Override
    public int getItemCount() {
        //添加了一个Foot—View,所以 +1;
        return strings.size() + 1;
    }

    class ItemClickViewHolder extends ViewHolder{

        private ImageView iv;
        private TextView tv;

        ItemClickViewHolder(View itemView, int viewType) {
            super(itemView);

            if (viewType == TYPE_FOOT)
                return;

            iv = (ImageView) itemView.findViewById(R.id.iv_item_head_foot);
            tv = (TextView) itemView.findViewById(R.id.tv_item_head_foot);

        }
    }

    /**
     * 根据是否还有更多数据处理FootView显示与否
     * */
    private void setFootView(boolean hasMoreData) {

        if (hasMoreData && footView != null)
            footView.setVisibility(View.VISIBLE);
        else if (footView != null)
            footView.setVisibility(View.GONE);
    }
}

For the item layout used by the Adapter, the picture will not be uploaded.

<?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="match_parent"
    android:layout_height="wrap_content"
    app:contentPadding="8dp"
    app:cardElevation="2dp"
    app:cardUseCompatPadding="true">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/iv_item_head_foot"
            android:layout_width="56dp"
            android:layout_height="56dp"
            android:contentDescription="@null"
            android:src="@mipmap/bg_loading"
            android:scaleType="centerCrop"/>

        <TextView
            android:id="@+id/tv_item_head_foot"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:textSize="14sp"
            android:lines="2"
            android:lineSpacingMultiplier="1.2"/>
    </LinearLayout>

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

FootView xml used by Adapter

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:orientation="horizontal">

    <ProgressBar
        android:layout_width="24dp"
        android:layout_height="24dp"
        style="@style/Base.TextAppearance.AppCompat.Small.Inverse"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="加载更多"
        android:layout_margin="16dp"
        android:textSize="14sp"/>

    <ProgressBar
        android:layout_width="24dp"
        android:layout_height="24dp"
        style="@style/Base.TextAppearance.AppCompat.Small.Inverse"/>

</LinearLayout>

Code using Adaprer in Activity

package com.example.zpf.animmenu;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.Arrays;

import adapter.RvAdapterItemClick;

public class RecyclerItemClickActivity extends BaseActivity {
    
    

    private final String[] urls = {
            "http://hbimg.b0.upaiyun.com/6293fd60a2597a6017633e3c8e3816d89b70dc2165ad9-jkFvRh_fw658",
            "http://icon.nipic.com/BannerPic/20160426/photo/20160426160807.jpg",
            "http://icon.nipic.com/BannerPic/20160426/photo/20160426160826.jpg",
            "http://icon.nipic.com/BannerPic/20160426/photo/20160426160848.jpg",
            "http://icon.nipic.com/BannerPic/20160426/photo/20160426160908.jpg",
            "http://icon.nipic.com/BannerPic/20160426/photo/20160426160926.jpg",
            "http://pic94.nipic.com/file/20160409/11284670_185122899000_2.jpg",
            "http://pic94.nipic.com/file/20160403/22743169_220209251000_2.jpg",
            "http://pic94.nipic.com/file/20160410/18807750_102028863000_2.jpg",
            "http://pic94.nipic.com/file/20160406/22743169_234848884000_2.jpg",
            "http://pic94.nipic.com/file/20160406/19700831_040444643000_2.jpg",
            "http://pic94.nipic.com/file/20160321/7874840_094355922000_2.jpg",
            "http://pic94.nipic.com/file/20160406/22743169_233812263000_2.jpg",
            "http://pic94.nipic.com/file/20160407/21544848_224025191000_2.jpg"};

    /**
     * 模拟下拉的handler message what
     * */
    private final int MSG_DATA_DOWN = 0;

    /**
     * 模拟上拉加载更多的handler message what
     * */
    private final int MSG_DATA_UP = 1;

    private SwipeRefreshLayout refreshLayout;
    private RvAdapterItemClick adapterItemClick;

    private Handler handler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);

            doMessage(msg);
        }
    };

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

        initView();
    }

    private void initView() {

        refreshLayout = (SwipeRefreshLayout) findViewById(R.id.srl_item_click);
        refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {

                refreshLayout.setRefreshing(true);
                handler.sendEmptyMessageDelayed(MSG_DATA_DOWN, 3000);
            }
        });

        RecyclerView rv = (RecyclerView) findViewById(R.id.rv_item_click);
        rv.setLayoutManager(new LinearLayoutManager(this));
        rv.setHasFixedSize(true);
        rv.addOnScrollListener(new RecyclerView.OnScrollListener() {

            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);

                LinearLayoutManager manager = (LinearLayoutManager) recyclerView.getLayoutManager();
                int lastPosition = manager.findLastVisibleItemPosition();
                View viewLast = manager.findViewByPosition(lastPosition);

                //viewFoot.getBottom() == recyclerView.getBottom() 表示已经滑动到最底部
                if (viewLast != null && viewLast.getBottom() == recyclerView.getBottom() &&
                        !adapterItemClick.isLoading()) {

                    //将加载数据状态设置true,防止多次加载,在doMessage里将值重置
                    adapterItemClick.setLoading(true);

                    //模拟三秒后获取到数据
                    handler.sendEmptyMessageDelayed(MSG_DATA_UP, 3000);
                }
            }
        });

        adapterItemClick = new RvAdapterItemClick(this);
        rv.setAdapter(adapterItemClick);

        ArrayList<String> strings = new ArrayList<>();
        strings.addAll(Arrays.asList(urls));
        adapterItemClick.setModels(strings);

        adapterItemClick.setOnItemClickListener(new RvAdapterItemClick.OnItemClickListener() {
            @Override
            public void OnItemClick(View view, int position, String url) {

                //RecyclerView的ItemClick点击事件的处理
                Toast.makeText(RecyclerItemClickActivity.this, String.valueOf(position),
                        Toast.LENGTH_SHORT).show();
            }
        });

    }

    /**
     * 模拟网络请求数据返回结果处理
     * */
    private void doMessage(Message msg) {

        //模拟下拉数据反馈处理
        if (msg.what == MSG_DATA_DOWN) {

            refreshLayout.setRefreshing(false);

            ArrayList<String> urlList = new ArrayList<>();
            urlList.addAll(Arrays.asList(urls));
            adapterItemClick.setModels(urlList);

        }
        //模拟上拉数据反馈处理
        else if (msg.what == MSG_DATA_UP) {

            adapterItemClick.setLoading(false);

            ArrayList<String> strings = new ArrayList<>();
            strings.addAll(Arrays.asList(urls));
            adapterItemClick.appendModels(strings);
        }
    }
}

Ok, That's all! If you are interested, please copy the code and try it.

Guess you like

Origin blog.csdn.net/nsacer/article/details/72669060