您的位置:首页 > 产品设计 > UI/UE

android UI进阶之实现listview的下拉加载

2012-08-13 17:56 597 查看
android UI进阶之实现listview的下拉加载

2012-02-14 10:29:14 我来说两句
收藏 我要投稿
[字体: ]

关于listview的操作五花八门,有下拉刷新,分级显示,分页列表,逐页加载等,以后会陆续和大家分享这些技术,今天讲下下拉加载这个功能的实现。

最初的下拉加载应该是ios上的效果,现在很多应用如新浪微博等都加入了这个操作。即下拉listview刷新列表,这无疑是一个非常友好的操作。今天就和大家分享下这个操作的实现。

先看下运行效果:











代码参考国外朋友Johan Nilsson的实现,http://johannilsson.com/2011/03/13/android-pull-to-refresh-update.html

主要原理为监听触摸和滑动操作,在listview头部加载一个视图。那要做的其实很简单:1.写好加载到listview头部的view 2.重写listview,实现onTouchEvent方法和onScroll方法,监听滑动状态。计算headview全部显示出来即可实行加载动作,加载完成即刷新列表。重新隐藏headview。

首先写下headview的xml代码:

[html] <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:paddingTop="10dip"

android:paddingBottom="15dip"

android:gravity="center"

android:id="@+id/pull_to_refresh_header"

>

<ProgressBar

android:id="@+id/pull_to_refresh_progress"

android:indeterminate="true"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginLeft="30dip"

android:layout_marginRight="20dip"

android:layout_marginTop="10dip"

android:visibility="gone"

android:layout_centerVertical="true"

style="?android:attr/progressBarStyleSmall"

/>

<ImageView

android:id="@+id/pull_to_refresh_image"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginLeft="30dip"

android:layout_marginRight="20dip"

android:visibility="gone"

android:layout_gravity="center"

android:gravity="center"

android:src="@drawable/ic_pulltorefresh_arrow"

/>

<TextView

android:id="@+id/pull_to_refresh_text"

android:textAppearance="?android:attr/textAppearanceMedium"

android:textStyle="bold"

android:paddingTop="5dip"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:layout_gravity="center"

android:gravity="center"

/>

<TextView

android:id="@+id/pull_to_refresh_updated_at"

android:layout_below="@+id/pull_to_refresh_text"

android:visibility="gone"

android:textAppearance="?android:attr/textAppearanceSmall"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:layout_gravity="center"

android:gravity="center"

/>

</RelativeLayout>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:paddingTop="10dip"

android:paddingBottom="15dip"

android:gravity="center"

android:id="@+id/pull_to_refresh_header"

>

<ProgressBar

android:id="@+id/pull_to_refresh_progress"

android:indeterminate="true"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginLeft="30dip"

android:layout_marginRight="20dip"

android:layout_marginTop="10dip"

android:visibility="gone"

android:layout_centerVertical="true"

style="?android:attr/progressBarStyleSmall"

/>

<ImageView

android:id="@+id/pull_to_refresh_image"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginLeft="30dip"

android:layout_marginRight="20dip"

android:visibility="gone"

android:layout_gravity="center"

android:gravity="center"

android:src="@drawable/ic_pulltorefresh_arrow"

/>

<TextView

android:id="@+id/pull_to_refresh_text"

android:textAppearance="?android:attr/textAppearanceMedium"

android:textStyle="bold"

android:paddingTop="5dip"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:layout_gravity="center"

android:gravity="center"

/>

<TextView

android:id="@+id/pull_to_refresh_updated_at"

android:layout_below="@+id/pull_to_refresh_text"

android:visibility="gone"

android:textAppearance="?android:attr/textAppearanceSmall"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:layout_gravity="center"

android:gravity="center"

/>

</RelativeLayout>

代码比较简单,即headview包括一个进度条一个箭头和两段文字(一个显示加载状态,另一个显示最后刷新时间,本例就不设置了)。

