网上发现一开源项目,下面是效果图:



相关的主要代码:

public class PullToRefreshView extends ViewGroup {    private static final int DRAG_MAX_DISTANCE = 120;    private static final float DRAG_RATE = .5f;    private static final float DECELERATE_INTERPOLATION_FACTOR = 2f;    public static final int STYLE_SUN = 0;    public static final int MAX_OFFSET_ANIMATION_DURATION = 700;    private static final int INVALID_POINTER = -1;    private View mTarget;    private ImageView mRefreshView;    private Interpolator mDecelerateInterpolator;    private int mTouchSlop;    private int mTotalDragDistance;    private BaseRefreshView mBaseRefreshView;    private float mCurrentDragPercent;    private int mCurrentOffsetTop;    private boolean mRefreshing;    private int mActivePointerId;    private boolean mIsBeingDragged;    private float mInitialMotionY;    private int mFrom;    private float mFromDragPercent;    private boolean mNotify;    private OnRefreshListener mListener;    public PullToRefreshView(Context context) {        this(context, null);    }    public PullToRefreshView(Context context, AttributeSet attrs) {        super(context, attrs);        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RefreshView);        final int type = a.getInteger(R.styleable.RefreshView_type, STYLE_SUN);        a.recycle();        mDecelerateInterpolator = new DecelerateInterpolator(DECELERATE_INTERPOLATION_FACTOR);        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();        mTotalDragDistance = Utils.convertDpToPixel(context, DRAG_MAX_DISTANCE);        mRefreshView = new ImageView(context);        setRefreshStyle(type);        addView(mRefreshView);        setWillNotDraw(false);        ViewCompat.setChildrenDrawingOrderEnabled(this, true);    }    public void setRefreshStyle(int type) {        setRefreshing(false);        switch (type) {            case STYLE_SUN:                mBaseRefreshView = new SunRefreshView(getContext(), this);                break;            default:                throw new InvalidParameterException("Type does not exist");        }        mRefreshView.setImageDrawable(mBaseRefreshView);    }    public int getTotalDragDistance() {        return mTotalDragDistance;    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        ensureTarget();        if (mTarget == null)            return;        widthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth() - getPaddingRight() - getPaddingLeft(), MeasureSpec.EXACTLY);        heightMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY);        mTarget.measure(widthMeasureSpec, heightMeasureSpec);        mRefreshView.measure(widthMeasureSpec, heightMeasureSpec);    }    private void ensureTarget() {        if (mTarget != null)            return;        if (getChildCount() > 0) {            for (int i = 0; i < getChildCount(); i++) {                View child = getChildAt(i);                if (child != mRefreshView)                    mTarget = child;            }        }    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        if (!isEnabled() || canChildScrollUp() || mRefreshing) {            return false;        }        final int action = MotionEventCompat.getActionMasked(ev);        switch (action) {            case MotionEvent.ACTION_DOWN:                setTargetOffsetTop(0, true);                mActivePointerId = MotionEventCompat.getPointerId(ev, 0);                mIsBeingDragged = false;                final float initialMotionY = getMotionEventY(ev, mActivePointerId);                if (initialMotionY == -1) {                    return false;                }                mInitialMotionY = initialMotionY;                break;            case MotionEvent.ACTION_MOVE:                if (mActivePointerId == INVALID_POINTER) {                    return false;                }                final float y = getMotionEventY(ev, mActivePointerId);                if (y == -1) {                    return false;                }                final float yDiff = y - mInitialMotionY;                if (yDiff > mTouchSlop && !mIsBeingDragged) {                    mIsBeingDragged = true;                }                break;            case MotionEvent.ACTION_UP:            case MotionEvent.ACTION_CANCEL:                mIsBeingDragged = false;                mActivePointerId = INVALID_POINTER;                break;            case MotionEventCompat.ACTION_POINTER_UP:                onSecondaryPointerUp(ev);                break;        }        return mIsBeingDragged;    }    @Override    public boolean onTouchEvent(@NonNull MotionEvent ev) {        if (!mIsBeingDragged) {            return super.onTouchEvent(ev);        }        final int action = MotionEventCompat.getActionMasked(ev);        switch (action) {            case MotionEvent.ACTION_MOVE: {                final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);                if (pointerIndex < 0) {                    return false;                }                final float y = MotionEventCompat.getY(ev, pointerIndex);                final float yDiff = y - mInitialMotionY;                final float scrollTop = yDiff * DRAG_RATE;                mCurrentDragPercent = scrollTop / mTotalDragDistance;                if (mCurrentDragPercent < 0) {                    return false;                }                float boundedDragPercent = Math.min(1f, Math.abs(mCurrentDragPercent));                float extraOS = Math.abs(scrollTop) - mTotalDragDistance;                float slingshotDist = mTotalDragDistance;                float tensionSlingshotPercent = Math.max(0,                        Math.min(extraOS, slingshotDist * 2) / slingshotDist);                float tensionPercent = (float) ((tensionSlingshotPercent / 4) - Math.pow(                        (tensionSlingshotPercent / 4), 2)) * 2f;                float extraMove = (slingshotDist) * tensionPercent / 2;                int targetY = (int) ((slingshotDist * boundedDragPercent) + extraMove);                mBaseRefreshView.setPercent(mCurrentDragPercent, true);                setTargetOffsetTop(targetY - mCurrentOffsetTop, true);                break;            }            case MotionEventCompat.ACTION_POINTER_DOWN:                final int index = MotionEventCompat.getActionIndex(ev);                mActivePointerId = MotionEventCompat.getPointerId(ev, index);                break;            case MotionEventCompat.ACTION_POINTER_UP:                onSecondaryPointerUp(ev);                break;            case MotionEvent.ACTION_UP:            case MotionEvent.ACTION_CANCEL: {                if (mActivePointerId == INVALID_POINTER) {                    return false;                }                final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);                final float y = MotionEventCompat.getY(ev, pointerIndex);                final float overScrollTop = (y - mInitialMotionY) * DRAG_RATE;                mIsBeingDragged = false;                if (overScrollTop > mTotalDragDistance) {                    setRefreshing(true, true);                } else {                    mRefreshing = false;                    animateOffsetToStartPosition();                }                mActivePointerId = INVALID_POINTER;                return false;            }        }        return true;    }    private void animateOffsetToStartPosition() {        mFrom = mCurrentOffsetTop;        mFromDragPercent = mCurrentDragPercent;        long animationDuration = Math.abs((long) (MAX_OFFSET_ANIMATION_DURATION * mFromDragPercent));        mAnimateToStartPosition.reset();        mAnimateToStartPosition.setDuration(animationDuration);        mAnimateToStartPosition.setInterpolator(mDecelerateInterpolator);        mAnimateToStartPosition.setAnimationListener(mToStartListener);        mRefreshView.clearAnimation();        mRefreshView.startAnimation(mAnimateToStartPosition);    }    private void animateOffsetToCorrectPosition() {        mFrom = mCurrentOffsetTop;        mFromDragPercent = mCurrentDragPercent;        mAnimateToCorrectPosition.reset();        mAnimateToCorrectPosition.setDuration(MAX_OFFSET_ANIMATION_DURATION);        mAnimateToCorrectPosition.setInterpolator(mDecelerateInterpolator);        mRefreshView.clearAnimation();        mRefreshView.startAnimation(mAnimateToCorrectPosition);        if (mRefreshing) {            mBaseRefreshView.start();            if (mNotify) {                if (mListener != null) {                    mListener.onRefresh();                }            }        } else {            mBaseRefreshView.stop();            animateOffsetToStartPosition();        }        mCurrentOffsetTop = mTarget.getTop();        mTarget.setPadding(0, 0, 0, mTotalDragDistance);    }    private final Animation mAnimateToStartPosition = new Animation() {        @Override        public void applyTransformation(float interpolatedTime, Transformation t) {            moveToStart(interpolatedTime);        }    };    private final Animation mAnimateToCorrectPosition = new Animation() {        @Override        public void applyTransformation(float interpolatedTime, Transformation t) {            int targetTop;            int endTarget = mTotalDragDistance;            targetTop = (mFrom + (int) ((endTarget - mFrom) * interpolatedTime));            int offset = targetTop - mTarget.getTop();            mCurrentDragPercent = mFromDragPercent - (mFromDragPercent - 1.0f) * interpolatedTime;            mBaseRefreshView.setPercent(mCurrentDragPercent, false);            setTargetOffsetTop(offset, false /* requires update */);        }    };    private void moveToStart(float interpolatedTime) {        int targetTop = mFrom - (int) (mFrom * interpolatedTime);        float targetPercent = mFromDragPercent * (1.0f - interpolatedTime);        int offset = targetTop - mTarget.getTop();        mCurrentDragPercent = targetPercent;        mBaseRefreshView.setPercent(mCurrentDragPercent, true);        mTarget.setPadding(0, 0, 0, targetTop);        setTargetOffsetTop(offset, false);    }    public void setRefreshing(boolean refreshing) {        if (mRefreshing != refreshing) {            setRefreshing(refreshing, false /* notify */);        }    }    private void setRefreshing(boolean refreshing, final boolean notify) {        if (mRefreshing != refreshing) {            mNotify = notify;            ensureTarget();            mRefreshing = refreshing;            if (mRefreshing) {                mBaseRefreshView.setPercent(1f, true);                animateOffsetToCorrectPosition();            } else {                animateOffsetToStartPosition();            }        }    }    private Animation.AnimationListener mToStartListener = new Animation.AnimationListener() {        @Override        public void onAnimationStart(Animation animation) {        }        @Override        public void onAnimationRepeat(Animation animation) {        }        @Override        public void onAnimationEnd(Animation animation) {            mBaseRefreshView.stop();            mCurrentOffsetTop = mTarget.getTop();        }    };    private void onSecondaryPointerUp(MotionEvent ev) {        final int pointerIndex = MotionEventCompat.getActionIndex(ev);        final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);        if (pointerId == mActivePointerId) {            final int newPointerIndex = pointerIndex == 0 ? 1 : 0;            mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);        }    }    private float getMotionEventY(MotionEvent ev, int activePointerId) {        final int index = MotionEventCompat.findPointerIndex(ev, activePointerId);        if (index < 0) {            return -1;        }        return MotionEventCompat.getY(ev, index);    }    private void setTargetOffsetTop(int offset, boolean requiresUpdate) {        mTarget.offsetTopAndBottom(offset);        mBaseRefreshView.offsetTopAndBottom(offset);        mCurrentOffsetTop = mTarget.getTop();        if (requiresUpdate && android.os.Build.VERSION.SDK_INT < 11) {            invalidate();        }    }    private boolean canChildScrollUp() {        if (android.os.Build.VERSION.SDK_INT < 14) {            if (mTarget instanceof AbsListView) {                final AbsListView absListView = (AbsListView) mTarget;                return absListView.getChildCount() > 0                        && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0)                        .getTop() < absListView.getPaddingTop());            } else {                return mTarget.getScrollY() > 0;            }        } else {            return ViewCompat.canScrollVertically(mTarget, -1);        }    }    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        ensureTarget();        if (mTarget == null)            return;        int height = getMeasuredHeight();        int width = getMeasuredWidth();        int left = getPaddingLeft();        int top = getPaddingTop();        int right = getPaddingRight();        int bottom = getPaddingBottom();        mTarget.layout(left, top + mCurrentOffsetTop, left + width - right, top + height - bottom + mCurrentOffsetTop);        mRefreshView.layout(left, top, left + width - right, top + height - bottom);    }    public void setOnRefreshListener(OnRefreshListener listener) {        mListener = listener;    }    public static interface OnRefreshListener {        public void onRefresh();    }}

github上可以直接下载android studio _demo,我这里也可以下载运行在eclipse上的demo,地址:http://download.csdn.net/detail/anddroid_lanyan/8638001


更多相关文章

  1. android短信发送器源代码
  2. android:注册时的协议---》方法一:弹出框
  3. 区分IOS和Android
  4. fanfou(饭否) android客户端 代码学习1
  5. Android使用HttpURLConnection显示网络图片
  6. Android(安卓)Material Design 实践(六)--MaterialNavigationDra
  7. Android横竖屏总结
  8. Android实用代码片段(一)
  9. Android(安卓)Material Design 实践(二)--Dialogs

随机推荐

  1. android 内存分析(MAT工具的使用)
  2. 27、从头学Android之多媒体--使用VideoVi
  3. system image file too large for device
  4. Android(安卓)Activity启动流程
  5. 如何解决Eclipse中Android(安卓)代码自动
  6. Android中双击返回键退出应用实例代码
  7. Android面试汇总文章
  8. 实现activity全屏显示
  9. android代码power off 以及特定文件格式
  10. 最好的Android(安卓)apps,Android(安卓)a