package com.yuyh.library.view.list;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.widget.ImageView;
import android.widget.TextView;
import com.yuyh.library.R;
import com.yuyh.library.view.listener.OnCancelListener;
import com.yuyh.library.view.listener.OnRefreshListener;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 下拉刷新的Listview
*
* @author yuyh.
* @date 16/4/10.
*/
public class RefreshListView extends TBListView {
private final static int RELEASE_TO_REFRESH = 0;
private final static int PULL_TO_REFRESH = 1;
private final static int REFRESHING = 2;
private final static int DONE = 3;
private final static int LOADING = 4;
private final static int RATIO = 3;
private View mHeader;
private TextView mHtvTitle;
private TextView mHtvTime;
private ImageView mIvArrow;
private ImageView mIvLoading;
private ImageView mIvCancel;
private android.view.animation.RotateAnimation mPullAnimation;
private android.view.animation.RotateAnimation mReverseAnimation;
private boolean mIsRecored;
private int mHeaderHeight;
private int mStartY;
private int mState;
private boolean mIsBack;
private OnRefreshListener mOnRefreshListener;
private OnCancelListener mOnCancelListener;
private boolean mIsRefreshable;
private boolean mIsCancelable;
public RefreshListView(Context context) {
super(context);
init();
}
public RefreshListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public RefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
mHeader = mInflater.inflate(R.layout.pull_to_refreshing_header, null);
mHtvTitle = (TextView) mHeader.findViewById(R.id.refreshing_header_htv_title);
mHtvTime = (TextView) mHeader.findViewById(R.id.refreshing_header_htv_time);
mIvArrow = (ImageView) mHeader.findViewById(R.id.refreshing_header_iv_arrow);
mIvLoading = (ImageView) mHeader.findViewById(R.id.refreshing_header_iv_loading);
mIvCancel = (ImageView) mHeader.findViewById(R.id.refreshing_header_iv_cancel);
mIvCancel.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
if (mOnCancelListener != null && mIsCancelable) {
mOnCancelListener.onCancel();
}
}
});
measureView(mHeader);
addHeaderView(mHeader);
mHeaderHeight = mHeader.getMeasuredHeight();
mHeader.setPadding(0, -1 * mHeaderHeight, 0, 0);
mHeader.invalidate();
mHtvTitle.setText(R.string.pull_to_refresh_pull_label);
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
String date = format.format(new Date());
mHtvTime.setText(getContext().getText(R.string.pull_to_refresh_date) + date);
mPullAnimation = new android.view.animation.RotateAnimation(0, -180,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
mPullAnimation.setInterpolator(new LinearInterpolator());
mPullAnimation.setDuration(250);
mPullAnimation.setFillAfter(true);
mReverseAnimation = new android.view.animation.RotateAnimation(-180, 0,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
mReverseAnimation.setInterpolator(new LinearInterpolator());
mReverseAnimation.setDuration(200);
mReverseAnimation.setFillAfter(true);
mState = DONE;
mIsRefreshable = false;
}
@Override
public void onDown(MotionEvent ev) {
if (mIsRefreshable) {
if (mFirstVisibleItem == 0 && !mIsRecored) {
mIsRecored = true;
mStartY = mDownPoint.y;
}
}
}
@Override
public void onMove(MotionEvent ev) {
if (mIsRefreshable) {
if (!mIsRecored && mFirstVisibleItem == 0) {
mIsRecored = true;
mStartY = mMovePoint.y;
}
if (mState != REFRESHING && mIsRecored && mState != LOADING) {
if (mState == RELEASE_TO_REFRESH) {
setSelection(0);
if (((mMovePoint.y - mStartY) / RATIO < mHeaderHeight)
&& (mMovePoint.y - mStartY) > 0) {
mState = PULL_TO_REFRESH;
changeHeaderViewByState();
} else if (mMovePoint.y - mStartY <= 0) {
mState = DONE;
changeHeaderViewByState();
}
}
if (mState == PULL_TO_REFRESH) {
setSelection(0);
if ((mMovePoint.y - mStartY) / RATIO >= mHeaderHeight) {
mState = RELEASE_TO_REFRESH;
mIsBack = true;
changeHeaderViewByState();
} else if (mMovePoint.y - mStartY <= 0) {
mState = DONE;
changeHeaderViewByState();
}
}
if (mState == DONE) {
if (mMovePoint.y - mStartY > 0) {
mState = PULL_TO_REFRESH;
changeHeaderViewByState();
}
}
if (mState == PULL_TO_REFRESH) {
mHeader.setPadding(0, -1 * mHeaderHeight
+ (mMovePoint.y - mStartY) / RATIO, 0, 0);
}
if (mState == RELEASE_TO_REFRESH) {
mHeader.setPadding(0, (mMovePoint.y - mStartY) / RATIO - mHeaderHeight, 0, 0);
}
}
}
}
@Override
public void onUp(MotionEvent ev) {
if (mState != REFRESHING && mState != LOADING) {
if (mState == PULL_TO_REFRESH) {
mState = DONE;
changeHeaderViewByState();
}
if (mState == RELEASE_TO_REFRESH) {
mState = REFRESHING;
changeHeaderViewByState();
onRefresh();
}
}
mIsRecored = false;
mIsBack = false;
}
private void measureView(View child) {
ViewGroup.LayoutParams p = child.getLayoutParams();
if (p == null) {
p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_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);
}
private void changeHeaderViewByState() {
switch (mState) {
case RELEASE_TO_REFRESH:
mIvArrow.setVisibility(View.VISIBLE);
mIvLoading.setVisibility(View.GONE);
mHtvTitle.setVisibility(View.VISIBLE);
mHtvTime.setVisibility(View.VISIBLE);
mIvCancel.setVisibility(View.GONE);
mIvArrow.clearAnimation();
mIvArrow.startAnimation(mPullAnimation);
mIvLoading.clearAnimation();
mHtvTitle.setText(R.string.pull_to_refresh_release_label);
break;
case PULL_TO_REFRESH:
mIvArrow.setVisibility(View.VISIBLE);
mIvLoading.setVisibility(View.GONE);
mHtvTitle.setVisibility(View.VISIBLE);
mHtvTime.setVisibility(View.VISIBLE);
mIvCancel.setVisibility(View.GONE);
mIvLoading.clearAnimation();
mIvArrow.clearAnimation();
if (mIsBack) {
mIsBack = false;
mIvArrow.clearAnimation();
mIvArrow.startAnimation(mReverseAnimation);
mHtvTitle.setText(R.string.pull_to_refresh_pull_label);
} else {
mHtvTitle.setText(R.string.pull_to_refresh_pull_label);
}
break;
case REFRESHING:
mHeader.setPadding(0, 0, 0, 0);
mIvLoading.setVisibility(View.VISIBLE);
mIvArrow.setVisibility(View.GONE);
mIvArrow.clearAnimation();
mHtvTitle.setText(R.string.pull_to_refresh_footer_refreshing_label);
mHtvTime.setVisibility(View.VISIBLE);
if (mIsCancelable) {
mIvCancel.setVisibility(View.VISIBLE);
} else {
mIvCancel.setVisibility(View.GONE);
}
break;
case DONE:
mHeader.setPadding(0, -1 * mHeaderHeight, 0, 0);
mIvLoading.setVisibility(View.GONE);
mIvArrow.clearAnimation();
mIvLoading.clearAnimation();
mIvArrow.setImageResource(R.drawable.pulltorefresh_ic_arrow);
mHtvTitle.setText(R.string.pull_to_refresh_pull_label);
mHtvTime.setVisibility(View.VISIBLE);
mIvCancel.setVisibility(View.GONE);
break;
}
}
public void onRefreshComplete() {
mState = DONE;
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
String date = format.format(new Date());
mHtvTime.setText(getContext().getText(R.string.pull_to_refresh_date) + date);
changeHeaderViewByState();
}
private void onRefresh() {
if (mOnRefreshListener != null) {
mOnRefreshListener.onRefresh();
}
}
public void onManualRefresh() {
if (mIsRefreshable) {
mState = REFRESHING;
changeHeaderViewByState();
onRefresh();
}
}
public void setOnRefreshListener(OnRefreshListener l) {
mOnRefreshListener = l;
mIsRefreshable = true;
}
public void setOnCancelListener(OnCancelListener l) {
mOnCancelListener = l;
mIsCancelable = true;
}
}