而后重写listview,代码如下:

[java] package com.notice.pullrefresh;

import android.content.Context;

import android.util.AttributeSet;

import android.view.LayoutInflater;

import android.view.MotionEvent;

import android.view.View;

import android.view.ViewGroup;

import android.view.animation.LinearInterpolator;

import android.view.animation.RotateAnimation;

import android.widget.AbsListView;

import android.widget.AbsListView.OnScrollListener;

import android.widget.ImageView;

import android.widget.ListAdapter;

import android.widget.ListView;

import android.widget.ProgressBar;

import android.widget.RelativeLayout;

import android.widget.TextView;

public class PullToRefreshListView extends ListView implements OnScrollListener {

// 状态

private static final int TAP_TO_REFRESH = 1;

private static final int PULL_TO_REFRESH = 2;

private static final int RELEASE_TO_REFRESH = 3;

private static final int REFRESHING = 4;

private OnRefreshListener mOnRefreshListener;

// 监听对listview的滑动动作

private OnScrollListener mOnScrollListener;

private LayoutInflater mInflater;

//顶部刷新时出现的控件

private RelativeLayout mRefreshView;

private TextView mRefreshViewText;

private ImageView mRefreshViewImage;

private ProgressBar mRefreshViewProgress;

private TextView mRefreshViewLastUpdated;

// 当前滑动状态

private int mCurrentScrollState;

// 当前刷新状态

private int mRefreshState;

// 箭头动画效果

private RotateAnimation mFlipAnimation;

private RotateAnimation mReverseFlipAnimation;

private int mRefreshViewHeight;

private int mRefreshOriginalTopPadding;

private int mLastMotionY;

private boolean mBounceHack;

public PullToRefreshListView(Context context) {

super(context);

init(context);

}

public PullToRefreshListView(Context context, AttributeSet attrs) {

super(context, attrs);

init(context);

}

public PullToRefreshListView(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

init(context);

}

/**

* 初始化控件和箭头动画(这里直接在代码中初始化动画而不是通过xml)

*/

private void init(Context context) {

mFlipAnimation = new RotateAnimation(0, -180,

RotateAnimation.RELATIVE_TO_SELF, 0.5f,

RotateAnimation.RELATIVE_TO_SELF, 0.5f);

mFlipAnimation.setInterpolator(new LinearInterpolator());

mFlipAnimation.setDuration(250);

mFlipAnimation.setFillAfter(true);

mReverseFlipAnimation = new RotateAnimation(-180, 0,

RotateAnimation.RELATIVE_TO_SELF, 0.5f,

RotateAnimation.RELATIVE_TO_SELF, 0.5f);

mReverseFlipAnimation.setInterpolator(new LinearInterpolator());

mReverseFlipAnimation.setDuration(250);

mReverseFlipAnimation.setFillAfter(true);

mInflater = (LayoutInflater) context.getSystemService(

Context.LAYOUT_INFLATER_SERVICE);

mRefreshView = (RelativeLayout) mInflater.inflate(

R.layout.pull_to_refresh_header, this, false);

mRefreshViewText =

(TextView) mRefreshView.findViewById(R.id.pull_to_refresh_text);

mRefreshViewImage =

(ImageView) mRefreshView.findViewById(R.id.pull_to_refresh_image);

mRefreshViewProgress =

(ProgressBar) mRefreshView.findViewById(R.id.pull_to_refresh_progress);

mRefreshViewLastUpdated =

(TextView) mRefreshView.findViewById(R.id.pull_to_refresh_updated_at);

mRefreshViewImage.setMinimumHeight(50);

mRefreshOriginalTopPadding = mRefreshView.getPaddingTop();

mRefreshState = TAP_TO_REFRESH;

//为listview头部增加一个view

addHeaderView(mRefreshView);

super.setOnScrollListener(this);

measureView(mRefreshView);

mRefreshViewHeight = mRefreshView.getMeasuredHeight();

}

@Override

protected void onAttachedToWindow() {

setSelection(1);

}

@Override

public void setAdapter(ListAdapter adapter) {

super.setAdapter(adapter);

setSelection(1);

}

/**

* 设置滑动监听器

*

*/

@Override

public void setOnScrollListener(AbsListView.OnScrollListener l) {

mOnScrollListener = l;

}

/**

* 注册一个list需要刷新时的回调接口

*

*/

public void setOnRefreshListener(OnRefreshListener onRefreshListener) {

mOnRefreshListener = onRefreshListener;

}

/**

* 设置标签显示何时最后被刷新

*

* @param lastUpdated

* Last updated at.

*/

public void setLastUpdated(CharSequence lastUpdated) {

if (lastUpdated != null) {

mRefreshViewLastUpdated.setVisibility(View.VISIBLE);

mRefreshViewLastUpdated.setText(lastUpdated);

} else {

mRefreshViewLastUpdated.setVisibility(View.GONE);

}

}

// 实现该方法处理触摸

@Override

public boolean onTouchEvent(MotionEvent event) {

final int y = (int) event.getY();

mBounceHack = false;

switch (event.getAction()) {

case MotionEvent.ACTION_UP:

if (!isVerticalScrollBarEnabled()) {

setVerticalScrollBarEnabled(true);

}

if (getFirstVisiblePosition() == 0 && mRefreshState != REFRESHING) {

// 拖动距离达到刷新需要

if ((mRefreshView.getBottom() >= mRefreshViewHeight

|| mRefreshView.getTop() >= 0)

&& mRefreshState == RELEASE_TO_REFRESH) {

// 把状态设置为正在刷新

mRefreshState = REFRESHING;

// 准备刷新

prepareForRefresh();

// 刷新

onRefresh();

} else if (mRefreshView.getBottom() < mRefreshViewHeight

|| mRefreshView.getTop() <= 0) {

// 中止刷新

resetHeader();

setSelection(1);

}

}

break;

case MotionEvent.ACTION_DOWN:

// 获得按下y轴位置

mLastMotionY = y;

break;

case MotionEvent.ACTION_MOVE:

// 计算边距

applyHeaderPadding(event);

break;

}

return super.onTouchEvent(event);

}

// 获得header的边距

private void applyHeaderPadding(MotionEvent ev) {

int pointerCount = ev.getHistorySize();

for (int p = 0; p < pointerCount; p++) {

if (mRefreshState == RELEASE_TO_REFRESH) {

if (isVerticalFadingEdgeEnabled()) {

setVerticalScrollBarEnabled(false);

}

int historicalY = (int) ev.getHistoricalY(p);

// 计算申请的边距,除以1.7使得拉动效果更好

int topPadding = (int) (((historicalY - mLastMotionY)

- mRefreshViewHeight) / 1.7);

mRefreshView.setPadding(

mRefreshView.getPaddingLeft(),

topPadding,

mRefreshView.getPaddingRight(),

mRefreshView.getPaddingBottom());

}

}

}

/**

* 将head的边距重置为初始的数值

*/

private void resetHeaderPadding() {

mRefreshView.setPadding(

mRefreshView.getPaddingLeft(),

mRefreshOriginalTopPadding,

mRefreshView.getPaddingRight(),

mRefreshView.getPaddingBottom());

}

/**

* 重置header为之前的状态

*/

private void resetHeader() {

if (mRefreshState != TAP_TO_REFRESH) {

mRefreshState = TAP_TO_REFRESH;

resetHeaderPadding();

// 将刷新图标换成箭头

mRefreshViewImage.setImageResource(R.drawable.ic_pulltorefresh_arrow);

// 清除动画

mRefreshViewImage.clearAnimation();

// 隐藏图标和进度条

mRefreshViewImage.setVisibility(View.GONE);

mRefreshViewProgress.setVisibility(View.GONE);

}

}

// 估算headview的width和height

private void measureView(View child) {

ViewGroup.LayoutParams p = child.getLayoutParams();

if (p == null) {

p = new ViewGroup.LayoutParams(

ViewGroup.LayoutParams.FILL_PARENT,

ViewGroup.LayoutParams.WRAP_CONTENT);

}

int childWidthSpec = ViewGroup.getChildMeasureSpec(0,

0 + 0, p.width);

int lpHeight = p.height;

int childHeightSpec;

if (lpHeight > 0) {

childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);

} else {

childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);

}

