文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2022-06-06 10:52

关注

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

您可能感兴趣的文章:Android下拉刷新ListView——RTPullListView(demo)Android中使用RecyclerView实现下拉刷新和上拉加载Android下拉刷新上拉加载控件(适用于所有View)Android RecyclerView实现下拉刷新和上拉加载android开发教程之实现listview下拉刷新和上拉刷新效果Android实现上拉加载更多以及下拉刷新功能(ListView)Android RecyclerView 上拉加载更多及下拉刷新功能的实现方法Android使用recyclerview打造真正的下拉刷新上拉加载效果Android ListView实现上拉加载更多和下拉刷新功能Android自定义View仿腾讯TIM下拉刷新View


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