欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

android下拉刷新ListView的介绍和实现代码

程序员文章站 2023-11-26 18:49:10
    大致上,我们发现,下拉刷新的列表和一般列表的区别是,当滚动条在顶端的时候,再往下拉动就会把整个列表拉下来,显示出松开刷新的提示。由此可以看出,在构建这个下拉刷新的组...

    大致上,我们发现,下拉刷新的列表和一般列表的区别是,当滚动条在顶端的时候,再往下拉动就会把整个列表拉下来,显示出松开刷新的提示。由此可以看出,在构建这个下拉刷新的组件的时候,只用继承listview,然后重写ontouchevent就能实现。还有就是要能在xml布局文件中引用,还需要一个参数为context,attributeset的构造函数。

  表面上的功能大概就这些了。另一方面,刷新的行为似乎还没有定义,在刷新前做什么,刷新时要做什么,刷新完成后要做什么,这些行为写入一个接口中,然后让组件去实现。

  在整个组件的实现中,主体部分自然是ontouchevent的部分。这里需要做一些说明,在listview中,数据的滚动和listview.scrollto的行为是不一样的。数据的滚动是大概适配器的事。所以在不满足下拉整个列表的条件下,ontouchevent 应该返回super.ontouchevent(ev),让listview组件原本的ontouchevent去处理。

  考虑到组件的id和表头的布局需要事先定义,同时我想把这个组件应用于多个项目里,所以就把这个组件作为一个library去实现。

     下面就是具体的实现代码。

  首先来看一下表头的布局文件chenzong_push_refresh_header.xml:

复制代码 代码如下:

<?xml version="1.0" encoding="utf-8"?>
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="40dip"
       >
    <imageview
        android:layout_width="30dip"
        android:layout_height="40dip"
        android:background="@drawable/arrow_down"
           android:layout_alignparentleft="true"
        android:id="@+id/push_refresh_header_img"
        android:layout_marginleft="10dip"
        />
    <progressbar
        android:layout_width="40dip"
        android:layout_height="40dip"
        android:layout_alignparentleft="true"
        android:layout_marginleft="10dip"
        android:id="@+id/push_refresh_header_pb"
        style="@android:style/widget.progressbar.inverse"
        android:visibility="gone"/>
    <linearlayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerinparent="true"
        android:orientation="vertical"
        >
        <textview
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="最近一次更新在:"
            android:textcolor="#000000"
            />
        <textview
            android:layout_height="wrap_content"
            android:layout_width="wrap_content"
            android:id="@+id/push_refresh_header_date"
            android:textcolor="#000000"
            android:text="2013-03-04 08:03:38"/>
    </linearlayout>
</relativelayout>

       箭头、processbar和最近的一次刷新时间,表头文件就这三个元素。

       刷新的行为接口refreshoperation的代码:

复制代码 代码如下:

public interface refreshoperation {
    public void onrefreshstart();
    public void onrefreshing();
    public void onrefreshend();
}

     列表拉下来时,箭头翻转的动画arrow_rotate.xml:

复制代码 代码如下:

<?xml version="1.0" encoding="utf-8"?>
<rotate
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/linear_interpolator"
    android:fromdegrees="0"
    android:todegrees="180"
    android:duration="300"
    android:pivotx="50%"
    android:pivoty="50%"
    android:fillafter="true"
    android:repeatcount="0">

</rotate>

      这些文件和一些资源文件备齐了之后,接下来就是下拉刷新列表pushrefreshlist的具体实现:

复制代码 代码如下:

package com.chenzong;

import java.util.calendar;

import com.doall.pushrefreshlist.r;

import android.content.context;
import android.os.handler;
import android.os.message;
import android.util.attributeset;
import android.view.layoutinflater;
import android.view.motionevent;
import android.view.view;
import android.view.animation.animation;
import android.view.animation.animationutils;
import android.widget.listview;
import android.widget.textview;


public class pushrefreshlist extends listview implements refreshoperation{

    private int header_layout=r.layout.chenzong_push_refresh_header;
    //表头文件
    private int arrow_down=r.drawable.arrow_down;
    //箭头往下的资源
    private int arrow_up=r.drawable.arrow_up;
    //箭头往上的资源
    private int img=r.id.push_refresh_header_img;
    //显示箭头的控件id
    private int pb=r.id.push_refresh_header_pb;
    //刷新时的进度条
    private int startpoint=0;
    //触摸的起始点
    private refreshoperation refresh;
    //刷新行为的对象
    private animation animation=null;
    private context context;
    private view headerview;
    private int minpushheight;

   
    private final string tag="pushrefresh";

