自定义ListView,产生下拉刷新效果

/ 0评 / 0

在介绍下拉刷新的实现之前,先看看效果图,可以看到,除了丑了一点,效果还是不错的,下面就来正式开始介绍实现。

ListView

总体介绍

首先我们思考下,要实现这个效果,需要些什么

给ListView添加下拉的视图

我们可以看到,下拉布局里面包括一个下拉箭头(ImageView),一个提示的文字(TextView),一个刷新时的进度条(ProgressBar),当然,有的人还多用一个TextView用于显示上次刷新时间,不过原理都是一样的,下面是下拉布局的xml文件,其中的进度条一开始是隐藏的

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="match_parent"
    android:layout_width="match_parent">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="@string/updata"
        android:textSize="23sp" />

    <ImageView
        android:id="@+id/arrow"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_toLeftOf="@id/text"
        android:src="@drawable/arrow" />

    <ProgressBar
        android:id="@+id/progress"
        style="?android:attr/progressBarStyle"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_toLeftOf="@id/text"
        android:visibility="gone" />

</RelativeLayout>
</LinearLayout>

ListView有一个成员函数addHeaderView(View v)用于添加一个view到ListView的头部,通过这个函数我们就可以把上面定义的布局文件通过View.inflate()加载出来,添加到ListView的头部

通过上面介绍的一个函数,我们就可以添加一个布局到ListView的头部了,可是这样并不是我们想要的样子,我们还需要把他给隐藏,而且希望在滑动的时候这个视图慢慢的出来或者消失,这个效果,我们可以通过setPadding()来设置头部布局的内边距,当顶部的内边距为负的总高度时,这个视图就隐藏了。当手指下拉的时候,根据滑动的距离,设置内部顶部边距,就可以实现顶部视图随手指滑动而移动的效果了

给ListView添加滑动监听

我选择的是直接覆写OnTouch方法实现点击监听,当手指移动的时候,判断ListView的第一项是否是在最顶部,在最顶部则记录当前手指的位置,继续移动,这判断从上次开始移动到目前的距离,用于设置内部上边距

/**
 * 实现点击监听
 */
@Override
public boolean onTouchEvent(MotionEvent ev) {
    switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
        break;
        case MotionEvent.ACTION_MOVE:
        break;
        case MotionEvent.ACTION_UP:
        break;
    }
    return super.onTouchEvent(ev);
}

判断当前ListView当前是不是最顶部也很简单,实现OnScrollListener接口,覆写如下方法。

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}

此方法最重要的是后面几个参数

firstVisibleItem:第一个可见的item的编号,从0开始

visibleItemCount:屏幕可见的item总数

totalItemCount:ListView全部item数量

这里我们主要使用的是firstVisibleItem,当firstVisibleItem为0的时候,说明ListView已经到了最顶部,如果继续拉下,则表示需要显示下拉视图了,这时记录手指的位置,然后根据继续下拉的距离,就可以慢慢显示下拉视图了,当松开手以后,根据已经下拉的距离,如果大于一定值就开始刷新,如果达到刷新的距离那就直接复原(重新隐藏下拉视图就行)。

总结一下,在下拉过程中发生的事:

用户点击屏幕开始下拉⇒距离达到一定程度(例子中是当下拉视图全部显示时),改变提示文字“下拉刷新”为"松开手指刷新"⇒释放手指,根据已经下拉的距离判断是否刷新或者直接隐藏下拉框

刷新的时候,视图的变化我封装成一个函数updateViewByState(),根据状态更新视图,不过为了突出重点,大家可以在源码里面看,不过大致的思路就是这样了

关于刷新

关于数据刷新的问题,我使用了接口回调的方式,在类中定义了一个接口,然后对外提供设置接口的方法,当外部需要调用刷新的时候,就可以实现这个接口,然后通过我提供的setOnUpdateListener方法传递进来一个接口的实例,类似于控件的setOnClick()方法

/**
 * 接口变量,用于保存调用者传过来的对象
 */
private UpdateView listener = null;

/**
 * 回调接口,用于给调用者刷新
 */
public interface UpdateView {
    public void updateListView();
}

/**
 * 类似于button.setOnClieckListener()
 * 用此方法给调用者设置刷新响应
 */
public void setOnUpdateListener(UpdateView listener) {
    this.listener = listener;
}

源码下载:360云盘   访问密码 8cf8 

参考视频:http://www.imooc.com/learn/135

 

 

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注