0
点赞
收藏
分享

微信扫一扫

RecyclerView简单案例&添加下拉刷新(SwipeRefreshLayout)、上拉加载(lastVisibleItem)


效果图如下


![这里写图片描述](https://img-blog.csdnimg.cn/img_convert/d4d5c8c88118f0cfa26f9a1f8c29c064.gif)

一、先看各个布局

  1. activity_main
    使用SwipeRefreshLayout包裹RecyclerView

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/srl"
android:layout_width="match_parent"
android:layout_height="match_parent">

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

</android.support.v4.widget.SwipeRefreshLayout>

</LinearLayout>

  1. list_item
    只显示一个一个字符串

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >

<TextView
android:id="@+id/tv_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="15dp"
android:textSize="18sp" />

<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#fcc" />

</LinearLayout>

  1. list_foot
    最后一个条目可见时加载更多数据(一个loading和文字提示)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="10dp">

<ProgressBar
android:id="@+id/pb_loading"
style="@android:style/Widget.ProgressBar.Inverse"
android:layout_width="26dp"
android:layout_height="26dp"
android:layout_marginLeft="130dp"/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text="松开加载"
android:textColor="#c0f0"
android:textSize="20sp"/>

</LinearLayout>

二、适配器的实现(★)

  1. RecyclerView的适配器(要熟练掌握哦)
    分析数据应该如何展示,完整代码紧跟在分析之后
  1. 怎么区分当前位置要展示的具体布局类型
    ListView中我们很熟悉了,通过​​getViewTypeCount(): Int​​获取需要展示的布局数目(如2),然后通过​​getItemViewType(): Int​​获取当前位置需要展示的具体布局类型
    ↑ VS ↓
    RecyclerView中仅使用​​getItemViewType(): Int​​即可获得当前位置对应的布局类型,用法和ListView的​​getItemViewType(): Int​​别无它异,具体参考下面的完整代码
  2. ViewHolder如何创建
    ListView中需要手动创建静态Holder,并在​​getView(): View​​中先后手动​​setTag()​​和​​getTag()​​来获取holder,然后进行控件内容的填充
    ↑ VS ↓
    RecyclerView已帮我们集成进了ViewHolder(这也是Recycler的核心),只要继承​​RecyclerView.Adapter​​时添加泛型​​RecyclerView.ViewHolder​​,然后分别添加各布局对应的Holder类(类中初始化控件),最后在​​onCreateViewHolder: RecyclerView.ViewHolder​​中通过各布局类型创建对应的Holder实例即可
  3. 如何通过ViewHolder填充数据
    ListView中在​​getView(): View​​的缓存复用、holder的​​setTag()​​完成后直接进行控件内容的填充
    ↑ VS ↓
    RecyclerView中,我们单独在​​onBindViewHolder(holder): void​​方法中通过转换holder类型后进行控件内容的填充

public class SampleAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
// 要展示的数据集合
private List<String> mDatas;

// 判断布局类型
private static final int TYPE_ITEM = 0;
private static final int TYPE_FOOT = 1;


/**
* 初始化工作(在这里是获得了数据集合)
*/
public SampleAdapter(List<String> datas) {
mDatas = datas;
}


/**
* 当前位置应该展示的条目布局的类型
*/
@Override public int getItemViewType(int position) {
// 数据集合最后一行数据之后的那一行就应该加载脚布局
if (position + 1 == getItemCount()) {
return TYPE_FOOT;
} else {
return TYPE_ITEM;
}
}


/**
* 设置各布局,并返回与其对应的ViewHolder实例
*/
@Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = null;
RecyclerView.ViewHolder holder = null;

if (viewType == TYPE_ITEM) {
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, null);
holder = new ItemHolder(view);

} else if (viewType == TYPE_FOOT) {
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_foot, null);
holder = new FootHolder(view);
} else {
// 默认的布局及其对应的ViewHolder实例,防止发生意外
// default view = ...
// default holder = ...
}

return holder;
}


/**
* 填充各布局的控件内容
*/
@Override public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
if (holder instanceof ItemHolder) {
((ItemHolder) holder).tvText.setText(String.valueOf(mDatas.get(position)));
}
}


/**
* 要展示的条目总数(包括所有数据集合和额外添加的头、身、脚条目数量)
*/
@Override public int getItemCount() {
return mDatas.size() + 1;
}


/****************************************
* 各布局类型的ViewHolder
*/
class FootHolder extends RecyclerView.ViewHolder {
public FootHolder(View view) {
super(view);
}
}

class ItemHolder extends RecyclerView.ViewHolder {
// 展示一行字符串
@BindView(R.id.tv_text) TextView tvText;

public ItemHolder(View view) {
super(view);
ButterKnife.bind(this, view);
}
}
}

三、Activity中如何展示并添加刷新和加载逻辑

注意数据集合发生变化,需要使用mAdapter.notifyItemRemoved(position)来告知适配器以进行界面刷新

public class MainActivity extends BaseActivity {

@BindView(R.id.srl) SwipeRefreshLayout srl;
@BindView(R.id.rv) RecyclerView rv;

/**
* 布局管理器
* 1. LinearLayoutManager:支持横向、纵向
* 2. GridLayoutManager:网格
* 3. StaggeredGridLayoutManager:瀑布流
*/
private LinearLayoutManager mLayoutManager;

private List<String> mDatas;
private SampleAdapter mAdapter;

// 记录最后可见条目
private int lastVisible;

// 分别记录刷新和加载次数
int refreshTimes = 0;
int addmoreTimes = 0;


@Override int layoutId() {
return R.layout.activity_main;
}


/**
* 初始化数据
*/
@Override void initData() {
mDatas = new ArrayList<String>();
for (int i = 0; i < 15; i++) {
mDatas.add("数据== " + (i + 1) + " ==");
}
}


@Override void initView() {
srl.setColorSchemeResources(R.color.color1, R.color.color2, R.color.color3, R.color.color4);
srl.setOnRefreshListener(this);

rv.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
// 不在滑动和最后可见条目是脚布局时加载更多
if (newState == RecyclerView.SCROLL_STATE_IDLE && lastVisible + 1 == mAdapter.getItemCount()) {
addmore();
}
}

@Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
lastVisible = mLayoutManager.findLastVisibleItemPosition();
}

});

rv.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(this);
rv.setLayoutManager(mLayoutManager);
rv.setItemAnimator(new DefaultItemAnimator());

mAdapter = new SampleAdapter(mDatas);
rv.setAdapter(mAdapter);
}


/**
* 模仿下拉刷新
*/
@Override void srlRefresh() {
mDatas.add(0, "刷新 " + ++refreshTimes + "次");

new Timer().schedule(new TimerTask() {
@Override public void run() {
runOnUiThread(new Runnable() {
@Override public void run() {
Toast.makeText(MainActivity.this, "刷新" + refreshTimes, Toast.LENGTH_SHORT).show();
srl.setRefreshing(false);
mAdapter.notifyDataSetChanged();
}
});
}
}, 1000);
}


/**
* 模仿上拉加载
*/
void addmore() {
new Timer().schedule(new TimerTask() {
@Override public void run() {
runOnUiThread(new Runnable() {
@Override public void run() {
mDatas.add("数据增加" + ++addmoreTimes);
Toast.makeText(MainActivity.this, "加载" + addmoreTimes, Toast.LENGTH_SHORT).show();
mAdapter.notifyItemInserted(mDatas.size());
}
});
}
}, 1000);
}
}


举报

相关推荐

0 条评论