child.measure(childWidthSpec, childHeightSpec);

}

@Override

public void onScroll(AbsListView view, int firstVisibleItem,

int visibleItemCount, int totalItemCount) {

// 在refreshview完全可见时,设置文字为松开刷新,同时翻转箭头

if (mCurrentScrollState == SCROLL_STATE_TOUCH_SCROLL

&& mRefreshState != REFRESHING) {

if (firstVisibleItem == 0) {

mRefreshViewImage.setVisibility(View.VISIBLE);

if ((mRefreshView.getBottom() >= mRefreshViewHeight + 20

|| mRefreshView.getTop() >= 0)

&& mRefreshState != RELEASE_TO_REFRESH) {

mRefreshViewText.setText("松开加载...");

mRefreshViewImage.clearAnimation();

mRefreshViewImage.startAnimation(mFlipAnimation);

mRefreshState = RELEASE_TO_REFRESH;

} else if (mRefreshView.getBottom() < mRefreshViewHeight + 20

&& mRefreshState != PULL_TO_REFRESH) {

mRefreshViewText.setText("下拉刷新...");

if (mRefreshState != TAP_TO_REFRESH) {

mRefreshViewImage.clearAnimation();

mRefreshViewImage.startAnimation(mReverseFlipAnimation);

}

mRefreshState = PULL_TO_REFRESH;

}

} else {

mRefreshViewImage.setVisibility(View.GONE);

resetHeader();

}

} else if (mCurrentScrollState == SCROLL_STATE_FLING

&& firstVisibleItem == 0

&& mRefreshState != REFRESHING) {

setSelection(1);

mBounceHack = true;

} else if (mBounceHack && mCurrentScrollState == SCROLL_STATE_FLING) {

setSelection(1);

}

if (mOnScrollListener != null) {

mOnScrollListener.onScroll(view, firstVisibleItem,

visibleItemCount, totalItemCount);

}

}

