/**
* 兼容 4.2 一下所有
* 修复 4.1.2 BUG(箭头动画不动)
* @author {author lsw}
*
*/
public class PullToRefresh extends FrameLayout implements
GestureDetector.OnGestureListener {
public static final int STATE_CLOSE = 1;
public static final int STATE_OPEN = 2;
public static final int STATE_OPEN_MAX = 4;
public static final int STATE_OPEN_MAX_RELEASE = 5;
public static final int STATE_OPEN_RELEASE = 3;
public static final int STATE_UPDATE = 6;
public static final int STATE_UPDATE_SCROLL = 7;
private int MAXHEIGHT = 80;
private final String TAG = "PullToRefresh";
private ImageView mArrow;
private String mDate;
private GestureDetector mDetector;
private Flinger mFlinger;
private boolean mIsAutoScroller;
private int mPading;
private ProgressBar mProgressBar;
private int mState;
private TextView mTitle;
private UpdateHandle mUpdateHandle;
private RotateAnimation mFlipAnimation;
private RotateAnimation mReverseFlipAnimation;
private boolean mIsOpen = true;
public PullToRefresh(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
DisplayMetrics dm =context.getResources().getDisplayMetrics();
MAXHEIGHT =(int) (context.getResources().getDimension(R.dimen.updatebar_height) * (dm.densityDpi/160));
addUpdateBar();
init();
}
public PullToRefresh(Context context, AttributeSet attrs) {
super(context, attrs);
DisplayMetrics dm =context.getResources().getDisplayMetrics();
MAXHEIGHT =(int) (context.getResources().getDimension(R.dimen.updatebar_height) * (dm.densityDpi/160));
//Log.i("lgsh", "MAXHEIGHT"+MAXHEIGHT);
addUpdateBar();
init();
}
public PullToRefresh(Context context) {
super(context);
DisplayMetrics dm =context.getResources().getDisplayMetrics();
MAXHEIGHT =(int) (context.getResources().getDimension(R.dimen.updatebar_height) * (dm.densityDpi/160));
addUpdateBar();
init();
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.d(TAG, "[dispatchTouchEvent]");
boolean bool1 = this.mIsAutoScroller;
GestureDetector localGestureDetector = this.mDetector;
float lastY = 0;
float newY = 0;
localGestureDetector.onTouchEvent(ev);
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
lastY = ev.getY();
case MotionEvent.ACTION_MOVE:
int i1 = getChildAt(1).getTop();
//Log.i("lgs", "getChildAt(1).getTop" + i1);
if (i1 != 0) {
updateView();
}
break;
case MotionEvent.ACTION_UP:
newY = ev.getY();
if (this.mState == STATE_OPEN) {
this.mState = STATE_OPEN_RELEASE;
}
if (this.mState == STATE_OPEN_MAX) {
this.mState = STATE_OPEN_MAX_RELEASE;
}
Log.d(TAG, "[onScroll] ActionUP mState=" + mState);
release();
break;
}
if (mState != STATE_UPDATE) {
bool1 = super.dispatchTouchEvent(ev);
//Log.i("lgs", "dispatchTouchEvent"+bool1+mState);
}
int i1 = getChildAt(1).getTop();
Log.d("lgs", "[dispatchTouchEvent] getTop()=" + i1);
if (i1 != 0) {
ev.setAction(3);
super.dispatchTouchEvent(ev);
updateView();
}
if(Math.abs(lastY -newY ) < 10){
return true;
}
return bool1;
}
private void init() {
GestureDetector localGestureDetector = new GestureDetector(this);
this.mDetector = localGestureDetector;
Flinger localFlinger = new Flinger();
this.mFlinger = localFlinger;
this.mState = 1;
setDrawingCacheEnabled(true);
setClipChildren(true);
this.mDetector.setIsLongpressEnabled(false);
}
private void updateView() {
Log.d("lgs", String.format("updateView %d", this.mState));
View localView1 = getChildAt(0);
View localView2 = getChildAt(1);
if (this.mDate == null)
this.mDate = "";
switch (this.mState) {
case STATE_CLOSE:
if (localView1.getVisibility() != View.INVISIBLE)
localView1.setVisibility(View.INVISIBLE);
case STATE_OPEN:
case STATE_OPEN_RELEASE:
Log.d(TAG, "updateView STATE_OPEN");
// STATE_OPEN
int m = localView2.getTop();
int n = -this.mPading - m;
//Log.i("lgs1", "localView2__m-n="+m+","+n+"mPading+"+mPading);
localView2.offsetTopAndBottom(n);
if (localView1.getVisibility() != 0)
localView1.setVisibility(View.VISIBLE);
int i1 = localView1.getTop();// 相对于父窗口的顶部大小
int i2 = -MAXHEIGHT;
int i3 = this.mPading;
int i4 = i2 - i3 - i1;
//Log.i("lgs1", "localView1__i1-4="+i1+","+i2+","+i3+","+i4);
localView1.offsetTopAndBottom(i4);
TextView localTextView1 = this.mTitle;
String str1 = "下拉可以刷新";
StringBuilder localStringBuilder1 = new StringBuilder(str1)
.append("\n");
localStringBuilder1.append(this.mDate);
localTextView1.setText(localStringBuilder1.toString());
this.mProgressBar.setVisibility(View.INVISIBLE);
this.mArrow.setVisibility(View.VISIBLE);
if (!mIsOpen) {
mIsOpen = true;
this.mArrow.startAnimation(mReverseFlipAnimation);
// mReverseFlipAnimation.start();
}
break;
case STATE_OPEN_MAX_RELEASE:
case STATE_OPEN_MAX:
int i5 = localView2.getTop();
int i6 = -this.mPading - i5;
//Log.i("lgs1", "localView2__i5-6="+i5+","+i6);
localView2.offsetTopAndBottom(i6);
if (localView1.getVisibility() != View.VISIBLE)
localView1.setVisibility(View.VISIBLE);
int i7 = localView1.getTop();
int i8 = -MAXHEIGHT;
int i9 = this.mPading;
int i10 = i8 - i9 - i7;
//Log.i("lgs1", "localView1__i7-10="+i7+","+i8+","+i9+","+i10);
localView1.offsetTopAndBottom(i10);
TextView localTextView2 = this.mTitle;
String str4 = "松开可以刷新";// release_update:松开可以刷新
StringBuilder localStringBuilder2 = new StringBuilder(str4)
.append("\n");
localStringBuilder2.append(this.mDate);
localTextView2.setText(localStringBuilder2.toString());
this.mProgressBar.setVisibility(View.INVISIBLE);
this.mArrow.setVisibility(View.VISIBLE);
if (mIsOpen) {
mIsOpen = false;
this.mArrow.startAnimation(mFlipAnimation);
// mFlipAnimation.start();
}
break;
case STATE_UPDATE:
// STATE_UPDATE
int i11 = localView2.getTop();
int i12 = -this.mPading - i11;
localView2.offsetTopAndBottom(i12);
int i13 = localView1.getTop();
if (this.mProgressBar.getVisibility() != View.VISIBLE)
this.mProgressBar.setVisibility(View.VISIBLE);
if (this.mArrow.getVisibility() != View.INVISIBLE)
this.mArrow.setVisibility(View.INVISIBLE);
TextView localTextView3 = this.mTitle;
String str7 = "加载中...";// doing_update:加载中...
StringBuilder localStringBuilder3 = new StringBuilder(str7)
.append("\n");
localStringBuilder3.append(this.mDate);
localTextView3.setText(localStringBuilder3.toString());
int i14 = -MAXHEIGHT;
int i15 = this.mPading;
int i16 = i14 - i15 - i13;
localView1.offsetTopAndBottom(i16);
if (localView1.getVisibility() != 0)
localView1.setVisibility(0);
this.mProgressBar.setVisibility(View.VISIBLE);
this.mArrow.setVisibility(View.GONE);
mArrow.clearAnimation();
break;
}
invalidate();
}
private void addUpdateBar() {
Context localContext1 = getContext();
mFlipAnimation = new RotateAnimation(0, -180,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
mFlipAnimation.setInterpolator(new LinearInterpolator());
mFlipAnimation.setDuration(200);
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(200);
mReverseFlipAnimation.setFillAfter(true);
View localView = LayoutInflater.from(localContext1).inflate(
R.layout.vw_update_bar, null);
localView.setVisibility(4);
addView(localView);
this.mArrow = (ImageView) localView.findViewById(R.id.arrow_image);
this.mProgressBar = (ProgressBar) localView.findViewById(R.id.refresh_progress);
this.mProgressBar.setVisibility(View.INVISIBLE);
this.mTitle = (TextView) findViewById(R.id.tv_title);
}
protected void onLayout(boolean paramBoolean, int paramInt1, int paramInt2,
int paramInt3, int paramInt4) {
View localView1 = getChildAt(0);
int i = -MAXHEIGHT;
int j = this.mPading;
int k = i - j;
int l = getMeasuredWidth();
int i1 = -this.mPading;
localView1.layout(0, k, l, i1);
//Log.i("lgs9", "onLayout="+" i=" +i+" j="+j+" k=" +k+" l="+l+" i1="+i1);
View localView2 = getChildAt(1);
int i2 = -this.mPading;
int i3 = getMeasuredWidth();
int i4 = getMeasuredHeight();
int i5 = this.mPading;
int i6 = i4 - i5;
localView2.layout(0, i2, i3, i6);
//Log.i("lgs9", "onLayout="+" i2=" +i2+" i3="+i3+" i4=" +i4+" i5="+i5+" i6="+i6);
}
public void endUpdate(String paramString) {
this.mDate = paramString;
Log.d(TAG, "[endUpdate] mPading=" + this.mPading);
if (this.mPading != 0) {
this.mState = STATE_CLOSE;
scrollToClose();
}
}
@Override
public boolean onDown(MotionEvent e) {
return false;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
Log.d("lgs2", "[onScroll] paramFloat2=" + distanceY + " mPadding="
+ this.mPading);
View childView;
if(getChildCount()>1){
childView = this.getChildAt(1);
if(childView instanceof ListView){
AdapterView localAdapterView = (AdapterView) getChildAt(1);
int k = localAdapterView.getCount();
if (k == 0) {
return false;
}
k = localAdapterView.getFirstVisiblePosition();// 获取第一个显示项目的position
int t = localAdapterView.getChildAt(0).getTop();
if (k != 0 || t != 0) {
return false;
}
}else if(childView instanceof ScrollView){
ScrollView localAdapterView = (ScrollView) getChildAt(1);
int k = localAdapterView.getChildCount();
if (k == 0) {
return false;
}
k = localAdapterView.getScrollY();
int t = localAdapterView.getChildAt(0).getTop();
if (k != 0 || t != 0) {
return false;
}
}
Log.d("lgs2", "[onScroll] ACTION_MOVE mState=" + mState);
this.mPading = (int) (this.mPading + distanceY / 1.2);
if (this.mPading > 0)
this.mPading = 0;
if (Math.abs(this.mPading) <= MAXHEIGHT) {
this.mState = STATE_OPEN;
} else {
this.mState = STATE_OPEN_MAX;
}
updateView();
}
return false;
}
@Override
public void onLongPress(MotionEvent e) {
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
return false;
}
private int getScrollRange() {
int scrollRange = 0;
if (getChildCount() > 0) {
View child = getChildAt(0);
scrollRange = Math
.max(0,
child.getHeight()
- (getHeight()
- this.getBottomPaddingOffset() - this
.getTopPaddingOffset()));
}
return scrollRange;
}
private boolean release() {
int tempStatus = STATE_OPEN_MAX_RELEASE;
int i = this.mPading;
if (i >= 0) {
return true;
}
int j = this.mState;
switch (j) {
case STATE_OPEN_RELEASE:
int k = Math.abs(this.mPading);
int i1 = MAXHEIGHT;
if (k < i1) {
tempStatus = STATE_OPEN_MAX_RELEASE;
this.mState = tempStatus;
}
scrollToClose();
break;
case STATE_OPEN_MAX_RELEASE:
this.mState = tempStatus;
scrollToUpdate();
break;
}
return false;
}
private void scrollToClose() {
Log.d(TAG, "[scrollToClose]");
Flinger localFlinger = this.mFlinger;
int i = -this.mPading;
localFlinger.startUsingDistance(i, 500);
}
private void scrollToUpdate() {
Log.d(TAG, "[scrollToUpdate]");
Flinger localFlinger = this.mFlinger;
int k = -this.mPading - MAXHEIGHT;
localFlinger.startUsingDistance(k, 500);
}
class Flinger implements Runnable {
private int mLastFlingX;
private Scroller mScroller;
public Flinger() {
Context localContext = PullToRefresh.this.getContext();
Scroller localScroller = new Scroller(localContext);
this.mScroller = localScroller;
}
private void startCommon() {
PullToRefresh.this.removeCallbacks(this);
}
public void run() {
Log.d(TAG, "[Flinger.run] mPading=" + mPading);
boolean bool1 = Math.abs(mPading) != MAXHEIGHT;
Scroller localScroller = this.mScroller;
boolean bool2 = localScroller.computeScrollOffset();
int i = localScroller.getCurrX();
int j = this.mLastFlingX - i;
PullToRefresh localPullDownView = PullToRefresh.this;
localPullDownView.move(j, bool1);
PullToRefresh.this.updateView();
if (bool2) {
this.mLastFlingX = i;
PullToRefresh.this.post(this);
} else {
PullToRefresh.this.mIsAutoScroller = bool1;
PullToRefresh.this.removeCallbacks(this);
}
}
public void startUsingDistance(int paramInt1, int paramInt2) {
Log.d(TAG, String.format(
"[Flinger.startUsingDistance]paramInt1=%d,paramInt2=%d",
paramInt1, paramInt2));
int i = 0;
if (paramInt1 == 0)
--paramInt1;
startCommon();
this.mLastFlingX = i;
Scroller localScroller = this.mScroller;
localScroller.startScroll(i, 0, -paramInt1, 0, paramInt2);
PullToRefresh.this.mIsAutoScroller = true;
PullToRefresh.this.post(this);
}
}
/**
* 释放的时候使用*
* @param f
* @param bool1
*/
public void move(float f, boolean bool1) {
Log.d(TAG, "[move]mIsAutoScroller=" + mIsAutoScroller);
if (this.mState != STATE_CLOSE) {
if (!bool1) {
// 刷新
Log.d(TAG, "[move]refresh");
if (mState == STATE_OPEN_MAX_RELEASE) {
this.mState = STATE_UPDATE;
if (mUpdateHandle != null) {
mUpdateHandle.onUpdate();
}
}
}
if (this.mState == STATE_OPEN_MAX_RELEASE
|| this.mState == STATE_OPEN_RELEASE) {
this.mPading += f;
}
} else {
Log.d(TAG, "[move]up top");
if (mIsAutoScroller) {
this.mPading += f;
}
}
}
public abstract interface UpdateHandle {
public abstract void onUpdate();
}
public void setUpdateDate(String paramString) {
this.mDate = paramString;
}
public void setUpdateHandle(UpdateHandle paramUpdateHandle) {
this.mUpdateHandle = paramUpdateHandle;
}
public void updateWithoutOffset() {
this.mState = STATE_UPDATE_SCROLL;
invalidate();
}
}
下拉刷新控件
2023-11-06 22:02:34
上一篇:【实战虚拟化】安全设计之一基本架构
下一篇:导航引擎结构分析之二