android下拉刷新ListView的介绍和实现代码
android下拉刷新ListView的介绍和实现代码
发布时间:2016-12-28 来源:查字典编辑
摘要:大致上,我们发现,下拉刷新的列表和一般列表的区别是,当滚动条在顶端的时候,再往下拉动就会把整个列表拉下来,显示出松开刷新的提示。由此可以看出...

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

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() {

}

推荐文章
猜你喜欢
附近的人在看
推荐阅读
拓展阅读
相关阅读
网友关注
最新安卓软件开发学习
热门安卓软件开发学习
编程开发子分类