package com.cml.pullflushlistview;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
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.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
/**
*
* @author Administrator
*
*/
public class PullRefleshListView extends ListView implements OnScrollListener {
private static final String TAG = PullRefleshListView.class.getSimpleName();
private static final String UPDATE_TIME_KEY = "update_time_key";
private static final String UPDATE_TIME_PRE = "last_update_time_pre";
private static final String FOOT_UPDATE_TIME_KEY = "foot_update_time_key";
private static final String FOOT_UPDATE_TIME_PRE = "foot_last_update_time_pre";
private enum PullState {
// 上拉操作
PULL_UP,
// 下拉操作
PULL_DOWN;
}
private enum FlushState {
FLUSHING // 正在刷新
, PULLDOWN, PULLUP, CANCEL, DEFAULT
}
public static interface OnFlushListener {
/**
* 上拉刷新
*/
public void onPullUp();
/**
* 下拉刷新
*/
public void onPullDown();
/**
* 取消刷新事件
*/
public void onCancel();
}
private OnFlushListener onFlushListener;
private FlushState flushState = FlushState.DEFAULT;
// 显示日期格式 默认为yyyy-MM-dd HH:mm:ss
private String updateTimeFormat = "yyyy-MM-dd HH:mm:ss";
private SimpleDateFormat format;
private Animation animation;
private Animation reverseAnimation;// 旋转动画,旋转动画之后旋转动画.
private Animation progressAnim;// progressbar滚动动画
// ====================下拉组件===================
// 第一次点击的y坐标
private float touchY = 0;
private View headView;
private int headViewHeight;
// 提示文本
private TextView tipTextView;
// 更新时间提示文本
private TextView updateTimeTextView;
// 箭头图标
private ImageView arrowImg;
private ProgressBar headProgressBar;
// =============================================
// ====================上拉组件===================
// 上拉底部显示
private View footView;
private int footViewHeight;
private TextView footTextView;// 提示文本
private TextView footUpdateTimeTextView;// 底部时间
// 箭头图标
private ImageView footArrowImg;
private ProgressBar footProgressBar;
// =============================================
private float lastMovePositionY;
private int firstPosition;
private int totalCount;// listview控件长度
private int lastVisiblePosition;// 最后可见控件
private boolean isARecord;
public PullRefleshListView(Context context) {
super(context);
setOnScrollListener(this);
initHeadView(context);
initFootView(context);
}
public PullRefleshListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setOnScrollListener(this);
initHeadView(context);
initFootView(context);
}
public PullRefleshListView(Context context, AttributeSet attrs) {
super(context, attrs);
setOnScrollListener(this);
initHeadView(context);
initFootView(context);
}
private void initFootView(Context context) {
footView = LayoutInflater.from(context).inflate(R.layout.foot, null);
footArrowImg = (ImageView) footView.findViewById(R.id.foot_arrowImageView);
footTextView = (TextView) footView.findViewById(R.id.foot_tipsTextView);
footUpdateTimeTextView = (TextView) footView.findViewById(R.id.foot_lastUpdatedTextView);
footProgressBar = (ProgressBar) footView.findViewById(R.id.foot_progressBar);
addFooterView(footView, null, false);
measureView(footView);
footViewHeight = footView.getMeasuredHeight();
// 在这里我们要将此headView设置到顶部不显示位置.
footView.setPadding(0, 0, 0, -1 * footViewHeight);
}
private void initHeadView(Context context) {
headView = LayoutInflater.from(context).inflate(R.layout.head, null);
arrowImg = (ImageView) headView.findViewById(R.id.head_arrowImageView);
tipTextView = (TextView) headView.findViewById(R.id.head_tipsTextView);
updateTimeTextView = (TextView) headView.findViewById(R.id.head_lastUpdatedTextView);
headProgressBar = (ProgressBar) headView.findViewById(R.id.head_progressBar);
addHeaderView(headView, null, false);
measureView(headView);
headViewHeight = headView.getMeasuredHeight();
Log.i(TAG, "初始化高度:" + headViewHeight);
// 在这里我们要将此headView设置到顶部不显示位置.
headView.setPadding(0, -1 * headView.getMeasuredHeight(), 0, 0);
initAnimation();
}
/***
* 初始化动画
*/
private void initAnimation() {
// 旋转动画
animation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
animation.setInterpolator(new LinearInterpolator());// 匀速
animation.setDuration(250);
animation.setFillAfter(true);// 停留在最后状态.
// 反向旋转动画
reverseAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
reverseAnimation.setInterpolator(new LinearInterpolator());
reverseAnimation.setDuration(250);
reverseAnimation.setFillAfter(true);
progressAnim = new RotateAnimation(0, 360, RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
progressAnim.setRepeatCount(-1);
progressAnim.setRepeatMode(Animation.RESTART);
progressAnim.setInterpolator(new LinearInterpolator());
progressAnim.setDuration(500);
}
/***
* 作用:测量 headView的宽和高.
*
* @param child
*/
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 onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
/**
* 隐藏下拉
*/
private void dismissTopTips() {
headView.setPadding(0, -1 * headViewHeight, 0, 0);
}
/**
* 隐藏底部上拉更新提示信息
*/
private void dissmissFootTips() {
footView.setPadding(0, 0, 0, -1 * footViewHeight);
}
/**
* 显示顶部提示信息
*
* @param parent
*/
private void showTopTips(View parent) {
if (headView.getPaddingTop() != 0)
headView.setPadding(0, 0, 0, 0);
}
private void showFootTips(View parent) {
if (footView.getPaddingBottom() != 0) {
footView.setPadding(0, 0, 0, 0);
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
// 按下
case MotionEvent.ACTION_DOWN:
touchY = ev.getY();
firstPosition = getFirstVisiblePosition();
lastVisiblePosition = getLastVisiblePosition();
totalCount = getCount();
break;
// 移动
case MotionEvent.ACTION_MOVE:
// 正在刷新,跳过操作
if (flushState == FlushState.FLUSHING) {
break;
}
// 下拉操作判断
if (firstPosition == 0) {
updateTimeTextView.setText(getLastUpdateTime(false));
doPullDown(ev);
} else if (totalCount - lastVisiblePosition < 2) {
footUpdateTimeTextView.setText(getLastUpdateTime(true));
doPullUp(ev);
}
lastMovePositionY = ev.getY();
break;
// 抬起
case MotionEvent.ACTION_UP:
touchY = 0;
isARecord = false;
doActionUp();
break;
}
/***
* 如果是ListView本身的拉动,那么返回true,这样ListView不可以拖动.
* 如果不是ListView的拉动,那么调用父类方法,这样就可以上拉执行.
*/
// if (isScroller) {
// return super.onTouchEvent(ev);
// } else {
// return true;
// }
return super.onTouchEvent(ev);
}
/**
* 手指弹出后回调事件
*/
private void doActionUp() {
if (null == onFlushListener) {
return;
}
switch (flushState) {
case PULLDOWN:// 下拉刷新
// 回复默认提示信息
setTipText("正在刷新");
headView.setPadding(0, 0, 0, 0);
flushState = FlushState.FLUSHING;
// 更新刷新时间
modifyLastUpdateTime(false);
toggleProgressBar(arrowImg, headProgressBar, false);
// 回调刷新事件
onFlushListener.onPullDown();
break;
case PULLUP:
flushState = FlushState.FLUSHING;
// 更新刷新时间
modifyLastUpdateTime(true);
toggleProgressBar(footArrowImg, footProgressBar, false);
// 回调刷新事件
onFlushListener.onPullUp();
break;
case CANCEL:
flushState = FlushState.FLUSHING;
// 隐藏下拉刷新
dismissTopTips();
// 隐藏上拉刷新提示
dissmissFootTips();
onFlushListener.onCancel();
flushState = FlushState.DEFAULT;
break;
default:
break;
}
}
// 下拉加载更多,默认为下拉操作
private PullState lastTopPullState = PullState.PULL_DOWN;
public void onPullUpSuccess() {
toggleProgressBar(footArrowImg, footProgressBar, true);
flushState = FlushState.DEFAULT;
// 隐藏上拉刷新提示
dissmissFootTips();
}
public void onPullDownSuccess() {
toggleProgressBar(arrowImg, headProgressBar, true);
flushState = FlushState.DEFAULT;
// 隐藏下拉刷新
dismissTopTips();
}
/**
* 将textView与progressbar转换显示
*
* @param text
* @param progress
* @param showText
* 是否显示文本信息
*/
private void toggleProgressBar(ImageView img, ProgressBar progress, boolean showImg) {
img.clearAnimation();
if (showImg) {
progress.setVisibility(GONE);
img.setVisibility(VISIBLE);
} else {
progress.setVisibility(VISIBLE);
img.setVisibility(GONE);
progress.startAnimation(progressAnim);
}
}
/**
* 执行上拉操作
*
*/
private void doPullUp(MotionEvent ev) {
// 按下 往下滑动 忽略
float distance = ev.getY() - touchY;
if (distance > 0) {
return;
}
if (!isARecord) {
isARecord = true;
showFootTips(this);
}
PullState state = null;
// 往上拉
if (ev.getY() < lastMovePositionY) {
setFootText("松开刷新");
state = PullState.PULL_UP;
flushState = FlushState.PULLUP;
footView.setPadding(0, 0, 0, (int) (ev.getY() - lastMovePositionY + footViewHeight));
} else {
setFootText("取消刷新");
state = PullState.PULL_DOWN;
flushState = FlushState.CANCEL;
}
toggleFootAnimation(state);
}
/**
* 执行下拉操作
*
*/
private void doPullDown(MotionEvent ev) {
// 按下 往上滑动 忽略
float distance = ev.getY() - touchY;
if (distance < 0) {
return;
}
if (!isARecord) {
isARecord = true;
showTopTips(this);
}
PullState state = null;
// 往上拉
if (ev.getY() < lastMovePositionY) {
setTipText("取消刷新");
state = PullState.PULL_UP;
flushState = FlushState.CANCEL;
} else {
headView.setPadding(0, (int) (ev.getY() - lastMovePositionY + headViewHeight), 0, 0);
setTipText("松开刷新");
state = PullState.PULL_DOWN;
flushState = FlushState.PULLDOWN;
}
toggleAnimation(state);
}
private void toggleFootAnimation(PullState state) {
if (lastTopPullState == state) {
return;
}
// 上下两次操作不同,旋转动画
if (PullState.PULL_UP == state) {
footArrowImg.startAnimation(animation);
} else {
footArrowImg.startAnimation(reverseAnimation);
}
lastTopPullState = state;
}
private void toggleAnimation(PullState state) {
if (lastTopPullState == state) {
return;
}
// 上下两次操作不同,旋转动画
if (PullState.PULL_UP == state) {
arrowImg.startAnimation(animation);
} else {
arrowImg.startAnimation(reverseAnimation);
}
lastTopPullState = state;
}
/**
* 设置提示文本提示信息
*
* @param tip
*/
private void setTipText(String tip) {
tipTextView.setText(tip);
}
private void setFootText(String text) {
footTextView.setText(text);
}
private String getLastUpdateTime(boolean isFoot) {
SharedPreferences pre = null;
if (!isFoot) {
pre = getContext().getSharedPreferences(UPDATE_TIME_PRE, Context.MODE_PRIVATE);
return pre.getString(UPDATE_TIME_KEY, "");
}
pre = getContext().getSharedPreferences(FOOT_UPDATE_TIME_PRE, Context.MODE_PRIVATE);
return pre.getString(FOOT_UPDATE_TIME_KEY, "");
}
/**
* 修改最后一次更新时间
*/
private void modifyLastUpdateTime(boolean isFoot) {
if (null == format) {
format = new SimpleDateFormat(updateTimeFormat);
}
SharedPreferences pre = null;
if (!isFoot) {
pre = getContext().getSharedPreferences(UPDATE_TIME_PRE, Context.MODE_PRIVATE);
Editor editor = pre.edit();
editor.putString(UPDATE_TIME_KEY, format.format(new Date(System.currentTimeMillis())));
editor.commit();
return;
}
pre = getContext().getSharedPreferences(FOOT_UPDATE_TIME_PRE, Context.MODE_PRIVATE);
Editor editor = pre.edit();
editor.putString(FOOT_UPDATE_TIME_KEY, format.format(new Date(System.currentTimeMillis())));
editor.commit();
}
public void setOnFlushListener(OnFlushListener onFlushListener) {
this.onFlushListener = onFlushListener;
}
}