RecyclerView下拉刷新、上拉加载、Item点击监听
下拉刷新,上拉加载更多,推荐使用SmartRefreshLayout
支持各种控件,可自定义加载样式……
地址: https://github.com/scwang90/SmartRefreshLayout
效果图:
备注:item点击效果没有加上,所以演示只是Toast第几个item点击了,视觉上看不出来,童鞋们可以自己copy代码试一下效果。
实现原理
- 下拉刷新:采用了google官方的v4包的SwipeRefreshLayout进行数据的下拉刷新操作。
- 上拉加载更多:采用了在《RecyclerView系列(一)》中给RecyclerView添加FootView的方法,然后监听当前屏幕最后一个可见item的的底部位置是否等于RecyclerView的底部位置,如果相等,说明此时已经滑动到最底部了,FootView也是可见状态。因此进行更多数据的加载。
- Item的点击事件:
(A)在所用的Adapter当中构造一个**OnItemClickListener接口并设置该接口可以实现的方法void OnItemClick(View view, int position, String url);
(B)在onCreateViewHolder()生成item布局view的时候给该view设置点击监听setOnClickListener(this)然后让该Adapter实现点击事件的监听。
(C)在onBindViewHolder()方法里给holder.itemView设置tag,使其携带数据。(D)在OnClick(){}实现里边进行设置OnItemClickListener的内部方法的实现。
代码一览:
Adapter代码内容
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);
}
}
Adapter用到的item布局,图片就不上传了。
<?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>
Adapter用到的FootView的xml
<?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>
Activity中使用Adaprer的代码
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!有兴趣的就赶紧copy代码试验一下吧。