@Override

public void onScrollStateChanged(AbsListView view, int scrollState) {

mCurrentScrollState = scrollState;

if (mCurrentScrollState == SCROLL_STATE_IDLE) {

mBounceHack = false;

}

if (mOnScrollListener != null) {

mOnScrollListener.onScrollStateChanged(view, scrollState);

}

}

public void prepareForRefresh() {

resetHeaderPadding();// 恢复header的边距

mRefreshViewImage.setVisibility(View.GONE);

// 注意加上,否则仍然显示之前的图片

mRefreshViewImage.setImageDrawable(null);

mRefreshViewProgress.setVisibility(View.VISIBLE);

// 设置文字

mRefreshViewText.setText("加载中...");

mRefreshState = REFRESHING;

}

public void onRefresh() {

if (mOnRefreshListener != null) {

mOnRefreshListener.onRefresh();

}

}

/**

* 重置listview为普通的listview,该方法设置最后更新时间

*

* @param lastUpdated

* Last updated at.

*/

public void onRefreshComplete(CharSequence lastUpdated) {

setLastUpdated(lastUpdated);

onRefreshComplete();

}

/**

* 重置listview为普通的listview,不设置最后更新时间

*/

public void onRefreshComplete() {

resetHeader();

// 如果refreshview在加载结束后可见,下滑到下一个条目

if (mRefreshView.getBottom() > 0) {

invalidateViews();

setSelection(1);

}

}

/**

* 刷新监听器接口

*/

public interface OnRefreshListener {

/**

* list需要被刷新时调用

*/

public void onRefresh();

}

}