    public pushrefreshlist(context cotext, attributeset attrs) {
        super(context, attrs);
        view empty=new view(context);
        //判断是否到列表的顶端,通常要用到this.getfirstvisibleposition(),这里创建一个高度的为零view,加到headerview和数据之间
        this.addheaderview(empty);
        layoutinflater inflater=layoutinflater.from(context);
        headerview=inflater.inflate(header_layout, null);
        this.addheaderview(headerview);
        this.setrefreshoperation(this);
        this.context=context;

    }

    @override
    protected void onlayout(boolean changed, int l, int t, int r, int b) {
        this.minpushheight=headerview.getmeasuredheight();
        //获取下拉刷新的触发高度
        super.onlayout(changed, l, t, r, b);
    }

    private boolean canhandleevent(int dy)
    {
        return (dy<0&&this.getfirstvisibleposition()==0&&!ispbvisible());
    }

    @override
    public boolean ontouchevent(motionevent ev) {

        int action=ev.getaction();
        switch(action)
        {
        case motionevent.action_down:
            startpoint=(int)ev.gety();
            break;
        case motionevent.action_move:
            int dy=startpoint-(int)ev.gety();
            if(canhandleevent(dy))
            {
                if(animation==null)
                {
                    if(math.abs(this.getscrolly())>=this.minpushheight)
                    {   
                        animation=animationutils.loadanimation(context, r.anim.arrow_rotate);
                        view mview=headerview.findviewbyid(img);
                        mview.startanimation(animation);
                        this.setscrollbarfadingenabled(true);
                    }
                }
                this.scrollto(0,dy/2);   
                return true;
            }
            break;
        case motionevent.action_up:

                this.setscrollbarfadingenabled(false);
                if(animation!=null)
                {
                    setimgbackgroundup();
                    switchcompent(view.invisible,view.visible);
                    this.scrollto(0,-minpushheight);
                    pushrefreshlist.this.refresh.onrefreshstart();
                    new thread(mrunnable).start();
                    animation=null;
                }
                else
                    this.scrollto(0,0);
            break;
        }
        return super.ontouchevent(ev);
    }

    private runnable mrunnable=new runnable()
    {

        @override
        public void run() {
            pushrefreshlist.this.refresh.onrefreshing();
            mhandler.obtainmessage().sendtotarget();
        }
    };

    private handler mhandler=new handler()
    {
        @override
        public void handlemessage(message msg) {
            pushrefreshlist.this.refresh.onrefreshend();
            pushrefreshlist.this.scrollto(0, 0);
            pushrefreshlist.this.setimgbackgrounddown();
            pushrefreshlist.this.switchcompent(view.visible, view.gone);
            textview tv=(textview)headerview.findviewbyid(r.id.push_refresh_header_date);
            tv.settext(this.getdatestr());
        }

        private string getdatestr()
        {
            calendar ca=calendar.getinstance();
            int year=ca.get(calendar.year);
            int month=ca.get(calendar.month);
            int date=ca.get(calendar.date);
            int hour=ca.get(calendar.hour);
            int mintes=ca.get(calendar.minute);
            int second=ca.get(calendar.second);
            return year+"-"+(month+1)+"-"+date+" "+hour+":"+mintes+":"+second;
        }
    };

    private void switchcompent(int imgstatus,int pbstatus)
    {
        view img=headerview.findviewbyid(r.id.push_refresh_header_img);
        img.clearanimation();
        //执行了动画的控件如果不调用clearanimation,setvisibility(view.gone)会失效
        img.setvisibility(imgstatus);
        headerview.findviewbyid(r.id.push_refresh_header_pb).setvisibility(pbstatus);
    }

    private boolean ispbvisible()
    {
        return view.visible==headerview.findviewbyid(r.id.push_refresh_header_pb).getvisibility();
    }

    private void setimgbackgroundup()
    {
        view mview=headerview.findviewbyid(this.img);
        mview.setbackgroundresource(arrow_up);
    }

    private void setimgbackgrounddown()
    {
        view mview=headerview.findviewbyid(this.img);
        mview.setbackgroundresource(arrow_down);
    }

    public void setrefreshoperation(refreshoperation refresh)
    {
        this.refresh=refresh;
    }

    @override
    public void onrefreshstart() {

    }

    @override
    public void onrefreshing() {

    }

    @override
    public void onrefreshend() {
    }