博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
自定义控件:下拉刷新
阅读量:2175 次
发布时间:2019-05-01

本文共 64204 字,大约阅读时间需要 214 分钟。

PullToRefresh 下拉刷新 上拉加载

  • 掌握自定义的具有下拉刷新和上拉加载功能的 ListView
  • 掌握自定义的侧边栏 SlidingMenu

在日常开发工作中,应用界面常常都是用ListView进行数据展示的,并且界面可以实现下拉刷新和下拉加载功能,本文从根本上来自定义一个具有下拉刷新和上拉加载的 ListView。另外,侧边栏 SlidingMenu的应用场景也很多,这里我们也自定义一个具有侧栏栏效果的 SlidingMenu。

自定义控件之 ListView

项目概述

这里我们将使用前面所学的自定义控件的知识来进行自定义一个具有下拉刷新和上拉加载的ListView如图所示。

布局界面 UI

在本章中,主界面为 MainActivity.java,具体代码如文件【2-1】所示:【文件 2-1】 activity_main.xml

另外,头布局 listview_header.xml 的代码如下所示。【文件 2-2】 listview_header.xml

根布局 listview_footer.xml 的代码如下所示 【文件 2-3】 listview_header.xml

运行程序,效果图如图所示。

主界面业务逻辑

观察市场上手机应用项目的功能界面,发现几乎都具有下拉刷新和上拉加载的功能效果,这里我们就将要实现该功能,主界面 MainActivity.java 的业务逻辑如下所示:【文件 2-4】 MainActivity.java

public class MainActivity extends Activity {
private List
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
(); 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&&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) { } }

自定义 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;// 新闻列表// 将头条新闻以头布局的形式加给listviewlvList.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
() { @Override public void onSuccess(ResponseInfo
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
() { @Override public void onSuccess(ResponseInfo
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
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
{
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
mHeaderTypes = new ArrayList<>(); private ArrowRefreshHeader mRefreshHeader; private OnItemClickListener mOnItemClickListener; private OnItemLongClickListener mOnItemLongClickListener; /** * RecyclerView使用的,真正的Adapter */ private RecyclerView.Adapter mInnerAdapter; private ArrayList
mHeaderViews = new ArrayList<>(); private ArrayList
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
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
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(); } }}
你可能感兴趣的文章
初探Java设计模式3:行为型模式(策略,观察者等)
查看>>
初探Java设计模式4:一文带你掌握JDK中的设计模式
查看>>
初探Java设计模式5:一文了解Spring涉及到的9种设计模式
查看>>
Java集合详解1:一文读懂ArrayList,Vector与Stack使用方法和实现原理
查看>>
Java集合详解2:一文读懂Queue和LinkedList
查看>>
Java集合详解3:一文读懂Iterator,fail-fast机制与比较器
查看>>
Java集合详解4:一文读懂HashMap和HashTable的区别以及常见面试题
查看>>
Java集合详解5:深入理解LinkedHashMap和LRU缓存
查看>>
Java集合详解6:这次,从头到尾带你解读Java中的红黑树
查看>>
Java集合详解7:一文搞清楚HashSet,TreeSet与LinkedHashSet的异同
查看>>
Java集合详解8:Java集合类细节精讲,细节决定成败
查看>>
Java并发指南1:并发基础与Java多线程
查看>>
Java并发指南2:深入理解Java内存模型JMM
查看>>
Java并发指南3:并发三大问题与volatile关键字,CAS操作
查看>>
Java并发指南4:Java中的锁 Lock和synchronized
查看>>
Java并发指南5:JMM中的final关键字解析
查看>>
Java并发指南6:Java内存模型JMM总结
查看>>
Java并发指南7:JUC的核心类AQS详解
查看>>
Java并发指南8:AQS中的公平锁与非公平锁,Condtion
查看>>
Java网络编程和NIO详解6:Linux epoll实现原理详解
查看>>