package com.notice.pullrefresh;

import android.content.Context;

import android.util.AttributeSet;

import android.view.LayoutInflater;

import android.view.MotionEvent;

import android.view.View;

import android.view.ViewGroup;

import android.view.animation.LinearInterpolator;

import android.view.animation.RotateAnimation;

import android.widget.AbsListView;

import android.widget.AbsListView.OnScrollListener;

import android.widget.ImageView;

import android.widget.ListAdapter;

import android.widget.ListView;

import android.widget.ProgressBar;

import android.widget.RelativeLayout;

import android.widget.TextView;

public class PullToRefreshListView extends ListView implements OnScrollListener {

// 状态

private static final int TAP_TO_REFRESH = 1;

private static final int PULL_TO_REFRESH = 2;

private static final int RELEASE_TO_REFRESH = 3;

private static final int REFRESHING = 4;

private OnRefreshListener mOnRefreshListener;

// 监听对listview的滑动动作

private OnScrollListener mOnScrollListener;

private LayoutInflater mInflater;

//顶部刷新时出现的控件

private RelativeLayout mRefreshView;

private TextView mRefreshViewText;

private ImageView mRefreshViewImage;

private ProgressBar mRefreshViewProgress;

private TextView mRefreshViewLastUpdated;

// 当前滑动状态

private int mCurrentScrollState;

// 当前刷新状态

private int mRefreshState;

// 箭头动画效果

private RotateAnimation mFlipAnimation;

private RotateAnimation mReverseFlipAnimation;

private int mRefreshViewHeight;

private int mRefreshOriginalTopPadding;

private int mLastMotionY;

private boolean mBounceHack;

public PullToRefreshListView(Context context) {

super(context);

init(context);

}

public PullToRefreshListView(Context context, AttributeSet attrs) {

super(context, attrs);

init(context);

}

public PullToRefreshListView(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

init(context);

}

/**

* 初始化控件和箭头动画(这里直接在代码中初始化动画而不是通过xml)

*/

private void init(Context context) {

mFlipAnimation = new RotateAnimation(0, -180,

RotateAnimation.RELATIVE_TO_SELF, 0.5f,

RotateAnimation.RELATIVE_TO_SELF, 0.5f);

mFlipAnimation.setInterpolator(new LinearInterpolator());

mFlipAnimation.setDuration(250);

mFlipAnimation.setFillAfter(true);

mReverseFlipAnimation = new RotateAnimation(-180, 0,

RotateAnimation.RELATIVE_TO_SELF, 0.5f,

RotateAnimation.RELATIVE_TO_SELF, 0.5f);

mReverseFlipAnimation.setInterpolator(new LinearInterpolator());

mReverseFlipAnimation.setDuration(250);

mReverseFlipAnimation.setFillAfter(true);

mInflater = (LayoutInflater) context.getSystemService(

Context.LAYOUT_INFLATER_SERVICE);

mRefreshView = (RelativeLayout) mInflater.inflate(

R.layout.pull_to_refresh_header, this, false);

mRefreshViewText =

(TextView) mRefreshView.findViewById(R.id.pull_to_refresh_text);

mRefreshViewImage =

(ImageView) mRefreshView.findViewById(R.id.pull_to_refresh_image);

mRefreshViewProgress =

(ProgressBar) mRefreshView.findViewById(R.id.pull_to_refresh_progress);

mRefreshViewLastUpdated =

(TextView) mRefreshView.findViewById(R.id.pull_to_refresh_updated_at);

mRefreshViewImage.setMinimumHeight(50);

mRefreshOriginalTopPadding = mRefreshView.getPaddingTop();

mRefreshState = TAP_TO_REFRESH;

//为listview头部增加一个view

addHeaderView(mRefreshView);

super.setOnScrollListener(this);

measureView(mRefreshView);

mRefreshViewHeight = mRefreshView.getMeasuredHeight();

}

@Override

protected void onAttachedToWindow() {

setSelection(1);

}

@Override

public void setAdapter(ListAdapter adapter) {

super.setAdapter(adapter);

setSelection(1);

}

/**

* 设置滑动监听器

*

*/

@Override

public void setOnScrollListener(AbsListView.OnScrollListener l) {

mOnScrollListener = l;

}

/**

* 注册一个list需要刷新时的回调接口

*

*/

public void setOnRefreshListener(OnRefreshListener onRefreshListener) {

mOnRefreshListener = onRefreshListener;

}

/**

* 设置标签显示何时最后被刷新

*

* @param lastUpdated

* Last updated at.

*/

public void setLastUpdated(CharSequence lastUpdated) {

if (lastUpdated != null) {

mRefreshViewLastUpdated.setVisibility(View.VISIBLE);

mRefreshViewLastUpdated.setText(lastUpdated);

} else {

mRefreshViewLastUpdated.setVisibility(View.GONE);

}

}

// 实现该方法处理触摸

@Override

public boolean onTouchEvent(MotionEvent event) {

final int y = (int) event.getY();

mBounceHack = false;

switch (event.getAction()) {

case MotionEvent.ACTION_UP:

if (!isVerticalScrollBarEnabled()) {

setVerticalScrollBarEnabled(true);

}

if (getFirstVisiblePosition() == 0 && mRefreshState != REFRESHING) {

// 拖动距离达到刷新需要

if ((mRefreshView.getBottom() >= mRefreshViewHeight

|| mRefreshView.getTop() >= 0)

&& mRefreshState == RELEASE_TO_REFRESH) {

// 把状态设置为正在刷新

mRefreshState = REFRESHING;

// 准备刷新

prepareForRefresh();

// 刷新

onRefresh();

} else if (mRefreshView.getBottom() < mRefreshViewHeight

|| mRefreshView.getTop() <= 0) {

// 中止刷新

resetHeader();

setSelection(1);

}

}

break;

case MotionEvent.ACTION_DOWN:

// 获得按下y轴位置

mLastMotionY = y;

break;

case MotionEvent.ACTION_MOVE:

// 计算边距

applyHeaderPadding(event);

break;

}

return super.onTouchEvent(event);

}

// 获得header的边距

private void applyHeaderPadding(MotionEvent ev) {

int pointerCount = ev.getHistorySize();

for (int p = 0; p < pointerCount; p++) {

if (mRefreshState == RELEASE_TO_REFRESH) {

if (isVerticalFadingEdgeEnabled()) {

setVerticalScrollBarEnabled(false);

}

int historicalY = (int) ev.getHistoricalY(p);

// 计算申请的边距,除以1.7使得拉动效果更好

int topPadding = (int) (((historicalY - mLastMotionY)

- mRefreshViewHeight) / 1.7);

mRefreshView.setPadding(

mRefreshView.getPaddingLeft(),

topPadding,

mRefreshView.getPaddingRight(),

mRefreshView.getPaddingBottom());

}

}

}

/**

* 将head的边距重置为初始的数值

*/

private void resetHeaderPadding() {

mRefreshView.setPadding(

mRefreshView.getPaddingLeft(),

mRefreshOriginalTopPadding,

mRefreshView.getPaddingRight(),

mRefreshView.getPaddingBottom());

}

/**

* 重置header为之前的状态

*/

private void resetHeader() {

if (mRefreshState != TAP_TO_REFRESH) {

mRefreshState = TAP_TO_REFRESH;

resetHeaderPadding();

// 将刷新图标换成箭头

mRefreshViewImage.setImageResource(R.drawable.ic_pulltorefresh_arrow);

// 清除动画

mRefreshViewImage.clearAnimation();

// 隐藏图标和进度条

mRefreshViewImage.setVisibility(View.GONE);

mRefreshViewProgress.setVisibility(View.GONE);

}

}

// 估算headview的width和height

private void measureView(View child) {

ViewGroup.LayoutParams p = child.getLayoutParams();

if (p == null) {

p = new ViewGroup.LayoutParams(

ViewGroup.LayoutParams.FILL_PARENT,

ViewGroup.LayoutParams.WRAP_CONTENT);

}

int childWidthSpec = ViewGroup.getChildMeasureSpec(0,

0 + 0, p.width);

int lpHeight = p.height;

int childHeightSpec;

if (lpHeight > 0) {

childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);

} else {

childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);

}

