下拉刷新和上拉加载的ListView-MutilListView
2015-07-02 16:14
351 查看
public class LoadListView extends ListView implements OnScrollListener { private int firstItem;// 当前可以见第一个Item的位置 private int lastItem;// 当前可以见最后一个Item的位置 private int totalItemCount;// list总数量 private OnLoadListener mListener;// 回调接口 private boolean isLoading = false;;// 是否正在加载 private View footer;// 底布局文件 private View head;// 头布局文件 private int headHeigth;// 布局高度 // 下拉刷新相关 private boolean isRemark;// 是否在第一个Item按下 private int startY;// 滑动开始前的Y值 private int state;// 当前状态 private final int NONE = 0;// 正常状态 private final int PULL = 1;// 提示下拉状态 private final int RELESE = 2;// 提示释放状态 private final int REFLASHING = 3;// 刷新状态状态 private int scrollState;// 当前listview的状态 public LoadListView(Context context) { super(context); initView(context); } public LoadListView(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } public LoadListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initView(context); } private void initView(Context context) { LayoutInflater mInflater = LayoutInflater.from(context); // 底布局操作相关 footer = mInflater.inflate(R.layout.listiview_footer, null); footer.findViewById(R.id.footer_ll_layout).setVisibility(View.GONE); this.addFooterView(footer); head = mInflater.inflate(R.layout.listview_head, null); // 通知父布局Head占用的大小 measureHead(head); // 获取高度 headHeigth = head.getMeasuredHeight(); // 设置头布局为高度的负值而隐藏 setHeaderPaddingTop(-headHeigth); this.addHeaderView(head); this.setOnScrollListener(this); } /** * 通知父布局Head占用的大小 (此处本人也未彻底搞懂) * * @param view */ private void measureHead(View view) { ViewGroup.LayoutParams p = view.getLayoutParams(); if (p == null) { p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } int width = ViewGroup.getChildMeasureSpec(0, 0, p.width); int height; int tempHeight = p.height; if (tempHeight > 0) { height = MeasureSpec.makeMeasureSpec(tempHeight, MeasureSpec.EXACTLY); } else { height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } view.measure(width, height); } /** * 设置Head布局的上边距,以达到隐藏头布局的目的 * * @param paddingTop */ private void setHeaderPaddingTop(int paddingTop) { head.setPadding(head.getPaddingLeft(), paddingTop, head.getPaddingRight(), head.getPaddingBottom()); // 刷新View的方法 head.invalidate(); } /** * 下拉刷新 监听手指的滑动状态 */ @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: // 如果实在顶部开始滑动 则记录当前y的位置,后面用来计算滑动的距离 if (firstItem == 0) { startY = (int) ev.getY(); isRemark = true; } break; case MotionEvent.ACTION_MOVE: onMove(ev);// 判断手指滑动过程中的动作 break; case MotionEvent.ACTION_UP: // 手指抬起后用来判断是否到达刷新数据要求的目的 if (state == RELESE) { state = REFLASHING; // 加载最新数据 reflushData(); } else if (state == PULL || state == NONE) { state = NONE; isRemark = false; reflushViewByState(); } break; } return super.onTouchEvent(ev); } private void onMove(MotionEvent ev) { if (!isRemark) { return; } int tempY = (int) ev.getY(); Log.v("y", tempY + ""); // 滑动的距离 int distance = tempY - startY; // 头布局慢慢显示出来的宽度 int topPadding = distance - headHeigth; switch (state) { case NONE: if (distance > 0) { state = PULL; reflushViewByState(); } else { } break; case PULL: // 绘制当前 拉动过程的头布局 setHeaderPaddingTop(topPadding); // 如果距离大于头布局+100 dp且ListView在滑动过程中 if (distance > headHeigth + 100 && scrollState == SCROLL_STATE_TOUCH_SCROLL) { state = RELESE; reflushViewByState(); } break; case RELESE: // 绘制当前 拉动过程的头布局 setHeaderPaddingTop(topPadding); if (distance < headHeigth + 100) { state = PULL; reflushViewByState(); } else if (distance <= 0) { state = NONE; isRemark = false; reflushViewByState(); } else if (distance > 500) { } break; } } /** * 刷新数据的执行方法 */ private void reflushData() { state = REFLASHING; isRemark = false; reflushViewByState(); mListener.onRefresh(); } /** * 根据当前状态改变界面显示 * * @param state */ private void reflushViewByState() { TextView tip = (TextView) head.findViewById(R.id.head_tv_tips); ImageView pic = (ImageView) head.findViewById(R.id.head_iv_pic); ProgressBar pb = (ProgressBar) head.findViewById(R.id.head_pb_progress); RotateAnimation anim = new RotateAnimation(0, 180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); anim.setDuration(500); anim.setFillAfter(true); RotateAnimation anim1 = new RotateAnimation(180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); anim1.setDuration(500); anim1.setFillAfter(true); switch (state) { case NONE: setHeaderPaddingTop(-headHeigth); break; case PULL: tip.setText("下拉可以刷新!"); pic.setVisibility(View.VISIBLE); pb.setVisibility(View.GONE); // 设置相关动画 pic.clearAnimation(); pic.setAnimation(anim); break; case RELESE: tip.setText("松开可以刷新!"); pic.setVisibility(View.VISIBLE); pb.setVisibility(View.GONE); // 设置相关动画 pic.setAnimation(anim1); break; case REFLASHING: setHeaderPaddingTop(0); tip.setText("正在刷新!"); pic.clearAnimation();// 这里一定要执行清楚动画,不然图片无法隐藏 pic.setVisibility(View.GONE); pb.setVisibility(View.VISIBLE); break; } } // 下拉刷新完成回调 public void reflushCompleted() { state = NONE; isRemark = false; reflushViewByState(); } // 分页加载完成回调 public void flushCompleted() { isLoading = false; footer.findViewById(R.id.footer_ll_layout).setVisibility(View.GONE); } public void setOnLoadListener(OnLoadListener listener) { this.mListener = listener; } public interface OnLoadListener { // 分页加载 void onLoadMore(); // 下拉刷新 void onRefresh(); } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if (lastItem == totalItemCount && SCROLL_STATE_IDLE == scrollState) { if (!isLoading) { footer.findViewById(R.id.footer_ll_layout).setVisibility( View.VISIBLE); mListener.onLoadMore(); isLoading = true; } } this.scrollState = scrollState; } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { this.lastItem = firstVisibleItem + visibleItemCount; this.totalItemCount = totalItemCount; this.firstItem = firstVisibleItem; } }
以上是实现了了下拉刷新和上拉加载第二页的ListView代码。
欢迎各位指出错误,大家多多指教。
相关文章推荐
- Android studio 閿欒 : 缂栫爜UTF-8鐨勪笉鍙 槧灏勫瓧绗?
- 互联网公司面试题总结1
- 打造一个自动检测页面是否存在XSS的小插件
- 解Linux进程间通信(IPC)方式
- 笔记本Win7低电量时自动关机的设置方法(降低硬盘损耗)
- html 、jsp笔记
- linux格式的U盘挂载了,但是打不开问题
- 【SuperMap .Net 组件】应用3DMax制作3D模型
- 在Debug模式下中断, 在Release模式下跳出当前函数的断言
- JVM调优总结
- WP8.1 双击两次返回键退出程序
- iOS 类增加成员变量
- 引用第三方jar时,混淆代码时的异常(Proguard)
- UVa - 102 - Ecological Bin Packing
- 简单实现拖动商品,加入购物车并总计商品的功能
- SQL Script for select data from ebs and make a csv file to FTP
- UVa - 102 - Ecological Bin Packing
- git命令之git stash apply和 pop 的区别
- 【SpringMVC】下载功能
- Win10在UEFI启动机制下无法更新升级的解决方法