标签:
在实际开发中,为了节省开发周期,下拉刷新上拉加载通常都会采取使用一些第三方库,典型的就是用PullToRefresh,XListView等等,还有就是谷歌推荐的SwipeRefreshLayout,可惜没有上拉加载功能,需要自己去实现一个上拉加载的脚View,再加上现在代替ListView的RecyclerView+CardView使用的频率也是也来也高,不得不说,CardView效果确实很好看,一个一个的小卡片,用户体验好,I like it!!!废话不说了,奔主题!今天也玩了一下SwipeRefreshLayout+RecyclerView实现下拉刷新上拉自动加载。
我最初的想法就是:先利用RecyclerView添加不同的item布局,上面是一个轮播的ViewPager,下面是一个一个的列表数据,当滑到到底部的时候,可以自动加载更多,当然要在底部添加一个个性化的视图显示正在加载,即脚View。
先看一下RecyclerView如何加载不同的item的,通过getItemViewType实现,注意:继承的是RecyclerView.Adapter。
1.设置3个常量,分别是ViewPager部分,中间的列表数据部分,和底部的正在加载脚部分:
private static final int ITEM_HEADER = 0;
private static final int ITEM_ITEM = 1;
private static final int ITEM_LOAD_FOOTER = 2;
三个上拉加载更多的显示状态:
//上拉加载更多
public static final int PULLUP_LOAD_MORE=0;
//正在加载...
public static final int ISLOADING=1;
//上拉加载的显示状态,初始为0
private int load_more_status=0;
Adapter里设置的一个方法,方便Activity调用改变加载状态来显示不同的加载信息(上拉加载更多,加载中…):
public void changeMoreStatus(int status){
load_more_status=status;
notifyDataSetChanged();
}
2.创建Viewholder:
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if(viewType==ITEM_HEADER){
View view = LayoutInflater.from(context).inflate(R.layout.item_header,parent,false);
return new HeaderViewHolder(view);
}else if(viewType==ITEM_ITEM){
View view = LayoutInflater.from(context).inflate(R.layout.item_item,parent,false);
return new ItemViewHolder(view);
}else if(viewType==ITEM_LOAD_FOOTER){
View view = LayoutInflater.from(context).inflate(R.layout.refresh_footer,parent,false);
return new LoadFooterViewHolder(view);
}
return null;
}
3.绑定数据:
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
if(holder instanceof ItemViewHolder){
((ItemViewHolder) holder).mTextView.setText(mListData.get(position-1));
}else if(holder instanceof LoadFooterViewHolder){
LoadFooterViewHolder footer = (LoadFooterViewHolder) holder;
switch(load_more_status){
case PULLUP_LOAD_MORE:
footer.progressbar.setVisibility(View.GONE);
footer.loadmore_text.setText("上拉加载更多");
break;
case ISLOADING:
footer.progressbar.setVisibility(View.VISIBLE);
footer.loadmore_text.setText("正在加载...");
break;
}
}
//列表数据的点击事件监听,注意:这里的position是比正常的position+1的,因为多加了一个头部View
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(context, "点击了位置"+position, Toast.LENGTH_SHORT).show();
}
});
}
说明:这里只处理了中间列表的数据,ViewPager部分的数据不在这处理。
4.获取item的数量:
@Override
public int getItemCount() {
return mListData.size()+2;
}
说明:+2是因为除了正常的列表数据外,还多加了一个头和脚View
5.ItemView类型:
@Override
public int getItemViewType(int position) {
if(position==0){
return ITEM_HEADER;
}else if(position==mListData.size()+1){
return ITEM_LOAD_FOOTER;
}else {
return ITEM_ITEM;
}
}
说明:第一项添加一个ViewPager,最后一项添加一个正在加载的脚View,剩下的中间的全部就是正常的列表数据。
下面的三个view内部类:
class HeaderViewHolder extends RecyclerView.ViewHolder{
private ViewPager mViewPager;
private LinearLayout linearlayout;
private ImageView[] points;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
mViewPager.setCurrentItem(mViewPager.getCurrentItem()+1);
handler.sendEmptyMessageDelayed(1,3000);
}
};
public HeaderViewHolder(View itemView) {
super(itemView);
mViewPager = (ViewPager) itemView.findViewById(R.id.viewpager);
linearlayout = (LinearLayout) itemView.findViewById(R.id.linearlayout);
//下面两句要在setAdapter之前调用,否则会出现先加载最后一张图片的情况
mViewPager.setCurrentItem(Integer.MAX_VALUE/2);
handler.sendEmptyMessageDelayed(1,3000);
mViewPager.setAdapter(new MyViewPagerAdapter(context, imagesUrl));
initPoint();
mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
for(int i=0;i<imagesUrl.length;i++){
if(position%imagesUrl.length==i){
points[i].setImageResource(R.drawable.point_focus);
}else {
points[i].setImageResource(R.drawable.point_normal);
}
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
private void initPoint() {
points = new ImageView[imagesUrl.length];
for(int i=0;i<points.length;i++){
points[i] = (ImageView) linearlayout.getChildAt(i);
}
points[0].setImageResource(R.drawable.point_focus);
}
}
class ItemViewHolder extends RecyclerView.ViewHolder{
private TextView mTextView;
public ItemViewHolder(View itemView) {
super(itemView);
mTextView = (TextView) itemView.findViewById(R.id.textview);
}
}
class LoadFooterViewHolder extends RecyclerView.ViewHolder{
private ProgressBar loarmore_progressbar;
private TextView loadmore_text;
public LoadFooterViewHolder(View itemView) {
super(itemView);
loarmore_progressbar= (ProgressBar) itemView.findViewById(R.id.loarmore_progressbar);
loadmore_text = (TextView) itemView.findViewById(R.id.loadmore_text);
}
}
说明:可以看出,我头部ViewPager的数据全是在内部类中处理的。
中间是列表数据,第3步绑定数据那里处理的,最下面是加载脚View,在上面的绑定数据那里设置了动态的显示不同的加载状态。
OK 这样数据适配器就搞定了!
下拉刷新有谷歌的SwipeRefreshLayout实现了,该如何检测到何时滑到底了需要加载新数据了呢。方法如下:
//向上滑动,当滑到底的时候,有上滑的趋势,就加载更多
mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if(!mSwipeRefreshLayout.isRefreshing()){
if(newState==RecyclerView.SCROLL_STATE_IDLE&&mAdapter.getItemCount()==lastVisibleItem+1){
//调用Adapter里的changeMoreStatus方法来改变加载脚View的显示状态为:正在加载...
mAdapter.changeMoreStatus(MyRecyclerViewAdapter.ISLOADING);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mListData.addAll(mListLoadData);
mAdapter.notifyDataSetChanged();
//当加载完数据后,再恢复加载脚View的显示状态为:上拉加载更多
mAdapter.changeMoreStatus(MyRecyclerViewAdapter.PULLUP_LOAD_MORE);
}
},3000);
}
}
}
说明:RecyclerView有一个setOnScrollListener方法,加载更多的逻辑就在这里面实现,具体不说了,看一下就明白了。
MainActivity的完整代码:
package com.example.lenovo.recyclerview;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
import Adapter.MyRecyclerViewAdapter;
public class MainActivity extends Activity {
private RecyclerView mRecyclerView;
private SwipeRefreshLayout mSwipeRefreshLayout;
private LinearLayoutManager mManager;
private MyRecyclerViewAdapter mAdapter;
private List<String> mListData;
private List<String> mListLoadData;
private String[] imagesUrl = {
"http://bbs.uc.cn/data/attachment/forum/201302/17/163510xsv14x35i9ix41i0.jpg",
"http://p3.so.qhimg.com/t0121ddd5bc66dcc9e8.jpg",
"http://p3.so.qhimg.com/t0181e8d7355386f79d.jpg",
"http://bbs.liebao.cn/data/attachment/forum/201210/25/182447qee2e922myyw8y8m.jpg"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
initView();
//下拉刷新
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mSwipeRefreshLayout.setRefreshing(false);
}
},2000);
}
});
//当滑到最后一项,还有上滑的趋势,就加载更多
mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if(!mSwipeRefreshLayout.isRefreshing()){
if(newState==RecyclerView.SCROLL_STATE_IDLE&&mAdapter.getItemCount()==lastVisibleItem+1){
mAdapter.changeMoreStatus(MyRecyclerViewAdapter.LOADING_MORE);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mListData.addAll(mListLoadData);
mAdapter.notifyDataSetChanged();
mAdapter.changeMoreStatus(MyRecyclerViewAdapter.PULLUP_LOAD_MORE);
}
},3000);
}
}
}
}
});
}
/**
* 初始化数据
*/
private void initData() {
mListData = new ArrayList<>();
mListLoadData = new ArrayList<>();
for(int i=0;i<30;i++){
mListData.add("数据"+i);
mListLoadData.add("加载的新数据"+i);
}
}
/**
* 初始化view
*/
private void initView() {
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
mManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mManager);
mAdapter = new MyRecyclerViewAdapter(this,mListData,imagesUrl);
mRecyclerView.setAdapter(mAdapter);
mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swiperefreshlayout);
//最多可以4种颜色
mSwipeRefreshLayout.setColorSchemeColors(Color.BLUE,Color.RED);
}
}
必要的地方都有说明,就不赘述了。搞定!运行!一看效果还是可以的,就下拉刷新 上拉加载玩了一下,当我手动滑动ViewPager的轮播图时候,发现有的不顺畅,下拉刷新有种要被拉下来的感觉,发现有冲突:
百度了一下,发现也有不少人有这个问题,解决办法网上也一大堆:
重写SwipeRefreshLayout。
于是乎,就重写了一下,代码如下:
package View;
import android.content.Context;
import android.support.v4.widget.SwipeRefreshLayout;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
/**
* Created by lenovo on 2016/7/9.
*/
public class MySwipeRefreshLayout extends SwipeRefreshLayout {
private int mTouchSlop;
// 上一次触摸时的X坐标
private float mPrevX;
public MySwipeRefreshLayout(Context context, AttributeSet attrs) {
super(context, attrs);
// 触发移动事件的最短距离,如果小于这个距离就不触发移动控件
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mPrevX = event.getX();
break;
case MotionEvent.ACTION_MOVE:
final float eventX = event.getX();
float xDiff = Math.abs(eventX - mPrevX);
// Log.d("refresh" ,"move----" + eventX + " " + mPrevX + " " + mTouchSlop);
// 增加60的容差,让下拉刷新在竖直滑动时就可以触发
if (xDiff > mTouchSlop + 60) {
return false;
}
}
return super.onInterceptTouchEvent(event);
}
}
再运行!搞定!完美!!
SwipeRefreshLayout+RecyclerView实现下拉刷新上拉自动加载
标签:
原文地址:http://blog.csdn.net/androidstudioo/article/details/51868223