child.measure(childWidthSpec, childHeightSpec);

}

@Override

public void onScroll(AbsListView view, int firstVisibleItem,

int visibleItemCount, int totalItemCount) {

// 在refreshview完全可见时,设置文字为松开刷新,同时翻转箭头

if (mCurrentScrollState == SCROLL_STATE_TOUCH_SCROLL

&& mRefreshState != REFRESHING) {

if (firstVisibleItem == 0) {

mRefreshViewImage.setVisibility(View.VISIBLE);

if ((mRefreshView.getBottom() >= mRefreshViewHeight + 20

|| mRefreshView.getTop() >= 0)

&& mRefreshState != RELEASE_TO_REFRESH) {

mRefreshViewText.setText("松开加载...");

mRefreshViewImage.clearAnimation();

mRefreshViewImage.startAnimation(mFlipAnimation);

mRefreshState = RELEASE_TO_REFRESH;

} else if (mRefreshView.getBottom() < mRefreshViewHeight + 20

&& mRefreshState != PULL_TO_REFRESH) {

mRefreshViewText.setText("下拉刷新...");

if (mRefreshState != TAP_TO_REFRESH) {

mRefreshViewImage.clearAnimation();

mRefreshViewImage.startAnimation(mReverseFlipAnimation);

}

mRefreshState = PULL_TO_REFRESH;

}

} else {

mRefreshViewImage.setVisibility(View.GONE);

resetHeader();

}

} else if (mCurrentScrollState == SCROLL_STATE_FLING

&& firstVisibleItem == 0

&& mRefreshState != REFRESHING) {

setSelection(1);

mBounceHack = true;

} else if (mBounceHack && mCurrentScrollState == SCROLL_STATE_FLING) {

setSelection(1);

}

if (mOnScrollListener != null) {

mOnScrollListener.onScroll(view, firstVisibleItem,

visibleItemCount, totalItemCount);

}

}

