您的位置:首页 > 其它

RecyclerView 下拉刷新上拉加载更多

2016-11-14 02:31 225 查看
这几天研究了下RecyclerView的使用和封装,发现还是蛮好用的,现在把学习成果分享给大家,主要是关于上拉加载更多的封装,之所以没有封装下拉刷新也是因为SwipeRefreshLayout的存在,并且它更加符合MD风格.

注意该封装只适用于类似listview这种列表形式的

附上效果



先来看看activity中使用该控件的代码

[java] view
plain copy







package com.byzk.www.recyclerviewpackage;

import android.os.Bundle;

import android.os.Handler;

import android.support.v4.widget.SwipeRefreshLayout;

import android.support.v7.app.AppCompatActivity;

import android.support.v7.widget.LinearLayoutManager;

import java.util.ArrayList;

import java.util.List;

public class MainActivity extends AppCompatActivity {

private List<String> dataList = new ArrayList<>();

private RefreshRecyclerView rv;

private MyAdapter myAdapter;

private SwipeRefreshLayout srl;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

initView();

initData();

initListener();

}

private void initView() {

srl = (SwipeRefreshLayout) findViewById(R.id.srl);

srl.setColorSchemeResources(android.R.color.holo_red_light, android.R.color.holo_blue_light, android.R.color.holo_green_light);

rv = (RefreshRecyclerView) findViewById(R.id.rv);

rv.setLayoutManager(new LinearLayoutManager(this));

rv.setLoadMoreEnable(true);//允许加载更多

rv.setFooterResource(R.layout.item_footer);//设置脚布局

myAdapter = new MyAdapter(dataList);

rv.setAdapter(myAdapter);

}

private void initData() {

for (int i = 0; i < 20; i++) {

dataList.add("数据" + i);

}

rv.notifyData();

}

private void initListener() {

rv.setOnLoadMoreListener(new RefreshRecyclerView.OnLoadMoreListener() {

@Override

public void loadMoreListener() {

handler.postDelayed(new Runnable() {

@Override

public void run() {

for (int i = 0; i < 10; i++) {

dataList.add("更多数据" + i);

}

rv.notifyData();//刷新数据

}

}, 2000);

}

});

srl.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {

@Override

public void onRefresh() {

handler.postDelayed(new Runnable() {

@Override

public void run() {

srl.setRefreshing(false);

dataList.add(0, "最新数据");

rv.notifyData();//刷新数据

}

}, 2000);

}

});

}

private Handler handler = new Handler();

}

可以发现activity中,recyclerview的写法没有太大变化,只是有如下几点需要注意

1.如果想要加载更多需要调用(必须)

rv.setLoadMoreEnable(true)

2.如果希望加载更多时候有脚布局提示需要调用(不是必须的)

rv.setFooterResource(int res)

3.实现加载更多回调(必须)

rv.setOnLoadMoreListener()

4.刷新数据调用(必须)

rv.notifyData()

activity布局代码

[java] view
plain copy







<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

tools:context="com.byzk.www.recyclerviewpackage.MainActivity">

<android.support.v4.widget.SwipeRefreshLayout

android:id="@+id/srl"

android:layout_width="wrap_content"

android:layout_height="wrap_content">

<com.byzk.www.recyclerviewpackage.RefreshRecyclerView

android:id="@+id/rv"

android:layout_width="match_parent"

android:layout_height="wrap_content" />

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

</RelativeLayout>

下拉刷新用的是v4包中的SwipeRefreshLayout直接包裹在自己封装的RecyclerView的外层,上拉加载更多用的是自己封装的RecyclerView.

前方高能,接下来有一大波代码来袭,核心代码RecyclerView的封装如下

[java] view
plain copy







package com.byzk.www.recyclerviewpackage;

import android.content.Context;

import android.support.v7.widget.LinearLayoutManager;

import android.support.v7.widget.RecyclerView;

import android.util.AttributeSet;

import android.util.Log;

import android.view.LayoutInflater;

