贴出来自定下拉刷新的源码,其主要部分已经贴出来了,欢迎拍砖。
git@git.oschina.net:gezihua/supro.git
package com.example.gezihua.myapplication.pull;
import android.animation.ValueAnimator;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.view.animation.DecelerateInterpolator;
import android.widget.RelativeLayout;
import com.example.gezihua.myapplication.R;
import java.lang.ref.WeakReference;
/**
* Created by gezihua on 16-12-20.
*/
public class PullToRefresh extends RelativeLayout {
private boolean mIsBeingDragged;
private float mTouchSlop;
private float mStartY;
private float mLastMottionY;
private ValueAnimator mResetAnimation;
public void setmRefreshView(IPullView mRefreshView) {
this.mRefreshView = mRefreshView;
}
private IPullView mRefreshView;
public void setHeaderView(IHeaderView headerView) {
mHeaderView = headerView;
}
private IHeaderView mHeaderView;
public PullToRefresh(Context context) {
super(context);
init();
}
private void init() {
ViewConfiguration config = ViewConfiguration.get(getContext());
mTouchSlop = config.getScaledTouchSlop();
int dimensionPixelOffset = getResources().getDimensionPixelOffset(R.dimen.pull_to_refresh_max);
if (dimensionPixelOffset < MAX_PULL) {
MAX_PULL = dimensionPixelOffset;
}
}
public PullToRefresh(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public PullToRefresh(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
//能相应第一个应该是Down事件
// 对于能滚动View的View来说,这个时候应该已经滚动到最上边
if (mRefreshView == null || !mRefreshView.canScroll()) {
Log.e("suj", "can scroll" + mRefreshView.canScroll());
mIsBeingDragged = false;
return super.onInterceptTouchEvent(ev);
}
int action = ev.getAction();
Log.e("suj", "onInterceptTouchEvent" + ev.toString());
switch (action) {
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
if (mIsBeingDragged) {
return true;
}
break;
}
// 这里应该返回false ,别问我为什么
//如果子布局还要处理事件,这里一定要返回false
//真正拦截不下发的地方应该在 move 事件
case MotionEvent.ACTION_DOWN: {
return startDragging(ev);
}
case MotionEvent.ACTION_MOVE: {
return onDragging(ev);
}
}
return super.onInterceptTouchEvent(ev);
}
private boolean onDragging(MotionEvent ev) {
mLastMottionY = ev.getY();
if (mLastMottionY < mStartY) {
mIsBeingDragged = false;
return false;
}
mIsBeingDragged = true;
boolean dragging = Math.abs(mLastMottionY - mStartY) >= mTouchSlop;
//Log.e("suj","can dragging"+dragging);
return dragging;
}
private boolean startDragging(MotionEvent ev) {
mStartY = ev.getY();
mIsBeingDragged = true;
return false;
}
private boolean showHeaderView() {
if (mHeaderView == null) {
return false;
}
return mHeaderView.canRefresh();
}
private static class H extends Handler {
WeakReference<PullToRefresh> pullToRefreshRef;
public H(PullToRefresh refresh) {
pullToRefreshRef = new WeakReference<PullToRefresh>(refresh);
}
@Override
public void dispatchMessage(Message msg) {
super.dispatchMessage(msg);
if (msg.what != MSG_END_DRAGGING) {
return;
}
PullToRefresh pullToRefresh = pullToRefreshRef.get();
if (pullToRefresh == null) {
return;
}
pullToRefresh.reset();
}
}
private final static int MSG_END_DRAGGING = 1;
private H mH;
private Message generateDraggingMsg(int msg) {
Message obtain = Message.obtain();
obtain.what = msg;
return obtain;
}
private void handleEndDragging(MotionEvent ev) {
mIsBeingDragged = false;
mLastMottionY = 0;
mStartY = 0;
// 为了解决不能连续刷新的问题,应该把以前的动画以及刷新动画停止,并且重置状态
removeDelayEndDragging();
endResetAnimation();
// then we can do some refresh animator;
// if the header is not show ,we can do animation immediately
if (showHeaderView()) {
if (mH == null) {
mH = new H(this);
}
mH.sendMessageDelayed(generateDraggingMsg(MSG_END_DRAGGING), 350);
// then we can start refresh animation
mHeaderView.showRefresh();
} else {
reset();
}
}
private void removeDelayEndDragging() {
if (mH == null) {
return;
}
mH.removeMessages(MSG_END_DRAGGING);
}
private void endResetAnimation(){
if (mResetAnimation==null){
return;
}
if (mResetAnimation.isRunning()){
mResetAnimation.cancel();
}
}
private void endHeaderAnimation(){
if (mHeaderView==null){
return;
}
mHeaderView.cancelRefresh();
}
// when destroy we must remove the delayed msg
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
removeDelayEndDragging();
}
private void reset() {
mResetAnimation = ValueAnimator.ofFloat(mRefreshView.getPullTransY(), 0);
mResetAnimation.setDuration(350);
mResetAnimation.setRepeatMode(ValueAnimator.RESTART);
mResetAnimation.setInterpolator(new DecelerateInterpolator());
mResetAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float animatedValue = (float) animation.getAnimatedValue();
mRefreshView.setPullTransY((int) animatedValue);
}
});
mResetAnimation.start();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.e("suj", "onTouchEvent" + event.toString());
if (mIsBeingDragged) {
int action = event.getAction();
//Log.e("suj","onTouchEvent"+event.toString());
switch (action) {
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP: {
handleEndDragging(event);
break;
}
case MotionEvent.ACTION_MOVE: {
return handleDragging(event);
}
case MotionEvent.ACTION_DOWN: {
break;
}
}
return true;
}
return super.onTouchEvent(event);
}
private int MAX_PULL = 300;
private boolean handleDragging(MotionEvent event) {
if (mRefreshView == null) {
return false;
}
mLastMottionY = event.getY();
if (mLastMottionY < mStartY) {
return false;
}
int lastTransY = mRefreshView.getPullTransY();
float v = mLastMottionY - mStartY;
//Log.e("suj","mLastMottionY"+mLastMottionY+"startY"+mStartY);
int pull = (lastTransY + v) / 2 > MAX_PULL ? MAX_PULL : (int) (lastTransY + v) / 2;
mRefreshView.setPullTransY(pull);
return true;
}
}