@Override

public void onScrollStateChanged(AbsListView view, int scrollState) {

mCurrentScrollState = scrollState;

if (mCurrentScrollState == SCROLL_STATE_IDLE) {

mBounceHack = false;

}

if (mOnScrollListener != null) {

mOnScrollListener.onScrollStateChanged(view, scrollState);

}

}

public void prepareForRefresh() {

resetHeaderPadding();// 恢复header的边距

mRefreshViewImage.setVisibility(View.GONE);

// 注意加上,否则仍然显示之前的图片

mRefreshViewImage.setImageDrawable(null);

mRefreshViewProgress.setVisibility(View.VISIBLE);

// 设置文字

mRefreshViewText.setText("加载中...");

mRefreshState = REFRESHING;

}

public void onRefresh() {

if (mOnRefreshListener != null) {

mOnRefreshListener.onRefresh();

}

}

/**

* 重置listview为普通的listview,该方法设置最后更新时间

*

* @param lastUpdated

* Last updated at.

*/

public void onRefreshComplete(CharSequence lastUpdated) {

setLastUpdated(lastUpdated);

onRefreshComplete();

}

/**

* 重置listview为普通的listview,不设置最后更新时间

*/

public void onRefreshComplete() {

resetHeader();

// 如果refreshview在加载结束后可见,下滑到下一个条目

if (mRefreshView.getBottom() > 0) {

invalidateViews();

setSelection(1);

}

}

/**

* 刷新监听器接口

*/