import android.view.MotionEvent;

import android.view.View;

import android.view.ViewGroup;

import jp.wasabeef.recyclerview.animators.adapters.SlideInBottomAnimationAdapter;

/**

* Author: zhuliyuan

* Time: 下午 3:26

* 将脚布局放在最后一个条目,当加载更多的时候显示,加载完成的时候隐藏

*

*/

public class RefreshRecyclerView extends RecyclerView {

private AutoLoadAdapter autoLoadAdapter;

public RefreshRecyclerView(Context context) {

this(context, null);

}

public RefreshRecyclerView(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public RefreshRecyclerView(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

init();

}

private boolean isLoadingMore = false;//是否正在加载更多

private OnLoadMoreListener loadMoreListener;//加载数据监听

private boolean loadMoreEnable = false;//是否允许加载更多

private int footerResource = -1;//脚布局

private boolean footer_visible = false;//脚部是否可以见

private void init() {

setOnScrollListener(new OnScrollListener() {

@Override

public void onScrollStateChanged(RecyclerView recyclerView, int newState) {

super.onScrollStateChanged(recyclerView, newState);

if (getAdapter() != null && getLayoutManager() != null) {

int lastVisiblePosition = ((LinearLayoutManager) getLayoutManager()).findLastVisibleItemPosition();

int itemCount = getAdapter().getItemCount();

/**

* 控制下拉刷新回调

* itemCount != 0 排除没有数据情况

* lastVisiblePosition + 4 >= itemCount - 1 最后可见+4 >= 总条数 加载更多

* distanceY < 0 为上拉的时候才刷新

*/

if (distanceY < 0 && itemCount != 0 && lastVisiblePosition + 4 >= itemCount - 1 && !isLoadingMore && loadMoreEnable) {

Log.i("test","加载更多");

//正在加载更多

loading();

if (footerResource != -1){//有脚布局

//显示脚布局

footer_visible = true;

getAdapter().notifyItemChanged(itemCount - 1);

}

if (loadMoreListener != null) {

loadMoreListener.loadMoreListener();

}

}

}

}

});

}

/**

* 判断滑动方向

*/

private float distanceY = 0;

float startY = 0;

@Override

public boolean dispatchTouchEvent(MotionEvent ev) {

float y = ev.getRawY();

switch (ev.getAction()){

case MotionEvent.ACTION_DOWN:

startY = y;

break;

case MotionEvent.ACTION_MOVE:

distanceY = y - startY;

startY = y;

break;

}

return super.dispatchTouchEvent(ev);

}

@Override

public void setAdapter(Adapter adapter) {

SlideInBottomAnimationAdapter slideInBottomAnimationAdapter = new SlideInBottomAnimationAdapter(adapter);

slideInBottomAnimationAdapter.setDuration(600);

autoLoadAdapter = new AutoLoadAdapter(slideInBottomAnimationAdapter);//添加动画

super.setAdapter(autoLoadAdapter);

}

/**

* 设置是否允许加载更多

*

* @param isEnable

*/

public void setLoadMoreEnable(boolean isEnable) {

this.loadMoreEnable = isEnable;

}

/**

* 设置脚布局

*/

public void setFooterResource(int footerResource) {

this.footerResource = footerResource;

}

/**

* 加载完成

*/

private void loadMoreComplete() {

this.isLoadingMore = false;

}

/**

* 正在刷新

*/

private void loading(){

this.isLoadingMore = true;//设置正在刷新

}

/**

* 加载更多数据回调

*

* @param listener

*/

public void setOnLoadMoreListener(OnLoadMoreListener listener) {

this.loadMoreListener = listener;

}

public interface OnLoadMoreListener {

void loadMoreListener();//上拉刷新

}

/**

* 刷新数据

*/

public void notifyData() {

if (getAdapter() != null) {

loadMoreComplete();

if(footerResource != -1 && loadMoreEnable){

//隐藏脚布局

footer_visible = false;

}

getAdapter().notifyDataSetChanged();

}

}

public class AutoLoadAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

private Adapter dataAdapter;//数据adapter

private final int TYPE_FOOTER = Integer.MAX_VALUE;//底部布局

public AutoLoadAdapter(RecyclerView.Adapter adapter) {

this.dataAdapter = adapter;

}

@Override

public int getItemViewType(int position) {

if (position == getItemCount() - 1 && loadMoreEnable && footerResource != -1 && footer_visible) {

return TYPE_FOOTER;

}

if (dataAdapter.getItemViewType(position) == TYPE_FOOTER) {

throw new RuntimeException("adapter中itemType不能为:" + Integer.MAX_VALUE);

}

return dataAdapter.getItemViewType(position);

}

@Override

public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

ViewHolder holder = null;

if (viewType == TYPE_FOOTER) {//脚部

holder = new FooterViewHolder(LayoutInflater.from(getContext()).inflate(footerResource, parent, false));

} else {//数据

holder = dataAdapter.onCreateViewHolder(parent, viewType);

}

return holder;

}

@Override

public void onBindViewHolder(ViewHolder holder, int position) {

int itemViewType = getItemViewType(position);

if (itemViewType != TYPE_FOOTER) {

dataAdapter.onBindViewHolder(holder, position);

}

}

@Override

public int getItemCount() {

if (dataAdapter.getItemCount() != 0) {

int count = dataAdapter.getItemCount();

if (loadMoreEnable && footerResource != -1 && footer_visible) {

count++;

}

return count;

}

return 0;

}

public class FooterViewHolder extends RecyclerView.ViewHolder {

public FooterViewHolder(View itemView) {

super(itemView);

}

}

}

}

