进一步封装ListView,实现下拉刷新和分页刷新的功能
来源:互联网 发布:ios软件删不掉怎么办 编辑:程序博客网 时间:2024/05/08 01:34
import android.content.Context;import android.util.AttributeSet;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.view.animation.RotateAnimation;import android.widget.AbsListView;import android.widget.ImageView;import android.widget.ListView;import android.widget.ProgressBar;import android.widget.TextView;import android.widget.AbsListView.OnScrollListener;public class MyListView extends ListView implements OnScrollListener { private View footer; //下拉刷新 private View header; //分页 private int firstVisibleItem; //第一个可见列表项的下标 private int lastVisibleItem; //最后一个可见列表项的下标 private int totalItemCount; //总共有多少个列表项 private int scrollState; //listView当前滚动状态 private boolean isLoading; /** * 分页加载接口 */ private ILoadListener iLoadListener; /** * 刷新数据接口 */ private IReflashListener iReflashListener; /** * */ private LayoutInflater inflater; /** * 下拉刷新头部的高度 */ private int headerHeight; private boolean isTopDown; //标记是否在列表的顶端按下 private int startY; //在列表的顶端按下的Y值 private int state; //当前的状态 private final int NONE = 0; //正常状态 private final int PULL = 1; //提示下拉状态 private final int RELEASE = 2; //提示释放状态 private final int REFLASHING = 3; //刷新状态 public MyListView(Context context) { super(context); // TODO Auto-generated constructor stub initView(context); } public MyListView(Context context, boolean hasHeader, boolean hasFooter) { super(context); initView(context); if (hasHeader) { setDefaultHeaderView(); } if (hasFooter) { setDefaultFooterView(); } } public MyListView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub initView(context); } public MyListView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); // TODO Auto-generated constructor stub initView(context); } /** * 设置底部刷新的布局 * @param viewId 布局的id(R.layout....) */ public void setFooterView(int viewId) { footer = inflater.inflate(viewId, null); footer.setVisibility(View.GONE); this.addFooterView(footer); } /** * 设置默认的底部刷新布局 */ public void setDefaultFooterView() { footer = inflater.inflate(R.layout.lv_footer_layout, null); footer.setVisibility(View.GONE); this.addFooterView(footer); } /** * 设置头部刷新布局 * @param viewId 布局的id(R.layout....) */ public void setHeaderView(int viewId) { header = inflater.inflate(viewId, null); header.setVisibility(View.GONE); this.addHeaderView(header); } /** * 设置默认的头部刷新布局 */ public void setDefaultHeaderView() { header = inflater.inflate(R.layout.lv_header_layout, null); measureView(header); hideHeader(); this.addHeaderView(header); } /** * 添加底部加载提示布局到listView * @param context */ private void initView(Context context) { this.inflater = LayoutInflater.from(context); setOnScrollListener(this); } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { // TODO Auto-generated method stub this.scrollState = scrollState; /* * 若滑动到ListView的底部,并且不再滑动状态的时候,显示分页刷新脚布局 * 否则隐藏该布局 */ if (scrollState == SCROLL_STATE_IDLE && lastVisibleItem == totalItemCount) { if (!isLoading) { showFooter(); //通过回调方法实现加载数据 iLoadListener.onLoad(); isLoading = false; } } else { hideFooter(); } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { // TODO Auto-generated method stub //记录第一行课件列表项的下标 this.firstVisibleItem = firstVisibleItem; //计算最后一行课件列表项的下标 this.lastVisibleItem = firstVisibleItem + visibleItemCount; //总共有多少个列表项 this.totalItemCount = totalItemCount; } @Override public boolean onTouchEvent(MotionEvent ev) { // TODO Auto-generated method stub /** * 这里实现下拉刷新的功能,通过监听手势的按下,移动,松开来实现 */ switch (ev.getAction()) { /* * 当按下屏幕的时候,如果第一行可见的列表项恰好是列表项的第一个时,把isTopDown标记值设置成true * 并记录开始的时候的Y坐标 */ case MotionEvent.ACTION_DOWN: if (firstVisibleItem == 0) { isTopDown = true; startY = (int) ev.getY(); } break; /** * 当动作是移动的时候,这时就要处理图片该如何显示的问题,因为下拉高度不同显示的图片和文字都不同 */ case MotionEvent.ACTION_MOVE: onMove(ev); break; /** * 当动作是松开的时候,要判断两种状态: * 1.如果下拉的高度足够,RELEASE也就是,那么就可以刷新,这时把状态设置成REFLASHING * 2.如果下拉的状态不够,那么不能刷新,这时把状态设置成NONE,并且把标识isTopDown设置成false */ case MotionEvent.ACTION_UP: if (state == RELEASE) { state = REFLASHING; //设置界面应该如何显示 reflashViewByState(); setHeaderPaddingTop(10); //加载数据 iReflashListener.onReflash(); } else if (state == PULL) { state = NONE; isTopDown = false; //设置界面应该如何显示 reflashViewByState(); } break; default: break; } return super.onTouchEvent(ev); } private void onMove(MotionEvent ev) { // TODO Auto-generated method stub //如果该移动操作不是在顶部下拉的,那么不执行操作,直接返回 if (!isTopDown) { return; } int tempY = (int) ev.getY(); //记录下拉了多少距离 int space = tempY - startY; int topPadding = space - headerHeight; switch (state) { case NONE: if (space > 0) { state = PULL; reflashViewByState(); } break; case PULL: setHeaderPaddingTop(topPadding); if (space > headerHeight + 30 && scrollState == SCROLL_STATE_TOUCH_SCROLL) { state = RELEASE; reflashViewByState(); } break; case RELEASE: setHeaderPaddingTop(topPadding); if (space < headerHeight + 30) { state = PULL; reflashViewByState(); } else if (space <= 0) { state = NONE; isTopDown = false; reflashViewByState(); } break; } } private void reflashViewByState() { TextView tip = (TextView) header.findViewById(R.id.tv_flash); ImageView arrow = (ImageView) header.findViewById(R.id.iv_flash); ProgressBar progress = (ProgressBar) header.findViewById(R.id.pb_flash); RotateAnimation anim1 = new RotateAnimation(0, 180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); anim1.setDuration(500); anim1.setFillAfter(true); RotateAnimation anim2 = new RotateAnimation(180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); anim2.setDuration(500); anim2.setFillAfter(true); switch (state) { case NONE: setHeaderPaddingTop(-headerHeight); arrow.clearAnimation(); break; case PULL: arrow.setVisibility(View.VISIBLE); progress.setVisibility(View.GONE); tip.setText("下拉可以刷新"); arrow.clearAnimation(); arrow.setAnimation(anim2); break; case RELEASE: arrow.setVisibility(View.VISIBLE); progress.setVisibility(View.GONE); tip.setText("释放立即刷新"); arrow.clearAnimation(); arrow.setAnimation(anim1); break; case REFLASHING: setHeaderPaddingTop(headerHeight); arrow.setVisibility(View.GONE); progress.setVisibility(View.VISIBLE); tip.setText("正在刷新"); arrow.clearAnimation(); break; default: break; } } public void reflashComplete() { state = NONE; isTopDown = false; reflashViewByState(); } public void setILoadListener(ILoadListener iLoadListener) { this.iLoadListener = iLoadListener; } public interface ILoadListener { public void onLoad(); } /** * 刷新数据接口 * @author raid * */ public interface IReflashListener { public void onReflash(); } public void setIReflashListener(IReflashListener iReflashListener) { this.iReflashListener = iReflashListener; } /** * 加载完毕 */ public void loadComplete() { isLoading = false; hideFooter(); } /** * 如果用户不需要分页功能,没有设置footer, * 那么隐藏footer的时候需要判断footer是否为空 */ private void hideFooter() { if (footer != null) { footer.setVisibility(View.GONE); } } /** * 如果用户不需要分页功能,没有设置footer, * 那么显示footer的时候需要判断footer是否为空 */ private void showFooter() { if (footer != null) { footer.setVisibility(View.VISIBLE); } } /** * 隐藏header */ private void hideHeader() { headerHeight = header.getMeasuredHeight(); setHeaderPaddingTop(-headerHeight); } /** * 设置组件的上内边距 * @param paddingTop 上内边距 */ private void setHeaderPaddingTop(int paddingTop) { header.setPadding(header.getPaddingLeft(), paddingTop, header.getPaddingRight(), header.getPaddingBottom()); header.invalidate(); } /** * 由于Android程序的运行机制决定了无法再组件类外部使用getWidth和getHeight方法 * 获得高度和宽度(在自定义组件类中可以实现),必须使用View.getMeasuredWidth * 和View.getMeasureHeight方法获得当前组件的宽度和高度, * 在调用这两个方法之前,必须调用View.measure方法先测量组件宽度和高度。 * 如果想直接获取在布局文件中定义的组件的宽度和高度, * 可以直接使用View.getLayoutParams().width和View.getLayoutParams()... * * 通知父布局,占用的宽,高 * @param view */ private void measureView(View view) { ViewGroup.LayoutParams p = view.getLayoutParams(); if (p == null) { p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } /** * 有三个参数,分别代表: * 1.父View的详细测量值(即MeasureSpec) * 2.view的内外边距 * 3.子布局的宽度 */ 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); }}
lv_footer_layout.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" android:padding="15dp" android:gravity="center" > <ProgressBar android:layout_width="wrap_content" android:layout_height="30dp" android:layout_gravity="center"/><TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:paddingLeft="10dp" android:text="加载中..."/> </LinearLayout>
lv_header_layout.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" android:padding="15dp" android:gravity="center" android:background="#5E5E5D" > <RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="20dp"> <ImageView android:id="@+id/iv_flash" android:layout_width="wrap_content" android:layout_height="wrap_content" android:scaleType="fitCenter" android:src="@drawable/pull_to_refresh_arrow"/> <ProgressBar android:id="@+id/pb_flash" android:layout_width="wrap_content" android:layout_height="wrap_content" style="?android:attr/progressBarStyleSmall"/> </RelativeLayout> <TextView android:id="@+id/tv_flash" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="下拉可以刷新" android:textSize="20sp" android:textColor="#EBEDEC"/></LinearLayout>
0 0
- 进一步封装ListView,实现下拉刷新和分页刷新的功能
- 实现ListView的下拉刷新功能
- 实现listview下拉刷新功能
- listView分页和listview下拉刷新
- ListView封装实现下拉刷新和上拉加载
- Android 实现listview 分页加载和下拉刷新
- Listview,顶部加viewpager,并且带有上拉刷新和下拉分页功能的展示
- ListView下拉刷新的实现
- ListView下拉刷新的实现
- 使用PullToRefresh实现下拉刷新和分页加载功能
- 自定义ListView实现下拉刷新功能
- Android中实现适用于ListView的下拉刷新功能
- android下拉刷新功能---教你实现简单的ListView下拉刷新
- 下拉刷新功能的实现。
- 关于ListView的下拉刷新和上拉加载功能
- 带有上拉加载下拉刷新和可滑动删除功能的ListView的简单实现
- listview实现下拉刷新
- ListView实现下拉刷新
- GCD的基本使用
- 栈 (Stack) 的C++实现(链表方法)
- 堆排序的递归和非递归实现(C++版)
- GCD的常用方法
- QListWidget和QListWidgetItem的简单使用
- 进一步封装ListView,实现下拉刷新和分页刷新的功能
- 函数式编程扫盲篇
- 面向对象
- OC动画组
- mysql 常见问题:ERROR 2003 (HY000) Can't connect to MySQL server on 'localhost' (10061)
- 栈和队列之用2个栈实现一个队列
- Qt入门-列表框QListWidget类
- 深入浅出聊Unity3D项目优化:从Draw Calls到GC
- jsp的生命周期(摘录)