Android ListView 疯狂之旅 之 《自定义下拉刷新功能的ListView》

Android ListView 疯狂之旅 之 《自定义下拉刷新功能的ListView》,第1张

概述效果图:一首先创建一个类,继承ListView,编写其构造方法publicclassRefreshListViewextendsListView{publicRefreshListView(Contextcontext){this(context,null);}publicRefreshListView(Contextcontext,AttributeSetattrs){

效果图:

一 首先创建一个类,继承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》所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/999567.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存