这里封装了上拉加载更多,自己写了个adpter壳子,当允许上拉加载更多并且设置了脚布局的时候将脚布局加载到最后一个条目,根据最后可见条目位置与总条数的比较来回调加载更多刷新,其他时候数据都来源于自己写的DataAdapter,下拉刷新可以按同样原理实现为了MD设计风格,这里我就直接套的SwipeRefreshLayout了.

提供数据Adapter如下

[java] view
plain copy







package com.byzk.www.recyclerviewpackage;

import android.support.v7.widget.RecyclerView;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import android.widget.TextView;

import java.util.List;

/**

* Author: zhuliyuan

* Time: 下午 5:36

*/

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {

private List<String> dataList;

public MyAdapter(List<String> dataList) {

this.dataList = dataList;

}

@Override

public MyAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

MyViewHolder myViewHolder = new MyViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false));

return myViewHolder;

}

@Override

public void onBindViewHolder(MyAdapter.MyViewHolder holder, int position) {

holder.tv.setText(dataList.get(position));

}

public class MyViewHolder extends RecyclerView.ViewHolder{

private TextView tv;

public MyViewHolder(View itemView) {

super(itemView);

tv = (TextView) itemView.findViewById(R.id.tv);

}

}

@Override

public int getItemCount() {

return (dataList == null || dataList.size() == 0)?0:dataList.size();

}

}

item布局如下

[java] view
plain copy







<?xml version="1.0" encoding="utf-8"?>

<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:card_view="http://schemas.android.com/apk/res-auto"

android:layout_width="match_parent"

android:layout_height="80dp"

android:layout_marginLeft="5dp"

android:layout_marginRight="5dp"

android:layout_marginTop="10dp"

android:clickable="true"

android:foreground="?attr/selectableItemBackground"

card_view:cardBackgroundColor="#0094ff"

card_view:cardCornerRadius="6dp"

card_view:cardElevation="5dp">

<TextView

android:id="@+id/tv"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="center"

android:text="哈哈哈"

android:textColor="#fff" />

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

提供数据adapter和item布局都是普通写法,这里不过多赘言

源码传送门

项目中recyclerview动画地址https://github.com/wasabeef/recyclerview-animators

到此封装完成,,如果有bug或者建议欢迎留言.

转自:http://blog.csdn.net/zly921112/article/details/50370494
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