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做复位处理。

更多相关文章

  1. Android(安卓)Studio使用USB真机调试
  2. 如何打开USB调试模式(Android(安卓)所有版本对应的打开方法)
  3. Android(安卓)设备管理员-android 一键锁屏
  4. Andoird用户界面设计上手指南:设置字体大小
  5. Android(安卓)TextView文字太多显示的最后一行被盖住一半的解决
  6. android windowSoftInputMode 使用说明
  7. Android横屏状态下返回到壁纸界面屏幕刷新问题
  8. Android(安卓)APP设计加载使用gif动图需要注意的一般性问题
  9. ArcGIS for Android(安卓)离线数据图例加载

随机推荐

  1. php中函数的定义
  2. php怎么改端口
  3. php变量命名规则
  4. php文件上传步骤是什么
  5. php怎么改成html
  6. php连接数据库的步骤
  7. 使用PHP简单实现类似“畅言”等评论系统
  8. php怎么放大字体
  9. PHP高效生成一个不重复随机数
  10. php无限极分类原理