public interface OnRefreshListener {

/**

* list需要被刷新时调用

*/

public void onRefresh();

}

}

相信我注释已经写的比较详细了,主要注意onTouchEvent和onScroll方法,在这里面计算头部边距,从而通过用户的手势实现“下拉刷新”到“松开加载”以及“加载”三个状态的切换。其中还有一系列和header有关的方法,用来设置header的显示以及取得header的边距。于此同时,代码留出了接口以供调用。

那么现在写一个测试Activity来试验下效果:

[java] package com.notice.pullrefresh;

import java.util.Arrays;

import java.util.LinkedList;

import android.app.ListActivity;

import android.os.AsyncTask;

import android.os.Bundle;

import android.widget.ArrayAdapter;

import com.notice.pullrefresh.PullToRefreshListView.OnRefreshListener;

public class PullrefreshActivity extends ListActivity {

private LinkedList<String> mListItems;

ArrayAdapter<String> adapter;

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.pull_to_refresh);

// list需要刷新时调用

((PullToRefreshListView) getListView())

.setOnRefreshListener(new OnRefreshListener() {

@Override

public void onRefresh() {

// 在这执行后台工作

new GetDataTask().execute();

}

});

mListItems = new LinkedList<String>();

mListItems.addAll(Arrays.asList(mStrings));

adapter = new ArrayAdapter<String>(this,

android.R.layout.simple_list_item_1, mListItems);

setListAdapter(adapter);

}

private class GetDataTask extends AsyncTask<Void, Void, String[]> {

@Override

protected String[] doInBackground(Void... params) {

// 在这里可以做一些后台工作

try {

Thread.sleep(2000);

} catch (InterruptedException e) {

e.printStackTrace();

}

return mStrings;

}

@Override

protected void onPostExecute(String[] result) {

// 下拉后增加的内容

mListItems.addFirst("Added after refresh...");

// 刷新完成调用该方法复位

((PullToRefreshListView) getListView()).onRefreshComplete();

super.onPostExecute(result);

}

}

private String[] mStrings = { "normal data1", "normal data2",

"nomal data3", "normal data4", "norma data5", "normal data6" };

}

package com.notice.pullrefresh;

import java.util.Arrays;

import java.util.LinkedList;

import android.app.ListActivity;

import android.os.AsyncTask;

import android.os.Bundle;

import android.widget.ArrayAdapter;

import com.notice.pullrefresh.PullToRefreshListView.OnRefreshListener;

public class PullrefreshActivity extends ListActivity {

private LinkedList<String> mListItems;

ArrayAdapter<String> adapter;

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.pull_to_refresh);

// list需要刷新时调用

((PullToRefreshListView) getListView())

.setOnRefreshListener(new OnRefreshListener() {

@Override

public void onRefresh() {

// 在这执行后台工作

new GetDataTask().execute();

}

});

mListItems = new LinkedList<String>();

mListItems.addAll(Arrays.asList(mStrings));

adapter = new ArrayAdapter<String>(this,

android.R.layout.simple_list_item_1, mListItems);

setListAdapter(adapter);

}

private class GetDataTask extends AsyncTask<Void, Void, String[]> {

@Override

protected String[] doInBackground(Void... params) {

// 在这里可以做一些后台工作

try {

Thread.sleep(2000);

} catch (InterruptedException e) {

e.printStackTrace();

}

return mStrings;

}

@Override

protected void onPostExecute(String[] result) {

// 下拉后增加的内容

mListItems.addFirst("Added after refresh...");

// 刷新完成调用该方法复位

((PullToRefreshListView) getListView()).onRefreshComplete();

super.onPostExecute(result);

}

}

private String[] mStrings = { "normal data1", "normal data2",

"nomal data3", "normal data4", "norma data5", "normal data6" };

}

代码通过asyncTask实现一个异步操作,并通过设置onRefreshListener监听器调用onRefresh方法实现下拉时刷新,并在刷新完成后调用onRefreshComplete做复位处理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: