PullToRefresh 下拉刷新 上拉加载
- 掌握自定义的具有下拉刷新和上拉加载功能的 ListView
- 掌握自定义的侧边栏 SlidingMenu
在日常开发工作中,应用界面常常都是用ListView进行数据展示的,并且界面可以实现下拉刷新和下拉加载功能,本文从根本上来自定义一个具有下拉刷新和上拉加载的 ListView。另外,侧边栏 SlidingMenu的应用场景也很多,这里我们也自定义一个具有侧栏栏效果的 SlidingMenu。
自定义控件之 ListView
项目概述
这里我们将使用前面所学的自定义控件的知识来进行自定义一个具有下拉刷新和上拉加载的ListView如图所示。
布局界面 UI
在本章中,主界面为 MainActivity.java,具体代码如文件【2-1】所示:【文件 2-1】 activity_main.xml
<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">
<com.itheima.refreshlistview.view.RefreshListView
android:id="@+id/refreshLv"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.itheima.refreshlistview.view.RefreshListView>
</RelativeLayout>
另外,头布局 listview_header.xml 的代码如下所示。【文件 2-2】 listview_header.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:orientation="horizontal" >
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ImageView
android:id="@+id/header_iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/common_listview_headview_red_arrow" />
<ProgressBar
android:id="@+id/header_pb"
android:visibility="invisible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminateDrawable="@drawable/custom_progressbar"
android:layout_gravity="center" />
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center" >
<TextView
android:id="@+id/tv_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下拉刷新"
android:textColor="#ff0000" />
<TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="最近更新时间: 1999-9-9 9:9:9"
android:textColor="#ff0000" />
</LinearLayout>
</LinearLayout>
根布局 listview_footer.xml 的代码如下所示 【文件 2-3】 listview_header.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:id="@+id/header_pb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminateDrawable="@drawable/custom_progressbar" />
<TextView
android:id="@+id/tv_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text="加载更多..."
android:textColor="#ff0000" />
</LinearLayout>
运行程序,效果图如图所示。
主界面业务逻辑
观察市场上手机应用项目的功能界面,发现几乎都具有下拉刷新和上拉加载的功能效果,这里我们就将要实现该功能,主界面 MainActivity.java 的业务逻辑如下所示:【文件 2-4】 MainActivity.java
public class MainActivity extends Activity {
private List<String> datas;
private Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final RefreshListView refreshLv = (RefreshListView) findViewById(R.id.refreshLv);
initData();
final MyAdapter adapter = new MyAdapter();
refreshLv.setAdapter(adapter);
refreshLv.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onFresh() {
handler.postDelayed(new Runnable() {
@Override
public void run() {
datas.add(0, "这是下拉刷新的新数据");
adapter.notifyDataSetChanged();
refreshLv.onFinish();
}
}, 3000);
}
@Override
public void onLoadMore() {
handler.postDelayed(new Runnable() {
@Override
public void run() {
datas.add("这是加载更多的数据 1");
datas.add("这是加载更多的数据 2");
datas.add("这是加载更多的数据 3");
adapter.notifyDataSetChanged();
refreshLv.onFinish();
}
}, 3000);
}
});
}
private void initData() {
datas = new ArrayList<String>();
for (int i = 0; i < 30; i++) {
datas.add("这是 listview 的数据" + i);
}
}
private class MyAdapter extends BaseAdapter {
@Override
public int getCount() {
return datas.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView tv = new TextView(getApplicationContext());
tv.setText(datas.get(position));
tv.setTextSize(15);
tv.setTextColor(Color.BLACK);
tv.setPadding(5, 5, 5, 5);
return tv;
}
}
}
自定义 ListView 的业务逻辑
下面我们将实现自定义 ListView 的主逻辑代码,自定义的 RefreshListView 通过继承 ListView 并进行相应的逻辑修改达到我们需要的效果。【文件 2-5】 RefreshListView.java
public class RefreshListView extends ListView implements OnScrollListener {
private int downY;
private View headerView;//头布局
private int headerViewdHeight;//头布局的高度
private final int DOWN_PULL = 0;//下拉刷新状态
private final int RELEASE_REFRESH = 1;//松开刷新状态
private final int REFRESHING = 2;//正在刷新状态
private int currentState = DOWN_PULL;//记录当前状态,默认为下拉刷新
private ImageView header_iv;
private ProgressBar header_pb;
private TextView tv_state;
private TextView tv_time;
private RotateAnimation upAnimation;//向上的动画
private RotateAnimation downAnimation;//向下的动画
private OnRefreshListener mOnRefreshListener;//刷新的回调接口对象
private boolean isLoadingMore = false;//记录加载更多的状态,默认值为 false
private View footerView;
private int footerViewHeight;
public RefreshListView(Context context) {
this(context, null);
}
public RefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
initHeaderView();
initFooterView();
init();
setOnScrollListener(this);
}
//初始化,就添加一个脚布局
private void initFooterView() {
footerView = View.inflate(getContext(), R.layout.listview_footer, null);
//获取脚布局的高度
footerView.measure(0, 0);
footerViewHeight = footerView.getMeasuredHeight();
//设置脚布局的 paddingtop
footerView.setPadding(0, -footerViewHeight, 0, 0);
this.addFooterView(footerView);
}
//初始化方法,这里是设置下拉刷新布局中的箭头动画
private void init() {
upAnimation = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
upAnimation.setDuration(500);
upAnimation.setFillAfter(true);
downAnimation = new RotateAnimation(-180, -360,Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
downAnimation.setDuration(500);
downAnimation.setFillAfter(true);
}
//初始化头布局
private void initHeaderView() {
headerView = View.inflate(getContext(), R.layout.listview_header, null);
header_iv = (ImageView) headerView.findViewById(R.id.header_iv);
header_pb = (ProgressBar) headerView.findViewById(R.id.header_pb);
tv_state = (TextView) headerView.findViewById(R.id.tv_state);
tv_time = (TextView) headerView.findViewById(R.id.tv_time);
//获得 headerview 的高度
headerView.measure(0, 0);//让系统去测量控件的宽高
headerViewdHeight = headerView.getMeasuredHeight();
// headerView.getHeight();//这里获得值永远为 0,它还没经过测量
//给 headerview 设置 paddingtop
headerView.setPadding(0, -headerViewdHeight, 0, 0);
//添加头布局
this.addHeaderView(headerView);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
downY = (int) ev.getY();
break;
case MotionEvent.ACTION_MOVE:
if(currentState == REFRESHING){
break;
}
int moveY = (int) ev.getY();
int diff = moveY -downY;
int paddingTop = -headerViewdHeight + diff;
//获得当前列表显示的第一个条目的索引
int firstVisiablePosition = getFirstVisiblePosition();
//只有当 paddingTop 大于头部高度的负数时才进行处理
if(paddingTop > -headerViewdHeight&&firstVisiablePosition == 0){
System.out.println(currentState+"");
//当前头布局完全显示,为松开刷新状态,下拉刷新变成松开刷新的时候
if(paddingTop > 0&¤tState == DOWN_PULL){
System.out.println("松开刷新");
currentState = RELEASE_REFRESH;
switchViewOnStateChange();
//当前头布局补完全显示,为下拉刷新状态,松开刷新变成下拉刷新的时候
}else if((paddingTop < 0&¤tState == RELEASE_REFRESH)){
System.out.println("下拉刷新");
currentState = DOWN_PULL;
switchViewOnStateChange();
}
// System.out.println("paddingTop = "+ paddingTop);
headerView.setPadding(0, paddingTop, 0, 0);
return true;//自己处理触摸事件
}
// break;
case MotionEvent.ACTION_UP:
if(currentState == DOWN_PULL){//当前状态为下拉刷新,隐藏头布局
headerView.setPadding(0, -headerViewdHeight, 0, 0);
}else if(currentState == RELEASE_REFRESH){//当前状态为松开刷新,改变状态
currentState = REFRESHING;
switchViewOnStateChange();
if(mOnRefreshListener != null){//正在刷新时,调用回调方法
mOnRefreshListener.onFresh();
}
}
break;
default:
break;
}
return super.onTouchEvent(ev); //listview 自己处理触摸事件,
}
//根据当前的状态来改变头布局的内容
private void switchViewOnStateChange(){
switch (currentState) {
case DOWN_PULL://下拉刷新
header_iv.startAnimation(downAnimation);
tv_state.setText("下拉刷新");
break;
case RELEASE_REFRESH://松开刷新
header_iv.startAnimation(upAnimation);
tv_state.setText("松开刷新");
break;
case REFRESHING://正在刷新
header_iv.clearAnimation();
header_iv.setVisibility(View.INVISIBLE);
header_pb.setVisibility(View.VISIBLE);
tv_state.setText("正在刷新...");
headerView.setPadding(0, 0, 0, 0);
break;
default:
break;
}
}
public void setOnRefreshListener(OnRefreshListener listener){
this.mOnRefreshListener = listener;
}
//刷新的回调接口
public interface OnRefreshListener{
//下拉刷新回调方法
void onFresh();
//加载更多的回调方法
void onLoadMore();
}
//当刷新完毕过后,调用的回调方法
public void onFinish() {
if(isLoadingMore){//加载更多
//隐藏脚布局
footerView.setPadding(0, -footerViewHeight, 0, 0);
//改变状态
isLoadingMore = false;
}else{//加载更多
//箭头图片显示
header_iv.setVisibility(View.VISIBLE);
//进度圈隐藏
header_pb.setVisibility(View.INVISIBLE);
//文字状态改变
tv_state.setText("下拉刷新");
//头布局隐藏
headerView.setPadding(0, -headerViewdHeight, 0, 0);
//状态值改变
currentState = DOWN_PULL;
//修改更新时间
tv_time.setText("最近刷新时间: "+getTime());
}
}
//获取当前刷新后的时间
private String getTime() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(new Date());
}
//当滚动发生改变时,调用该方法
// OnScrollListener.SCROLL_STATE_FLING;2 手指用力滑动一下,离开屏幕,listview 有一个
惯性的滑动状态
// OnScrollListener.SCROLL_STATE_IDLE;0 listview 列表处于停滞状态,手指没有触摸屏幕
// OnScrollListener.SCROLL_STATE_TOUCH_SCROLL;1 手指触摸着屏幕,上下滑动的状态
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
System.out.println("scrollState" + scrollState);
//手指离开屏幕,并且列表显示到最后一条数据的时候
int lastVisiablePosition = getLastVisiblePosition();
if(scrollState !=OnScrollListener.SCROLL_STATE_TOUCH_SCROLL&&lastVisiablePosition
== (getCount()-1)&&!isLoadingMore){
System.out.println("加载更多");
isLoadingMore = true;
footerView.setPadding(0, 0, 0, 0);
setSelection(getCount()-1);
if(mOnRefreshListener != null){
mOnRefreshListener.onLoadMore();
}
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
}
}
自定义 ListView 之后,在主界面布局中使用改写好的 ListView 类的全路径引入,这样定义好之后,运行程序,效果图如图所示
ListView
效果图
下拉刷新原理
- 给ListView添加header头布局,设置负的padding值,当下拉刷新的时候,给header设置正的padding值,显示header
- 给ListView添加footer脚布局,设置负的padding值,当上拉到底部的时候,给footer设置正的padding值,显示footer
- 判断是否加载更多,监听ListView的滚动事件,当ListView滚动状态处于fling,如果当前可见的position==集合的个数list.size()
- 加载更多:
list.addAll(data);
adapter.notifyDataSetChange();
- 下拉刷新:list.add(0,data);
重写onTouchEvent(),判断当前下拉手势
实现代码
public class RefreshListView extends ListView implements OnScrollListener,
android.widget.AdapterView.OnItemClickListener {
private static final int STATE_PULL_REFRESH = 0;// 下拉刷新
private static final int STATE_RELEASE_REFRESH = 1;// 松开刷新
private static final int STATE_REFRESHING = 2;// 正在刷新
private int mCurrrentState = STATE_PULL_REFRESH;// 当前状态
private View mHeaderView;//头布局
private int mHeaderViewHeight;//头布局高度
private TextView tvTitle;
private TextView tvTime;
private ImageView ivArrow;
private ProgressBar pbProgress;
private RotateAnimation animUp;
private RotateAnimation animDown;
private View mFooterView;//脚布局
private int mFooterViewHeight;//脚布局高度
private int startY = -1;// 滑动起点的y坐标
OnRefreshListener mListener;
public RefreshListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initHeaderView();
initFooterView();
}
public RefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
initHeaderView();
initFooterView();
}
public RefreshListView(Context context) {
super(context);
initHeaderView();
initFooterView();
}
/**
* 初始化头布局
*/
private void initHeaderView() {
mHeaderView = View.inflate(getContext(), R.layout.refresh_header, null);
this.addHeaderView(mHeaderView);//添加头布局
tvTitle = (TextView) mHeaderView.findViewById(R.id.tv_title);
tvTime = (TextView) mHeaderView.findViewById(R.id.tv_time);
ivArrow = (ImageView) mHeaderView.findViewById(R.id.iv_arr);
pbProgress = (ProgressBar) mHeaderView.findViewById(R.id.pb_progress);
mHeaderView.measure(0, 0);
mHeaderViewHeight = mHeaderView.getMeasuredHeight();
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隐藏头布局
initArrowAnim();
tvTime.setText("最后刷新时间:" + getCurrentTime());
}
/*
* 初始化脚布局
*/
private void initFooterView() {
mFooterView = View.inflate(getContext(),
R.layout.refresh_listview_footer, null);
this.addFooterView(mFooterView);//添加脚布局
mFooterView.measure(0, 0);
mFooterViewHeight = mFooterView.getMeasuredHeight();
mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);// 隐藏
this.setOnScrollListener(this);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
startY = (int) ev.getRawY();
break;
case MotionEvent.ACTION_MOVE:
if (startY == -1) {// 确保startY有效
startY = (int) ev.getRawY();
}
if (mCurrrentState == STATE_REFRESHING) {// 正在刷新时不做处理
break;
}
int endY = (int) ev.getRawY();
int dy = endY - startY;// 移动偏移量
if (dy > 0 && getFirstVisiblePosition() == 0) {// 只有下拉并且当前是第一个item,才允许下拉
int padding = dy - mHeaderViewHeight;// 计算padding
mHeaderView.setPadding(0, padding, 0, 0);// 设置当前padding
if (padding > 0 && mCurrrentState != STATE_RELEASE_REFRESH) {// 状态改为松开刷新
mCurrrentState = STATE_RELEASE_REFRESH;
refreshState();
} else if (padding < 0 && mCurrrentState != STATE_PULL_REFRESH) {// 改为下拉刷新状态
mCurrrentState = STATE_PULL_REFRESH;
refreshState();
}
return true;
}
break;
case MotionEvent.ACTION_UP:
startY = -1;// 重置
if (mCurrrentState == STATE_RELEASE_REFRESH) {
mCurrrentState = STATE_REFRESHING;// 正在刷新
mHeaderView.setPadding(0, 0, 0, 0);// 显示
refreshState();
} else if (mCurrrentState == STATE_PULL_REFRESH) {
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隐藏
}
break;
}
return super.onTouchEvent(ev);
}
/**
* 刷新下拉控件的布局
*/
private void refreshState() {
switch (mCurrrentState) {
case STATE_PULL_REFRESH:
tvTitle.setText("下拉刷新");
ivArrow.setVisibility(View.VISIBLE);
pbProgress.setVisibility(View.INVISIBLE);
ivArrow.startAnimation(animDown);
break;
case STATE_RELEASE_REFRESH:
tvTitle.setText("松开刷新");
ivArrow.setVisibility(View.VISIBLE);
pbProgress.setVisibility(View.INVISIBLE);
ivArrow.startAnimation(animUp);
break;
case STATE_REFRESHING:
tvTitle.setText("正在刷新...");
ivArrow.clearAnimation();// 必须先清除动画,才能隐藏
ivArrow.setVisibility(View.INVISIBLE);
pbProgress.setVisibility(View.VISIBLE);
if (mListener != null) {
mListener.onRefresh();
}
break;
}
}
/**
* 初始化箭头动画
*/
private void initArrowAnim() {
// 箭头向上动画
animUp = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
animUp.setDuration(200);
animUp.setFillAfter(true);
// 箭头向下动画
animDown = new RotateAnimation(-180, 0, Animation.RELATIVE_TO_SELF,
0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
animDown.setDuration(200);
animDown.setFillAfter(true);
}
public void setOnRefreshListener(OnRefreshListener listener) {
mListener = listener;
}
public interface OnRefreshListener {
public void onRefresh();
public void onLoadMore();// 加载下一页数据
}
/*
* 收起下拉刷新的控件
*/
public void onRefreshComplete(boolean success) {
if (isLoadingMore) {// 正在加载更多...
mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);// 隐藏脚布局
isLoadingMore = false;
} else {
mCurrrentState = STATE_PULL_REFRESH;
tvTitle.setText("下拉刷新");
ivArrow.setVisibility(View.VISIBLE);
pbProgress.setVisibility(View.INVISIBLE);
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隐藏
if (success) {
tvTime.setText("最后刷新时间:" + getCurrentTime());
}
}
}
/**
* 获取当前时间
*/
public String getCurrentTime() {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return format.format(new Date());
}
private boolean isLoadingMore;
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == SCROLL_STATE_IDLE
|| scrollState == SCROLL_STATE_FLING) {
if (getLastVisiblePosition() == getCount() - 1 && !isLoadingMore) {// 滑动到最后
System.out.println("到底了.....");
mFooterView.setPadding(0, 0, 0, 0);// 显示
setSelection(getCount() - 1);// 改变listview显示位置
isLoadingMore = true;
if (mListener != null) {
mListener.onLoadMore();
}
}
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
}
OnItemClickListener mItemClickListener;
@Override
public void setOnItemClickListener(
android.widget.AdapterView.OnItemClickListener listener) {
super.setOnItemClickListener(this);
mItemClickListener = listener;
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
if (mItemClickListener != null) {
mItemClickListener.onItemClick(parent, view, position
- getHeaderViewsCount(), id);
}
}
}
应用
private RefreshListView lvList;// 新闻列表
// 将头条新闻以头布局的形式加给listview
lvList.addHeaderView(headerView);
// 设置下拉刷新监听
lvList.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh() {
getDataFromServer();
}
@Override
public void onLoadMore() {
if (mMoreUrl != null) {
getMoreDataFromServer();
} else {
Toast.makeText(mActivity, "最后一页了", Toast.LENGTH_SHORT).show();
lvList.onRefreshComplete(false);// 收起加载更多的布局
}
}
});
private void getDataFromServer() {
HttpUtils utils = new HttpUtils();
utils.send(HttpMethod.GET, mUrl, new RequestCallBack<String>() {
@Override
public void onSuccess(ResponseInfo<String> responseInfo) {
String result = (String) responseInfo.result;
System.out.println("页签详情页返回结果:" + result);
parseData(result, false);
lvList.onRefreshComplete(true);
// 设置缓存
CacheUtils.setCache(mUrl, result, mActivity);
}
@Override
public void onFailure(HttpException error, String msg) {
Toast.makeText(mActivity, msg, Toast.LENGTH_SHORT).show();
error.printStackTrace();
lvList.onRefreshComplete(false);
}
});
}
/**
* 加载下一页数据
*/
private void getMoreDataFromServer() {
HttpUtils utils = new HttpUtils();
utils.send(HttpMethod.GET, mMoreUrl, new RequestCallBack<String>() {
@Override
public void onSuccess(ResponseInfo<String> responseInfo) {
String result = (String) responseInfo.result;
parseData(result, true);
lvList.onRefreshComplete(true);
}
@Override
public void onFailure(HttpException error, String msg) {
Toast.makeText(mActivity, msg, Toast.LENGTH_SHORT).show();
error.printStackTrace();
lvList.onRefreshComplete(false);
}
});
}
protected void parseData(String result, boolean isMore) {
Gson gson = new Gson();
mTabDetailData = gson.fromJson(result, TabData.class);
System.out.println("页签详情解析:" + mTabDetailData);
// 处理下一页链接
String more = mTabDetailData.data.more;
if (!TextUtils.isEmpty(more)) {
mMoreUrl = GlobalContants.SERVER_URL + more;
} else {
mMoreUrl = null;
}
if (!isMore) {
mTopNewsList = mTabDetailData.data.topnews;
mNewsList = mTabDetailData.data.news;
if (mTopNewsList != null) {
mViewPager.setAdapter(new TopNewsAdapter());
mIndicator.setViewPager(mViewPager);
mIndicator.setSnap(true);// 支持快照显示
mIndicator.setOnPageChangeListener(this);
mIndicator.onPageSelected(0);// 让指示器重新定位到第一个点
tvTitle.setText(mTopNewsList.get(0).title);
}
if (mNewsList != null) {
mNewsAdapter = new NewsAdapter();
lvList.setAdapter(mNewsAdapter);
}
// 自动轮播条显示
if (mHandler == null) {
mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
int currentItem = mViewPager.getCurrentItem();
if (currentItem < mTopNewsList.size() - 1) {
currentItem++;
} else {
currentItem = 0;
}
mViewPager.setCurrentItem(currentItem);// 切换到下一个页面
mHandler.sendEmptyMessageDelayed(0, 3000);// 继续延时3秒发消息,
// 形成循环
};
};
mHandler.sendEmptyMessageDelayed(0, 3000);// 延时3秒后发消息
}
} else {// 如果是加载下一页,需要将数据追加给原来的集合
ArrayList<TabNewsData> news = mTabDetailData.data.news;
mNewsList.addAll(news);
mNewsAdapter.notifyDataSetChanged();
}
}
RefreshListView refreshLv = (RefreshListView) findViewById(R.id.refreshLv);
initData();
final MyAdapter adapter = new MyAdapter();
refreshLv.setAdapter(adapter);
refreshLv.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onFresh() {
handler.postDelayed(new Runnable() {
@Override
public void run() {
datas.add(0, "这是下拉刷新的新数据");
adapter.notifyDataSetChanged();
refreshLv.onFinish();
}
}, 3000);
}
@Override
public void onLoadMore() {
handler.postDelayed(new Runnable() {
@Override
public void run() {
datas.add("这是加载更多的数据1");
datas.add("这是加载更多的数据2");
datas.add("这是加载更多的数据3");
adapter.notifyDataSetChanged();
refreshLv.onFinish();
}
}, 3000);
}
});
public class RefreshListView extends ListView implements AbsListView.OnScrollListener {
private int downY;
private View headerView;//头布局
private int headerViewdHeight;//头布局的高度
private final int DOWN_PULL = 0;//下拉刷新状态
private final int RELEASE_REFRESH = 1;//松开刷新状态
private final int REFRESHING = 2;//正在刷新状态
private int currentState = DOWN_PULL;//记录当前状态,默认为下拉刷新
private ImageView header_iv;
private ProgressBar header_pb;
private TextView tv_state;
private TextView tv_time;
private RotateAnimation upAnimation;//向上的动画
private RotateAnimation downAnimation;//向下的动画
private OnRefreshListener mOnRefreshListener;//刷新的回调接口对象
private boolean isLoadingMore = false;//记录加载更多的状态,默认值为false
private View footerView;
private int footerViewHeight;
public RefreshListView(Context context) {
this(context, null);
}
public RefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
initHeaderView();
initFooterView();
init();
setOnScrollListener(this);
}
//初始化,就添加一个脚布局
private void initFooterView() {
footerView = View.inflate(getContext(), R.layout.listview_footer, null);
//获取脚布局的高度
footerView.measure(0, 0);
footerViewHeight = footerView.getMeasuredHeight();
//设置脚布局的paddingtop
footerView.setPadding(0, -footerViewHeight, 0, 0);
this.addFooterView(footerView);
}
//初始化方法,这里是设置下拉刷新布局中的箭头动画
private void init() {
upAnimation = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
upAnimation.setDuration(500);
upAnimation.setFillAfter(true);
downAnimation = new RotateAnimation(-180, -360, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
downAnimation.setDuration(500);
downAnimation.setFillAfter(true);
}
//初始化头布局
private void initHeaderView() {
headerView = View.inflate(getContext(), R.layout.listview_header, null);
header_iv = (ImageView) headerView.findViewById(R.id.header_iv);
header_pb = (ProgressBar) headerView.findViewById(R.id.header_pb);
tv_state = (TextView) headerView.findViewById(R.id.tv_state);
tv_time = (TextView) headerView.findViewById(R.id.tv_time);
//获得headerview 的高度
headerView.measure(0, 0);//让系统去测量控件的宽高
headerViewdHeight = headerView.getMeasuredHeight();
// headerView.getHeight();//这里获得值永远为0,它还没经过测量
//给headerview 设置paddingtop
headerView.setPadding(0, -headerViewdHeight, 0, 0);
//添加头布局
this.addHeaderView(headerView);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
downY = (int) ev.getY();
break;
case MotionEvent.ACTION_MOVE:
if (currentState == REFRESHING) {
break;
}
int moveY = (int) ev.getY();
int diff = moveY - downY;
int paddingTop = -headerViewdHeight + diff;
//获得当前列表显示的第一个条目的索引
int firstVisiablePosition = getFirstVisiblePosition();
//只有当paddingTop 大于头部高度的负数时才进行处理
if (paddingTop > -headerViewdHeight && firstVisiablePosition == 0) {
System.out.println(currentState + "");
//当前头布局完全显示,为松开刷新状态,下拉刷新变成松开刷新的时候
if (paddingTop > 0 && currentState == DOWN_PULL) {
System.out.println("松开刷新");
currentState = RELEASE_REFRESH;
switchViewOnStateChange();
//当前头布局补完全显示,为下拉刷新状态,松开刷新变成下拉刷新的时候
} else if ((paddingTop < 0 && currentState == RELEASE_REFRESH)) {
System.out.println("下拉刷新");
currentState = DOWN_PULL;
switchViewOnStateChange();
}
// System.out.println("paddingTop = "+ paddingTop);
headerView.setPadding(0, paddingTop, 0, 0);
return true;//自己处理触摸事件
}
// break;
case MotionEvent.ACTION_UP:
if (currentState == DOWN_PULL) {//当前状态为下拉刷新,隐藏头布局
headerView.setPadding(0, -headerViewdHeight, 0, 0);
} else if (currentState == RELEASE_REFRESH) {//当前状态为松开刷新,改变状态
currentState = REFRESHING;
switchViewOnStateChange();
if (mOnRefreshListener != null) {//正在刷新时,调用回调方法
mOnRefreshListener.onFresh();
}
}
break;
default:
break;
}
return super.onTouchEvent(ev); //listview 自己处理触摸事件,
}
//根据当前的状态来改变头布局的内容
private void switchViewOnStateChange() {
switch (currentState) {
case DOWN_PULL://下拉刷新
header_iv.startAnimation(downAnimation);
tv_state.setText("下拉刷新");
break;
case RELEASE_REFRESH://松开刷新
header_iv.startAnimation(upAnimation);
tv_state.setText("松开刷新");
break;
case REFRESHING://正在刷新
header_iv.clearAnimation();
header_iv.setVisibility(View.INVISIBLE);
header_pb.setVisibility(View.VISIBLE);
tv_state.setText("正在刷新...");
headerView.setPadding(0, 0, 0, 0);
break;
default:
break;
}
}
public void setOnRefreshListener(OnRefreshListener listener) {
this.mOnRefreshListener = listener;
}
//刷新的回调接口
public interface OnRefreshListener {
//下拉刷新回调方法
void onFresh();
//加载更多的回调方法
void onLoadMore();
}
//当刷新完毕过后,调用的回调方法
public void onFinish() {
if (isLoadingMore) {//加载更多
//隐藏脚布局
footerView.setPadding(0, -footerViewHeight, 0, 0);
//改变状态
isLoadingMore = false;
} else {//加载更多
//箭头图片显示
header_iv.setVisibility(View.VISIBLE);
//进度圈隐藏
header_pb.setVisibility(View.INVISIBLE);
//文字状态改变
tv_state.setText("下拉刷新");
//头布局隐藏
headerView.setPadding(0, -headerViewdHeight, 0, 0);
//状态值改变
currentState = DOWN_PULL;
//修改更新时间
tv_time.setText("最近刷新时间: " + getTime());
}
}
//获取当前刷新后的时间
private String getTime() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(new Date());
}
//当滚动发生改变时,调用该方法
// OnScrollListener.SCROLL_STATE_FLING;2 手指用力滑动一下,离开屏幕,listview 有一个惯性的滑动状态
// OnScrollListener.SCROLL_STATE_IDLE;0 listview 列表处于停滞状态,手指没有触摸屏幕
// OnScrollListener.SCROLL_STATE_TOUCH_SCROLL;1 手指触摸着屏幕,上下滑动的状态
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
System.out.println("scrollState" + scrollState);
//手指离开屏幕,并且列表显示到最后一条数据的时候
int lastVisiablePosition = getLastVisiblePosition();
if (scrollState != OnScrollListener.SCROLL_STATE_TOUCH_SCROLL && lastVisiablePosition
== (getCount() - 1) && !isLoadingMore) {
System.out.println("加载更多");
isLoadingMore = true;
footerView.setPadding(0, 0, 0, 0);
setSelection(getCount() - 1);
if (mOnRefreshListener != null) {
mOnRefreshListener.onLoadMore();
}
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
}
}
RecyclerView
public class LRecyclerView extends RecyclerView {
private boolean pullRefreshEnabled = true;
private OnRefreshListener mRefreshListener;
private OnLoadMoreListener mLoadMoreListener;
private LScrollListener mLScrollListener;
private ArrowRefreshHeader mRefreshHeader;
private View mEmptyView;
private View mFootView;
private int mRefreshProgressStyle = ProgressStyle.SysProgress;
private final RecyclerView.AdapterDataObserver mDataObserver = new DataObserver();
private float mLastY = -1;
private static final float DRAG_RATE = 2.2f;
private LRecyclerViewAdapter mWrapAdapter;
private boolean isNoMore = false;
private int mRefreshHeaderHeight;
//scroll variables begin
protected LayoutManagerType layoutManagerType;//当前RecyclerView类型
private int[] lastPositions;//最后一个的位置
private int lastVisibleItemPosition;//最后一个可见的item的位置
private int currentScrollState = 0;//当前滑动的状态
/**
* 触发在上下滑动监听器的容差距离
*/
private static final int HIDE_THRESHOLD = 20;
/**
* 滑动的距离
*/
private int mDistance = 0;
/**
* 是否需要监听控制
*/
private boolean mIsScrollDown = true;
/**
* Y轴移动的实际距离(最顶部为0)
*/
private int mScrolledYDistance = 0;
/**
* X轴移动的实际距离(最左侧为0)
*/
private int mScrolledXDistance = 0;
//scroll variables end
private AppBarStateChangeListener.State appbarState = AppBarStateChangeListener.State.EXPANDED;
public LRecyclerView(Context context) {
this(context, null);
}
public LRecyclerView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public LRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
//下拉刷新布局
mRefreshHeader = new ArrowRefreshHeader(getContext());
//设置下拉刷新的样式
mRefreshHeader.setProgressStyle(mRefreshProgressStyle);
}
//脚布局,加载更多等
LoadingFooter footView = new LoadingFooter(getContext());
mFootView = footView;
mFootView.setVisibility(GONE);//隐藏脚布局
}
@Override
public void setAdapter(Adapter adapter) {
mWrapAdapter = (LRecyclerViewAdapter) adapter;
super.setAdapter(mWrapAdapter);
mWrapAdapter.getInnerAdapter().registerAdapterDataObserver(mDataObserver);
mDataObserver.onChanged();
//设置下拉刷新和加载更多
mWrapAdapter.setRefreshHeader(mRefreshHeader);
mWrapAdapter.addFooterView(mFootView);
}
private class DataObserver extends RecyclerView.AdapterDataObserver {
@Override
public void onChanged() {
Adapter<?> adapter = getAdapter();
if (adapter instanceof LRecyclerViewAdapter) {
LRecyclerViewAdapter lRecyclerViewAdapter = (LRecyclerViewAdapter) adapter;
if (lRecyclerViewAdapter.getInnerAdapter() != null && mEmptyView != null) {
int count = lRecyclerViewAdapter.getInnerAdapter().getItemCount();
Log.e("lzx","count " + count);
if (count == 0) {
mEmptyView.setVisibility(View.VISIBLE);
LRecyclerView.this.setVisibility(View.GONE);
} else {
mEmptyView.setVisibility(View.GONE);
LRecyclerView.this.setVisibility(View.VISIBLE);
}
}
} else {
if (adapter != null && mEmptyView != null) {
if (adapter.getItemCount() == 0) {
mEmptyView.setVisibility(View.VISIBLE);
LRecyclerView.this.setVisibility(View.GONE);
} else {
mEmptyView.setVisibility(View.GONE);
LRecyclerView.this.setVisibility(View.VISIBLE);
}
}
}
if (mWrapAdapter != null) {
mWrapAdapter.notifyDataSetChanged();
}
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount) {
mWrapAdapter.notifyItemRangeChanged(positionStart + mWrapAdapter.getHeaderViewsCount() + 1, itemCount);
}
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
mWrapAdapter.notifyItemRangeInserted(positionStart + mWrapAdapter.getHeaderViewsCount() + 1, itemCount);
}
@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
mWrapAdapter.notifyItemRangeRemoved(positionStart + mWrapAdapter.getHeaderViewsCount() + 1, itemCount);
}
@Override
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
int headerViewsCountCount = mWrapAdapter.getHeaderViewsCount();
mWrapAdapter.notifyItemRangeChanged(fromPosition + headerViewsCountCount + 1, toPosition + headerViewsCountCount + 1 + itemCount);
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (mLastY == -1) {
mLastY = ev.getRawY();
}
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mLastY = ev.getRawY();
break;
case MotionEvent.ACTION_MOVE:
final float deltaY = ev.getRawY() - mLastY;
mLastY = ev.getRawY();
if (isOnTop() && pullRefreshEnabled && (appbarState == AppBarStateChangeListener.State.EXPANDED)) {
mRefreshHeader.onMove(deltaY / DRAG_RATE);
if (mRefreshHeader.getVisibleHeight() > 0 && mRefreshHeader.getState() < ArrowRefreshHeader.STATE_REFRESHING) {
return false;
}
}
break;
default:
mLastY = -1; // reset
if (isOnTop() && pullRefreshEnabled && appbarState == AppBarStateChangeListener.State.EXPANDED) {
if (mRefreshHeader.releaseAction()) {
if (mRefreshListener != null) {
mRefreshListener.onRefresh();
}
}
}
break;
}
return super.onTouchEvent(ev);
}
private int findMax(int[] lastPositions) {
int max = lastPositions[0];
for (int value : lastPositions) {
if (value > max) {
max = value;
}
}
return max;
}
private int findMin(int[] firstPositions) {
int min = firstPositions[0];
for (int value : firstPositions) {
if (value < min) {
min = value;
}
}
return min;
}
private boolean isOnTop() {
if (pullRefreshEnabled && mRefreshHeader.getParent() != null) {
return true;
} else {
return false;
}
}
/**
* set view when no content item
*
* @param emptyView visiable view when items is empty
*/
public void setEmptyView(View emptyView) {
this.mEmptyView = emptyView;
mDataObserver.onChanged();
}
public void refreshComplete() {
mRefreshHeader.refreshComplete();
setNoMore(false);
}
public void setNoMore(boolean noMore){
isNoMore = noMore;
}
public void setRefreshHeader(BaseRefreshHeader refreshHeader) {
mRefreshHeader = (ArrowRefreshHeader) refreshHeader;
}
public void setPullRefreshEnabled(boolean enabled) {
pullRefreshEnabled = enabled;
}
public void setRefreshProgressStyle(int style) {
if (mRefreshHeader != null) {
mRefreshHeader.setProgressStyle(style);
}
}
public void setArrowImageView(int resId) {
if (mRefreshHeader != null) {
mRefreshHeader.setArrowImageView(resId);
}
}
public void setOnRefreshListener(OnRefreshListener listener) {
mRefreshListener = listener;
}
public void setOnLoadMoreListener(OnLoadMoreListener listener) {
mLoadMoreListener = listener;
}
public void setLScrollListener(LScrollListener listener) {
mLScrollListener = listener;
}
public interface LScrollListener {
void onScrollUp();//scroll down to up
void onScrollDown();//scroll from up to down
void onScrolled(int distanceX, int distanceY);// moving state,you can get the move distance
void onScrollStateChanged(int state);
}
public void setRefreshing(boolean refreshing) {
if (refreshing && pullRefreshEnabled && mRefreshListener != null) {
mRefreshHeader.setState(ArrowRefreshHeader.STATE_REFRESHING);
mRefreshHeaderHeight = mRefreshHeader.getMeasuredHeight();
mRefreshHeader.onMove(mRefreshHeaderHeight);
mRefreshListener.onRefresh();
}
}
public void forceToRefresh() {
LoadingFooter.State state = RecyclerViewStateUtils.getFooterViewState(this);
if(state == LoadingFooter.State.Loading) {
return;
}
if (pullRefreshEnabled && mRefreshListener != null) {
scrollToPosition(0);
mRefreshHeader.setState(ArrowRefreshHeader.STATE_REFRESHING);
mRefreshHeader.onMove(mRefreshHeaderHeight);
mRefreshListener.onRefresh();
}
}
@Override
public void onScrolled(int dx, int dy) {
super.onScrolled(dx, dy);
int firstVisibleItemPosition = 0;
RecyclerView.LayoutManager layoutManager = getLayoutManager();
if (layoutManagerType == null) {
if (layoutManager instanceof LinearLayoutManager) {
layoutManagerType = LayoutManagerType.LinearLayout;
} else if (layoutManager instanceof GridLayoutManager) {
layoutManagerType = LayoutManagerType.GridLayout;
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
layoutManagerType = LayoutManagerType.StaggeredGridLayout;
} else {
throw new RuntimeException(
"Unsupported LayoutManager used. Valid ones are LinearLayoutManager, GridLayoutManager and StaggeredGridLayoutManager");
}
}
switch (layoutManagerType) {
case LinearLayout:
firstVisibleItemPosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
lastVisibleItemPosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
break;
case GridLayout:
firstVisibleItemPosition = ((GridLayoutManager) layoutManager).findFirstVisibleItemPosition();
lastVisibleItemPosition = ((GridLayoutManager) layoutManager).findLastVisibleItemPosition();
break;
case StaggeredGridLayout:
StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;
if (lastPositions == null) {
lastPositions = new int[staggeredGridLayoutManager.getSpanCount()];
}
staggeredGridLayoutManager.findLastVisibleItemPositions(lastPositions);
lastVisibleItemPosition = findMax(lastPositions);
staggeredGridLayoutManager.findFirstCompletelyVisibleItemPositions(lastPositions);
firstVisibleItemPosition = findMax(lastPositions);
break;
}
// 根据类型来计算出第一个可见的item的位置,由此判断是否触发到底部的监听器
// 计算并判断当前是向上滑动还是向下滑动
calculateScrollUpOrDown(firstVisibleItemPosition, dy);
// 移动距离超过一定的范围,我们监听就没有啥实际的意义了
mScrolledXDistance += dx;
mScrolledYDistance += dy;
mScrolledXDistance = (mScrolledXDistance < 0) ? 0 : mScrolledXDistance;
mScrolledYDistance = (mScrolledYDistance < 0) ? 0 : mScrolledYDistance;
if (mIsScrollDown && (dy == 0)) {
mScrolledYDistance = 0;
}
//Be careful in here
if (null != mLScrollListener) {
mLScrollListener.onScrolled(mScrolledXDistance, mScrolledYDistance);
}
}
@Override
public void onScrollStateChanged(int state) {
super.onScrollStateChanged(state);
currentScrollState = state;
if (mLScrollListener != null) {
mLScrollListener.onScrollStateChanged(state);
}
if (mLoadMoreListener != null) {
if (currentScrollState == RecyclerView.SCROLL_STATE_IDLE) {
RecyclerView.LayoutManager layoutManager = getLayoutManager();
int visibleItemCount = layoutManager.getChildCount();
int totalItemCount = layoutManager.getItemCount();
if (visibleItemCount > 0
&& lastVisibleItemPosition >= totalItemCount - 1
&& totalItemCount > visibleItemCount
&& !isNoMore
//&& !mIsScrollDown
&& mRefreshHeader.getState() != ArrowRefreshHeader.STATE_REFRESHING) {
mLoadMoreListener.onLoadMore();
}
}
}
}
/**
* 计算当前是向上滑动还是向下滑动
*/
private void calculateScrollUpOrDown(int firstVisibleItemPosition, int dy) {
if (null != mLScrollListener) {
if (firstVisibleItemPosition == 0) {
if (!mIsScrollDown) {
mIsScrollDown = true;
mLScrollListener.onScrollDown();
}
} else {
if (mDistance > HIDE_THRESHOLD && mIsScrollDown) {
mIsScrollDown = false;
mLScrollListener.onScrollUp();
mDistance = 0;
} else if (mDistance < -HIDE_THRESHOLD && !mIsScrollDown) {
mIsScrollDown = true;
mLScrollListener.onScrollDown();
mDistance = 0;
}
}
}
if ((mIsScrollDown && dy > 0) || (!mIsScrollDown && dy < 0)) {
mDistance += dy;
}
}
public enum LayoutManagerType {
LinearLayout,
StaggeredGridLayout,
GridLayout
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
//解决LRecyclerView与CollapsingToolbarLayout滑动冲突的问题
AppBarLayout appBarLayout = null;
ViewParent p = getParent();
while (p != null) {
if (p instanceof CoordinatorLayout) {
break;
}
p = p.getParent();
}
if(p instanceof CoordinatorLayout) {
CoordinatorLayout coordinatorLayout = (CoordinatorLayout)p;
final int childCount = coordinatorLayout.getChildCount();
for (int i = childCount - 1; i >= 0; i--) {
final View child = coordinatorLayout.getChildAt(i);
if(child instanceof AppBarLayout) {
appBarLayout = (AppBarLayout)child;
break;
}
}
if(appBarLayout != null) {
appBarLayout.addOnOffsetChangedListener(new AppBarStateChangeListener() {
@Override
public void onStateChanged(AppBarLayout appBarLayout, State state) {
appbarState = state;
}
});
}
}
}
}
Adapter
public class LRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int TYPE_REFRESH_HEADER = 10000;
private static final int TYPE_NORMAL = 0;
private static final int TYPE_FOOTER_VIEW = 10001;
private static final int HEADER_INIT_INDEX = 10002;
private static List<Integer> mHeaderTypes = new ArrayList<>();
private ArrowRefreshHeader mRefreshHeader;
private OnItemClickListener mOnItemClickListener;
private OnItemLongClickListener mOnItemLongClickListener;
/**
* RecyclerView使用的,真正的Adapter
*/
private RecyclerView.Adapter mInnerAdapter;
private ArrayList<View> mHeaderViews = new ArrayList<>();
private ArrayList<View> mFooterViews = new ArrayList<>();
public LRecyclerViewAdapter(RecyclerView.Adapter innerAdapter) {
this.mInnerAdapter = innerAdapter;
}
public void setRefreshHeader(ArrowRefreshHeader refreshHeader){
mRefreshHeader = refreshHeader;
}
public RecyclerView.Adapter getInnerAdapter() {
return mInnerAdapter;
}
public void addHeaderView(View view) {
if (view == null) {
throw new RuntimeException("header is null");
}
mHeaderTypes.add(HEADER_INIT_INDEX + mHeaderViews.size());
mHeaderViews.add(view);
}
public void addFooterView(View view) {
if (view == null) {
throw new RuntimeException("footer is null");
}
if (getFooterViewsCount() > 0) {
removeFooterView(getFooterView());
}
mFooterViews.add(view);
//this.notifyDataSetChanged();
}
/**
* 根据header的ViewType判断是哪个header
* @param itemType
* @return
*/
private View getHeaderViewByType(int itemType) {
if(!isHeaderType(itemType)) {
return null;
}
return mHeaderViews.get(itemType - HEADER_INIT_INDEX);
}
/**
* 判断一个type是否为HeaderType
* @param itemViewType
* @return
*/
private boolean isHeaderType(int itemViewType) {
return mHeaderViews.size() > 0 && mHeaderTypes.contains(itemViewType);
}
/**
* 返回第一个FootView
* @return
*/
public View getFooterView() {
return getFooterViewsCount()>0 ? mFooterViews.get(0) : null;
}
/**
* 返回第一个HeaderView
* @return
*/
public View getHeaderView() {
return getHeaderViewsCount()>0 ? mHeaderViews.get(0) : null;
}
public ArrayList<View> getHeaderViews() {
return mHeaderViews;
}
public void removeHeaderView(View view) {
mHeaderViews.remove(view);
this.notifyDataSetChanged();
}
public void removeFooterView(View view) {
mFooterViews.remove(view);
this.notifyDataSetChanged();
}
public int getHeaderViewsCount() {
return mHeaderViews.size();
}
public int getFooterViewsCount() {
return mFooterViews.size();
}
public boolean isHeader(int position) {
return position >= 1 && position < mHeaderViews.size() + 1;
}
public boolean isRefreshHeader(int position) {
return position == 0;
}
public boolean isFooter(int position) {
int lastPosition = getItemCount() - getFooterViewsCount();
return getFooterViewsCount() > 0 && position >= lastPosition;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_REFRESH_HEADER) {
return new ViewHolder(mRefreshHeader);
} else if (isHeaderType(viewType)) {
return new ViewHolder(getHeaderViewByType(viewType));
} else if (viewType == TYPE_FOOTER_VIEW) {
return new ViewHolder(mFooterViews.get(0));
}
return mInnerAdapter.onCreateViewHolder(parent, viewType);
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
if (isHeader(position) || isRefreshHeader(position)) {
return;
}
final int adjPosition = position - (getHeaderViewsCount() + 1);
int adapterCount;
if (mInnerAdapter != null) {
adapterCount = mInnerAdapter.getItemCount();
if (adjPosition < adapterCount) {
mInnerAdapter.onBindViewHolder(holder, adjPosition);
if (mOnItemClickListener != null) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v)
{
mOnItemClickListener.onItemClick(holder.itemView, adjPosition);
}
});
}
if (mOnItemLongClickListener != null) {
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v)
{
mOnItemLongClickListener.onItemLongClick(holder.itemView, adjPosition);
return true;
}
});
}
}
}
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position, List<Object> payloads) {
if (payloads.isEmpty()) {
onBindViewHolder(holder,position);
} else {
if (isHeader(position) || isRefreshHeader(position)) {
return;
}
final int adjPosition = position - (getHeaderViewsCount() + 1);
int adapterCount;
if (mInnerAdapter != null) {
adapterCount = mInnerAdapter.getItemCount();
if (adjPosition < adapterCount) {
mInnerAdapter.onBindViewHolder(holder, adjPosition, payloads);
}
}
}
}
@Override
public int getItemCount() {
if (mInnerAdapter != null) {
return getHeaderViewsCount() + getFooterViewsCount() + mInnerAdapter.getItemCount() + 1;
} else {
return getHeaderViewsCount() + getFooterViewsCount() + 1;
}
}
@Override
public int getItemViewType(int position) {
int adjPosition = position - (getHeaderViewsCount() + 1);
if (isRefreshHeader(position)) {
return TYPE_REFRESH_HEADER;
}
if (isHeader(position)) {
position = position - 1;
return mHeaderTypes.get(position);
}
if (isFooter(position)) {
return TYPE_FOOTER_VIEW;
}
int adapterCount;
if (mInnerAdapter != null) {
adapterCount = mInnerAdapter.getItemCount();
if (adjPosition < adapterCount) {
return mInnerAdapter.getItemViewType(adjPosition);
}
}
return TYPE_NORMAL;
}
@Override
public long getItemId(int position) {
if (mInnerAdapter != null && position >= getHeaderViewsCount()) {
int adjPosition = position - getHeaderViewsCount();
int adapterCount = mInnerAdapter.getItemCount();
if (adjPosition < adapterCount) {
return mInnerAdapter.getItemId(adjPosition);
}
}
return -1;
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
if (manager instanceof GridLayoutManager) {
final GridLayoutManager gridManager = ((GridLayoutManager) manager);
gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
return (isHeader(position) || isFooter(position) || isRefreshHeader(position))
? gridManager.getSpanCount() : 1;
}
});
}
mInnerAdapter.onAttachedToRecyclerView(recyclerView);
}
@Override
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
mInnerAdapter.onDetachedFromRecyclerView(recyclerView);
}
@Override
public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
super.onViewAttachedToWindow(holder);
ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
if (lp != null && lp instanceof StaggeredGridLayoutManager.LayoutParams) {
if(isHeader(holder.getLayoutPosition()) ||isRefreshHeader(holder.getLayoutPosition()) || isFooter(holder.getLayoutPosition())) {
StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
p.setFullSpan(true);
}
}
mInnerAdapter.onViewAttachedToWindow(holder);
}
@Override
public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) {
mInnerAdapter.onViewDetachedFromWindow(holder);
}
@Override
public void onViewRecycled(RecyclerView.ViewHolder holder) {
mInnerAdapter.onViewRecycled(holder);
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View itemView) {
super(itemView);
}
}
/**
*
* @param isCallback whether position is from callback interface
* @param position
* @return
*/
public int getAdapterPosition(boolean isCallback, int position) {
if(isCallback) {
int adjPosition = position - (getHeaderViewsCount() + 1);
int adapterCount = mInnerAdapter.getItemCount();
if (adjPosition < adapterCount) {
return adjPosition;
}
}else {
return (position + getHeaderViewsCount()) + 1;
}
return -1;
}
public void setOnItemClickListener(OnItemClickListener itemClickListener)
{
this.mOnItemClickListener = itemClickListener;
}
public void setOnItemLongClickListener(OnItemLongClickListener itemLongClickListener)
{
this.mOnItemLongClickListener = itemLongClickListener;
}
}
RecyclerViewStateUtils
public class RecyclerViewStateUtils {
/**
* 设置LRecyclerViewAdapter的FooterView State
*
* @param instance context
* @param recyclerView recyclerView
* @param pageSize 分页展示时,recyclerView每一页的数量
* @param state FooterView State
* @param errorListener FooterView处于Error状态时的点击事件
*/
public static void setFooterViewState(Activity instance, RecyclerView recyclerView, int pageSize, LoadingFooter.State state, View.OnClickListener errorListener) {
if(instance==null || instance.isFinishing()) {
return;
}
RecyclerView.Adapter outerAdapter = recyclerView.getAdapter();
if (outerAdapter == null || !(outerAdapter instanceof LRecyclerViewAdapter)) {
return;
}
LRecyclerViewAdapter lRecyclerViewAdapter = (LRecyclerViewAdapter) outerAdapter;
//只有一页的时候,就别加什么FooterView了
if (lRecyclerViewAdapter.getInnerAdapter().getItemCount() < pageSize) {
return;
}
LoadingFooter footerView;
//已经有footerView了
if (lRecyclerViewAdapter.getFooterViewsCount() > 0) {
footerView = (LoadingFooter)lRecyclerViewAdapter.getFooterView();
footerView.setState(state);
footerView.setVisibility(View.VISIBLE);
if (state == LoadingFooter.State.NetWorkError) {
footerView.setOnClickListener(errorListener);
} else if (state == LoadingFooter.State.TheEnd){
((LRecyclerView)recyclerView).setNoMore(true);
}
}
recyclerView.scrollToPosition(lRecyclerViewAdapter.getItemCount() - 1);
}
/**
* 设置LRecyclerViewAdapter的FooterView State
*
* @param instance context
* @param recyclerView recyclerView
* @param pageSize 分页展示时,recyclerView每一页的数量
* @param state FooterView State
* @param errorListener FooterView处于Error状态时的点击事件
*/
public static void setFooterViewState2(Activity instance, RecyclerView recyclerView, int pageSize, LoadingFooter.State state, View.OnClickListener errorListener) {
if(instance==null || instance.isFinishing()) {
return;
}
RecyclerView.Adapter outerAdapter = recyclerView.getAdapter();
if (outerAdapter == null || !(outerAdapter instanceof LRecyclerViewAdapter)) {
return;
}
LRecyclerViewAdapter lRecyclerViewAdapter = (LRecyclerViewAdapter) outerAdapter;
LoadingFooter footerView;
//已经有footerView了
if (lRecyclerViewAdapter.getFooterViewsCount() > 0) {
footerView = (LoadingFooter) lRecyclerViewAdapter.getFooterView();
footerView.setState(state);
if (state == LoadingFooter.State.NetWorkError) {
footerView.setOnClickListener(errorListener);
}
recyclerView.scrollToPosition(0);
} else {
footerView = new LoadingFooter(instance);
footerView.setState(state);
if (state == LoadingFooter.State.NetWorkError) {
footerView.setOnClickListener(errorListener);
}
lRecyclerViewAdapter.addFooterView(footerView);
recyclerView.scrollToPosition(0);
}
}
/**
* 获取当前RecyclerView.FooterView的状态
*
* @param recyclerView
*/
public static LoadingFooter.State getFooterViewState(RecyclerView recyclerView) {
RecyclerView.Adapter outerAdapter = recyclerView.getAdapter();
if (outerAdapter != null && outerAdapter instanceof LRecyclerViewAdapter) {
if (((LRecyclerViewAdapter) outerAdapter).getFooterViewsCount() > 0) {
LoadingFooter footerView = (LoadingFooter) ((LRecyclerViewAdapter) outerAdapter).getFooterView();
return footerView.getState();
}
}
return LoadingFooter.State.Normal;
}
/**
* 设置当前RecyclerView.FooterView的状态
*
* @param recyclerView
* @param state
*/
public static void setFooterViewState(RecyclerView recyclerView, LoadingFooter.State state) {
RecyclerView.Adapter outerAdapter = recyclerView.getAdapter();
if (outerAdapter != null && outerAdapter instanceof LRecyclerViewAdapter) {
if (((LRecyclerViewAdapter) outerAdapter).getFooterViewsCount() > 0) {
LoadingFooter footerView = (LoadingFooter) ((LRecyclerViewAdapter) outerAdapter).getFooterView();
footerView.setState(state);
}
}
}
}
public class BooheeListView extends ListView implements OnScrollListener {
private boolean isLastStatus;
private OnLoadMoreListener mListener;
public interface OnLoadMoreListener {
void onLoadMore();
}
public BooheeListView(Context context, AttributeSet attrs) {
super(context, attrs);
setOnScrollListener(this);
}
public void setOnLoadMoreListener(OnLoadMoreListener listener) {
this.mListener = listener;
}
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (firstVisibleItem + visibleItemCount != totalItemCount || totalItemCount <= 0) {
this.isLastStatus = false;
return;
}
loadMore();
this.isLastStatus = true;
}
private void loadMore() {
if (this.mListener != null && !this.isLastStatus) {
this.mListener.onLoadMore();
}
}
}