效果图:
一 首先创建一个类,继承ListVIEw,编写其构造方法public class RefreshListVIEw extends ListVIEw { public RefreshListVIEw(Context context) { this(context, null); } public RefreshListVIEw(Context context, AttributeSet attrs) { this(context, attrs, 0); } public RefreshListVIEw(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private voID init() { }}
二 在activity中使用我们的RefreshListVIEw控件向ListVIEw中设置数据的过程与我们androID中提供的ListVIEw设置数据的方式一至,这里就不贴出代码块了
此时运行的效果图
可以看到与我们正常的ListVIEw是一样的
三 向RefresListVIEw中添加我们下拉刷新使用到的头布局头布局中的显示,包括显示下拉状态的向下的指示箭头,包括指示正在加载中的圆形进度条,包括显示状态与时间的文本框
定义头布局文件xListvIEw_footer.xml文件中
<pre name="code" ><?xml version="1.0" enCoding="utf-8"?><linearLayout xmlns:androID="http://schemas.androID.com/apk/res/androID" androID:layout_wIDth="fill_parent" androID:layout_height="wrap_content" androID:gravity="bottom" > <relativeLayout androID:ID="@+ID/xListvIEw_header_content" androID:layout_wIDth="fill_parent" androID:layout_height="60dp" > <linearLayout androID:layout_wIDth="wrap_content" androID:layout_height="wrap_content" androID:layout_centerInParent="true" androID:gravity="center" androID:orIEntation="vertical" androID:ID="@+ID/xListvIEw_header_text"> <TextVIEw androID:ID="@+ID/xListvIEw_header_hint_textvIEw" androID:layout_wIDth="wrap_content" androID:layout_height="wrap_content" androID:text="下拉刷新" /> <linearLayout androID:layout_wIDth="wrap_content" androID:layout_height="wrap_content" androID:layout_margintop="3dp" > <TextVIEw androID:layout_wIDth="wrap_content" androID:layout_height="wrap_content" androID:text="上次更新时间:" androID:textSize="12sp" /> <TextVIEw androID:ID="@+ID/xListvIEw_header_time" androID:layout_wIDth="wrap_content" androID:layout_height="wrap_content" androID:textSize="12sp" /> </linearLayout> </linearLayout> <ImageVIEw androID:ID="@+ID/xListvIEw_header_arrow" androID:layout_wIDth="wrap_content" androID:layout_height="wrap_content" androID:layout_alignleft="@ID/xListvIEw_header_text" androID:layout_centerVertical="true" androID:layout_marginleft="-35dp" androID:src="@drawable/xListvIEw_arrow" /> <Progressbar androID:ID="@+ID/xListvIEw_header_progressbar" androID:layout_wIDth="30dp" androID:layout_height="30dp" androID:layout_alignleft="@ID/xListvIEw_header_text" androID:layout_centerVertical="true" androID:layout_marginleft="-40dp" androID:visibility="visible" /> </relativeLayout></linearLayout>
将头布局文件添加给ListVIEw
在RefresListVIEw中
private voID init(Context context) { VIEw vIEw = VIEw.inflate(context,R.layout.xListvIEw_header,null); this.addheaderVIEw(vIEw); }
四 隐藏我们添加的头布局
首先让系统去帮我们测量头布局的高度,测量好后,我们就可以设置头布局的显示位置
private voID init(Context context) { VIEw vIEw = VIEw.inflate(context, R.layout.xListvIEw_header, null); vIEw.measure(0, 0); final int measuredHeight = vIEw.getMeasuredHeight(); vIEw.setpadding(0,-measuredHeight,0,0); this.addheaderVIEw(vIEw); }
五 设置头布局与lisVIEw的联动使用我们的控件实现OntouchListener接口,并复写ontouch方法
import androID.vIEw.VIEw.OntouchListener;public class RefreshListVIEw extends ListVIEw implements OntouchListener {....@OverrIDe public boolean ontouch(VIEw v, MotionEvent event) { return true; }}
在ontouch方法中我们需要重新设置显示头布局,所以我们需要将部分变量修改为成员变量
private voID init(Context context) { setontouchListener(this); //获取头布局 mheaderVIEw = VIEw.inflate(context, R.layout.xListvIEw_header, null); //进行测量 mheaderVIEw.measure(0, 0); //获取头布局的高度 mheaderHeight = mheaderVIEw.getMeasuredHeight(); //设置头布局显示 mheaderVIEw.setpadding(0, -mheaderHeight, 0, 0); //添加到ListVIEw中 this.addheaderVIEw(mheaderVIEw); }
在ontouch方法中进行设置显示随ListVIEw的滑动而显示的头布局
@OverrIDe public boolean ontouchEvent( MotionEvent event) { int downY = 0; switch ( event.getAction()) { case MotionEvent.ACTION_DOWN: //获取按下时的Y轴的位置 downY = (int)event.getY(); break; case MotionEvent.ACTION_MOVE: int moveY = (int)event.getY(); //计算在Y轴方向的滑动偏移量, int diffY = moveY - downY; //计算我们的头布局需要移动的距离 int paddingtop = -mheaderHeight +diffY; //设置显示头布局 mheaderVIEw.setpadding(0,paddingtop,0,0); break; default: break; } return true; }
注:这里之所以使用使用的是-mheaderHeight高度,是因为我们在上面设置的头布局的paddingtop的大小正好是头布局的高度,也就是说刚刚好将头布局显示在屏幕外侧
优化代码
//设置显示头布局,当显示的条目为第一条的时候并且移动的距离大于0的时候再开时向下移动 if(getFirstVisibleposition()==0&&diffY>0){ mheaderVIEw.setpadding(0,paddingtop,0,0); return true; }
六 定义更新下拉刷新过程中的头布局显示变化
定义下拉至释放刷新的中的变量
// 代表下拉刷新状态 private final int PulL_REFRESH_STATE = 0; // 释放刷新状态 private final int RELEASE_STATE = 1; // 正在刷新状态 private final int RELEASEING = 2; // 默认当前是下拉刷新状态 private int header_current_state = PulL_REFRESH_STATE;
创建更新头布局的方法
//更新头布局的方法 private voID updateheaderVIEw() { switch (header_current_state) { case PulL_REFRESH_STATE: //下拉刷新状态 break; case RELEASE_STATE: //释放刷新状态 break; case RELEASEING: //正在刷新的状态 break; } }
在ontouchEvent方法 中ACTION_MOVE事件处理中调用使用我们的更新头布局的方法
case MotionEvent.ACTION_MOVE: int moveY = (int)event.getY(); //计算在Y轴方向的滑动偏移量, int diffY = moveY - downY; //计算我们的头布局需要移动的距离 int paddingtop = -mheaderHeight +diffY; //设置显示头布局,当显示的条目为第一条的时候并且移动的距离大于0的时候再开时向下移动 if(getFirstVisibleposition()==0&&diffY>0){ //判断paddingtop 来更新头布局 if (paddingtop > 0 && header_current_state != RELEASE_STATE) { // System.out.println("进入释放刷新状态"); header_current_state = RELEASE_STATE; // 更新头布局状态 updateheaderVIEw(); } else if (paddingtop < 0 && header_current_state != PulL_REFRESH_STATE) { // System.out.println("~~~~下拉刷新状态~~~~"); header_current_state = PulL_REFRESH_STATE; updateheaderVIEw(); } mheaderVIEw.setpadding(0,paddingtop,0,0); return true; }
然后我们在方法updateheaderVIEw这个方法中对应的状态下更新设置显示我们头布局中的信息
//显示下拉上拉正在刷新状态的textvIEw mXListvIEwheaderHintTextvIEw = (TextVIEw) mheaderVIEw.findVIEwByID(R.ID.xListvIEw_header_hint_textvIEw); //头布局中显示时间的控件 mXListvIEwheaderTime = (TextVIEw) mheaderVIEw.findVIEwByID(R.ID.xListvIEw_header_time); //头布局中显示的指示箭头 mXListvIEwheaderArrow = (ImageVIEw) mheaderVIEw.findVIEwByID(R.ID.xListvIEw_header_arrow); //头布局中显示的加载圆形进度条 mXListvIEwheaderProgressbar = (Progressbar) mheaderVIEw.findVIEwByID(R.ID.xListvIEw_header_progressbar);
当头布局出现在屏幕上,但是还没有完全显示在屏幕上的时候,指示箭头应当向下,状太信息应当为下拉刷新
当头布局完全显示在屏幕上的时候,指示箭头指示方向向上,状态为释放刷新
//更新头布局的方法 private voID updateheaderVIEw() { switch (header_current_state) { case PulL_REFRESH_STATE: //下拉刷新状态 //[1]更改iv状态 mXListvIEwheaderArrow.startAnimation(downAnimation); //[2]设置 tv_update 状态 mXListvIEwheaderHintTextvIEw.setText("下拉刷新"); //[3]隐藏头布局 mheaderVIEw.setpadding(0, -mheaderHeight, 0, 0); break; case RELEASE_STATE: //释放刷新状态 mXListvIEwheaderArrow.startAnimation(upAnimation); mXListvIEwheaderHintTextvIEw.setText("释放刷新"); break; case RELEASEING: //正在刷新的状态 //[1]把动画图片隐藏 mXListvIEwheaderArrow.setVisibility(VIEw.INVISIBLE); mXListvIEwheaderArrow.clearanimation(); //[2]显示进度条 mXListvIEwheaderProgressbar.setVisibility(VIEw.VISIBLE); //[3]刷新状态的文字改为 正在刷新 mXListvIEwheaderHintTextvIEw.setText("正在刷新ing"); //[4]设置头布局回到屏幕顶部 mheaderVIEw.setpadding(0, 0, 0, 0); break; }
在ontouchEvent中处理ACTION_UP事件
如果当前的状态是释放刷新,那当手指抬起的时候,我们将要进行正在刷新状态,并进行相关UI显示更新 *** 作
case MotionEvent.ACTION_UP: if (header_current_state == PulL_REFRESH_STATE) { updateheaderVIEw(); }else if (header_current_state == RELEASE_STATE) { //[1]把正在刷新状态 赋值给 当前状态 header_current_state = RELEASEING; //[2]调用更新头布局的方法 updateheaderVIEw(); //[3]更新为下拉状态// header_current_state =PulL_REFRESH_STATE; } break;
可以看到上面使用到了将指示箭头进行旋转 *** 作的动画,可以在构造中进行初始化 *** 作
private RotateAnimation upAnimation; private RotateAnimation downAnimation;//初始化头布局 图片旋转的动画 private voID initAnim() { //向上旋转的动画 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); }
七 设置下拉刷新的监听回调接口
//设置下拉刷新数据的接口 public interface OnPullDownRefreshListener{ public voID onPullDownRefresh(); } private OnPullDownRefreshListener mOnPullDownRefreshListener; //设置刷新的监听 public voID setonPullDownRefreshListener(OnPullDownRefreshListener Listener){ mOnPullDownRefreshListener = Listener; }
然后在ontouchEvent方法中的ACTION_UP事件中片回调
if (mOnPullDownRefreshListener!=null) { mOnPullDownRefreshListener.onRefresh(); }
八 设置加载数据完成后,隐藏头布局并更新显示时间
ublic voID setonLoadFinish() { //[0]进度条隐藏 mXListvIEwheaderProgressbar.setVisibility(VIEw.INVISIBLE); //[2]在这里更新时间 mXListvIEwheaderTime.setText(getCurrentTimerr()); //[3]隐藏头布局 mheaderVIEw.setpadding(0, -mheaderHeight, 0, 0); //[4]把状态置为下拉状态 header_current_state = PulL_REFRESH_STATE; }
也就是说当我们的数据更新完毕后,需要调用我们设置的方法将显示刷新头布局隐藏,并更新相应的状态与显示信息更新刷新显示的时间 :
public String getCurrentTimerr(){ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return sdf.format(new Date()); }
到这里,我们的这个完整的具有下拉刷新功能的ListVIEw就可以进行使用了
九 添加上拉加载更多数据功能private voID initFootVIEw() { //[1]通过打气筒把一个布局转换成一个vIEw对象 mfootVIEw = VIEw.inflate(getContext(), R.layout.xListvIEw_footer, null); mfootVIEw.measure(0, 0); footHeight = mfootVIEw.getMeasuredHeight(); //[1]默认情况隐藏脚布局 mfootVIEw.setpadding(0, -footHeight, 0, 0); //[2]添加脚布局 this.addFooterVIEw(mfootVIEw); //[3]给ListvIEw设置滑动监听 this.setonScrollListener(this); }
脚布局文件中 :
<pre name="code" ><?xml version="1.0" enCoding="utf-8"?> <relativeLayout xmlns:androID="http://schemas.androID.com/apk/res/androID" androID:layout_wIDth="fill_parent" androID:layout_height="wrap_content" androID:padding="10dp" > <TextVIEw androID:ID="@+ID/xListvIEw_footer_hint_textvIEw" androID:layout_wIDth="wrap_content" androID:layout_height="wrap_content" androID:layout_centerInParent="true" androID:text="@string/xListvIEw_footer_hint_normal" /> <Progressbar androID:layout_toleftOf="@ID/xListvIEw_footer_hint_textvIEw" androID:ID="@+ID/xListvIEw_footer_progressbar" androID:layout_wIDth="wrap_content" androID:layout_height="wrap_content" androID:visibility="visible" /> </relativeLayout>
可以看到这里设置了一个滑动监听,在这里我们需要将我们的控件实现滑动监听事件
public class RefreshListVIEw extends ListVIEw implements AbsListVIEw.OnScrollListener {... @OverrIDe public voID onScrollStateChanged(AbsListVIEw vIEw, int scrollState) { } @OverrIDe public voID onScroll(AbsListVIEw vIEw, int firstVisibleItem, int visibleItemCount, int totalitemCount) { }}
设置上拉加载更多的回调监听
private OnUpLoadingMoreListener mOnUpLoadingMoreListener; public voID setonLoadingMoreListener(OnUpLoadingMoreListener l){ mOnUpLoadingMoreListener = l; } public interface OnUpLoadingMoreListener{ public voID onl oadingMore(); }
在ListVIEw的滑动监听事件中回调监听方法
@OverrIDe public voID onScrollStateChanged(AbsListVIEw vIEw, int scrollState) { if (scrollState== SCRolL_STATE_IDLE ||scrollState == SCRolL_STATE_FliNG) { //判断lisvIEw 是否滑动到了底部 if (getLastVisibleposition()==getCount()-1 ) { //[1]把脚布局显示出来 mfootVIEw.setpadding(0, 0, 0, 0); if (mOnUpLoadingMoreListener!=null) { mOnUpLoadingMoreListener.onLoadingMore(); } } } }
设置加载完成后调用方法来隐藏加载更多的显示布局
//加载更多完成 需要处理的逻辑 public voID setonLoadIngMoreFinish() { //[1]把加载更多脚布局隐藏 mfootVIEw.setpadding(0, -footHeight, 0, 0); }
点击下载源码
下载密码:uvfr
AndroID ListVIEw 疯狂之旅 第一季 《自定义侧拉删除》 | 点击打开链接查看 |
AndroID ListVIEw 疯狂之旅 第二季 《分组排序显示数据》 | 点击打开链接查看 |
最新脑筋急转: 男人与女人一起比赛猜智力题 ,一般女人会赢,因为”难得糊涂“,男的糊涂
以上是内存溢出为你收集整理的Android ListView 疯狂之旅 之 《自定义下拉刷新功能的ListView》全部内容,希望文章能够帮你解决Android ListView 疯狂之旅 之 《自定义下拉刷新功能的ListView》所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)