269 lines
8.5 KiB
Java
269 lines
8.5 KiB
Java
|
|
package com.rmondjone.xrecyclerview;
|
|||
|
|
|
|||
|
|
import android.animation.ValueAnimator;
|
|||
|
|
import android.content.Context;
|
|||
|
|
import android.os.Handler;
|
|||
|
|
import android.util.AttributeSet;
|
|||
|
|
import android.view.Gravity;
|
|||
|
|
import android.view.LayoutInflater;
|
|||
|
|
import android.view.View;
|
|||
|
|
import android.view.ViewGroup;
|
|||
|
|
import android.view.animation.Animation;
|
|||
|
|
import android.view.animation.RotateAnimation;
|
|||
|
|
import android.widget.ImageView;
|
|||
|
|
import android.widget.LinearLayout;
|
|||
|
|
import android.widget.ProgressBar;
|
|||
|
|
import android.widget.TextView;
|
|||
|
|
|
|||
|
|
import com.rmondjone.xrecyclerview.progressindicator.AVLoadingIndicatorView;
|
|||
|
|
import com.rmondjone.locktableview.R;
|
|||
|
|
|
|||
|
|
import java.util.Date;
|
|||
|
|
|
|||
|
|
public class ArrowRefreshHeader extends LinearLayout implements BaseRefreshHeader {
|
|||
|
|
|
|||
|
|
private LinearLayout mContainer;
|
|||
|
|
private ImageView mArrowImageView;
|
|||
|
|
private SimpleViewSwitcher mProgressBar;
|
|||
|
|
private TextView mStatusTextView;
|
|||
|
|
private int mState = STATE_NORMAL;
|
|||
|
|
|
|||
|
|
private TextView mHeaderTimeView;
|
|||
|
|
|
|||
|
|
private Animation mRotateUpAnim;
|
|||
|
|
private Animation mRotateDownAnim;
|
|||
|
|
|
|||
|
|
private static final int ROTATE_ANIM_DURATION = 180;
|
|||
|
|
|
|||
|
|
public int mMeasuredHeight;
|
|||
|
|
|
|||
|
|
public ArrowRefreshHeader(Context context) {
|
|||
|
|
super(context);
|
|||
|
|
initView();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @param context
|
|||
|
|
* @param attrs
|
|||
|
|
*/
|
|||
|
|
public ArrowRefreshHeader(Context context, AttributeSet attrs) {
|
|||
|
|
super(context, attrs);
|
|||
|
|
initView();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void initView() {
|
|||
|
|
// 初始情况,设置下拉刷新view高度为0
|
|||
|
|
mContainer = (LinearLayout) LayoutInflater.from(getContext()).inflate(
|
|||
|
|
R.layout.listview_header, null);
|
|||
|
|
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
|
|||
|
|
lp.setMargins(0, 0, 0, 0);
|
|||
|
|
this.setLayoutParams(lp);
|
|||
|
|
this.setPadding(0, 0, 0, 0);
|
|||
|
|
|
|||
|
|
addView(mContainer, new LayoutParams(LayoutParams.MATCH_PARENT, 0));
|
|||
|
|
setGravity(Gravity.BOTTOM);
|
|||
|
|
|
|||
|
|
mArrowImageView = (ImageView)findViewById(R.id.listview_header_arrow);
|
|||
|
|
mStatusTextView = (TextView)findViewById(R.id.refresh_status_textview);
|
|||
|
|
|
|||
|
|
//init the progress view
|
|||
|
|
mProgressBar = (SimpleViewSwitcher)findViewById(R.id.listview_header_progressbar);
|
|||
|
|
AVLoadingIndicatorView progressView = new AVLoadingIndicatorView(getContext());
|
|||
|
|
progressView.setIndicatorColor(0xffB5B5B5);
|
|||
|
|
progressView.setIndicatorId(ProgressStyle.BallSpinFadeLoader);
|
|||
|
|
mProgressBar.setView(progressView);
|
|||
|
|
|
|||
|
|
|
|||
|
|
mRotateUpAnim = new RotateAnimation(0.0f, -180.0f,
|
|||
|
|
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
|
|||
|
|
mRotateUpAnim.setDuration(ROTATE_ANIM_DURATION);
|
|||
|
|
mRotateUpAnim.setFillAfter(true);
|
|||
|
|
mRotateDownAnim = new RotateAnimation(-180.0f, 0.0f,
|
|||
|
|
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
|
|||
|
|
mRotateDownAnim.setDuration(ROTATE_ANIM_DURATION);
|
|||
|
|
mRotateDownAnim.setFillAfter(true);
|
|||
|
|
|
|||
|
|
mHeaderTimeView = (TextView)findViewById(R.id.last_refresh_time);
|
|||
|
|
measure(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
|
|||
|
|
mMeasuredHeight = getMeasuredHeight();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void setProgressStyle(int style) {
|
|||
|
|
if(style == ProgressStyle.SysProgress){
|
|||
|
|
mProgressBar.setView(new ProgressBar(getContext(), null, android.R.attr.progressBarStyle));
|
|||
|
|
}else{
|
|||
|
|
AVLoadingIndicatorView progressView = new AVLoadingIndicatorView(this.getContext());
|
|||
|
|
progressView.setIndicatorColor(0xffB5B5B5);
|
|||
|
|
progressView.setIndicatorId(style);
|
|||
|
|
mProgressBar.setView(progressView);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void setArrowImageView(int resid){
|
|||
|
|
mArrowImageView.setImageResource(resid);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void setState(int state) {
|
|||
|
|
if (state == mState) return ;
|
|||
|
|
|
|||
|
|
if (state == STATE_REFRESHING) { // 显示进度
|
|||
|
|
mArrowImageView.clearAnimation();
|
|||
|
|
mArrowImageView.setVisibility(View.INVISIBLE);
|
|||
|
|
mProgressBar.setVisibility(View.VISIBLE);
|
|||
|
|
smoothScrollTo(mMeasuredHeight);
|
|||
|
|
} else if(state == STATE_DONE) {
|
|||
|
|
mArrowImageView.setVisibility(View.INVISIBLE);
|
|||
|
|
mProgressBar.setVisibility(View.INVISIBLE);
|
|||
|
|
} else { // 显示箭头图片
|
|||
|
|
mArrowImageView.setVisibility(View.VISIBLE);
|
|||
|
|
mProgressBar.setVisibility(View.INVISIBLE);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
switch(state){
|
|||
|
|
case STATE_NORMAL:
|
|||
|
|
if (mState == STATE_RELEASE_TO_REFRESH) {
|
|||
|
|
mArrowImageView.startAnimation(mRotateDownAnim);
|
|||
|
|
}
|
|||
|
|
if (mState == STATE_REFRESHING) {
|
|||
|
|
mArrowImageView.clearAnimation();
|
|||
|
|
}
|
|||
|
|
mStatusTextView.setText(R.string.listview_header_hint_normal);
|
|||
|
|
break;
|
|||
|
|
case STATE_RELEASE_TO_REFRESH:
|
|||
|
|
if (mState != STATE_RELEASE_TO_REFRESH) {
|
|||
|
|
mArrowImageView.clearAnimation();
|
|||
|
|
mArrowImageView.startAnimation(mRotateUpAnim);
|
|||
|
|
mStatusTextView.setText(R.string.listview_header_hint_release);
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
case STATE_REFRESHING:
|
|||
|
|
mStatusTextView.setText(R.string.refreshing);
|
|||
|
|
break;
|
|||
|
|
case STATE_DONE:
|
|||
|
|
mStatusTextView.setText(R.string.refresh_done);
|
|||
|
|
break;
|
|||
|
|
default:
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
mState = state;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public int getState() {
|
|||
|
|
return mState;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
public void refreshComplete(){
|
|||
|
|
mHeaderTimeView.setText(friendlyTime(new Date()));
|
|||
|
|
setState(STATE_DONE);
|
|||
|
|
new Handler().postDelayed(new Runnable(){
|
|||
|
|
public void run() {
|
|||
|
|
reset();
|
|||
|
|
}
|
|||
|
|
}, 200);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void setVisibleHeight(int height) {
|
|||
|
|
if (height < 0) height = 0;
|
|||
|
|
LayoutParams lp = (LayoutParams) mContainer .getLayoutParams();
|
|||
|
|
lp.height = height;
|
|||
|
|
mContainer.setLayoutParams(lp);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public int getVisibleHeight() {
|
|||
|
|
LayoutParams lp = (LayoutParams) mContainer.getLayoutParams();
|
|||
|
|
return lp.height;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
public void onMove(float delta) {
|
|||
|
|
if(getVisibleHeight() > 0 || delta > 0) {
|
|||
|
|
setVisibleHeight((int) delta + getVisibleHeight());
|
|||
|
|
if (mState <= STATE_RELEASE_TO_REFRESH) { // 未处于刷新状态,更新箭头
|
|||
|
|
if (getVisibleHeight() > mMeasuredHeight) {
|
|||
|
|
setState(STATE_RELEASE_TO_REFRESH);
|
|||
|
|
}else {
|
|||
|
|
setState(STATE_NORMAL);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
public boolean releaseAction() {
|
|||
|
|
boolean isOnRefresh = false;
|
|||
|
|
int height = getVisibleHeight();
|
|||
|
|
if (height == 0) // not visible.
|
|||
|
|
isOnRefresh = false;
|
|||
|
|
|
|||
|
|
if(getVisibleHeight() > mMeasuredHeight && mState < STATE_REFRESHING){
|
|||
|
|
setState(STATE_REFRESHING);
|
|||
|
|
isOnRefresh = true;
|
|||
|
|
}
|
|||
|
|
// refreshing and header isn't shown fully. do nothing.
|
|||
|
|
if (mState == STATE_REFRESHING && height <= mMeasuredHeight) {
|
|||
|
|
// return false;
|
|||
|
|
}
|
|||
|
|
if (mState != STATE_REFRESHING) {
|
|||
|
|
smoothScrollTo(0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (mState == STATE_REFRESHING) {
|
|||
|
|
int destHeight = mMeasuredHeight;
|
|||
|
|
smoothScrollTo(destHeight);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return isOnRefresh;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void reset() {
|
|||
|
|
smoothScrollTo(0);
|
|||
|
|
new Handler().postDelayed(new Runnable() {
|
|||
|
|
public void run() {
|
|||
|
|
setState(STATE_NORMAL);
|
|||
|
|
}
|
|||
|
|
}, 500);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void smoothScrollTo(int destHeight) {
|
|||
|
|
ValueAnimator animator = ValueAnimator.ofInt(getVisibleHeight(), destHeight);
|
|||
|
|
animator.setDuration(300).start();
|
|||
|
|
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
|||
|
|
@Override
|
|||
|
|
public void onAnimationUpdate(ValueAnimator animation)
|
|||
|
|
{
|
|||
|
|
setVisibleHeight((int) animation.getAnimatedValue());
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
animator.start();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static String friendlyTime(Date time) {
|
|||
|
|
//获取time距离当前的秒数
|
|||
|
|
int ct = (int)((System.currentTimeMillis() - time.getTime())/1000);
|
|||
|
|
|
|||
|
|
if(ct == 0) {
|
|||
|
|
return "刚刚";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if(ct > 0 && ct < 60) {
|
|||
|
|
return ct + "秒前";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if(ct >= 60 && ct < 3600) {
|
|||
|
|
return Math.max(ct / 60,1) + "分钟前";
|
|||
|
|
}
|
|||
|
|
if(ct >= 3600 && ct < 86400)
|
|||
|
|
return ct / 3600 + "小时前";
|
|||
|
|
if(ct >= 86400 && ct < 2592000){ //86400 * 30
|
|||
|
|
int day = ct / 86400 ;
|
|||
|
|
return day + "天前";
|
|||
|
|
}
|
|||
|
|
if(ct >= 2592000 && ct < 31104000) { //86400 * 30
|
|||
|
|
return ct / 2592000 + "月前";
|
|||
|
|
}
|
|||
|
|
return ct / 31104000 + "年前";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|