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:
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
- Pull-down refresh: SwipeRefreshLayout of Google's official v4 package is used for data pull-down refresh operation.
- 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.
- 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.