广

android开发

  • IOS开发
  • android开发
  • PHP编程
  • JavaScript
  • ASP.NET
  • ASP编程
  • JSP编程
  • Java编程
  • 易语言
  • Ruby编程
  • Perl编程
  • AJAX
  • 正则表达式
  • C语言
  • 编程开发

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

    2018-04-07 07:50:20 次阅读 稿源:互联网
    广告

        大致上,我们发现,下拉刷新的列表和一般列表的区别是,当滚动条在顶端的时候,再往下拉动就会把整个列表拉下来,显示出松开刷新的提示。由此可以看出,在构建这个下拉刷新的组件的时候,只用继承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() {
        }

    一起学吧部分文章转载自互联网,供读者交流和学习,若有涉及作者版权等问题请及时与我们联系,以便更正、删除或按规定办理。感谢所有提供资讯的网站,欢迎各类媒体与一起学吧进行文章共享合作。

    广告
    广告
    广告