zoukankan      html  css  js  c++  java
  • 一款Android开源的下拉刷新动画

    无意间在GitHub看到的,就Down了下来。但是作者是用AndroidStudio开发的,这边移动Eclipse供小伙伴们下载使用。

    截图

    这么好的东西因为字数不够不让分享,得了,贴段代码吧

    package com.example.pullrefersh;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.support.v4.view.MotionEventCompat;
    import android.support.v4.view.ViewCompat;
    import android.util.AttributeSet;
    import android.util.TypedValue;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewConfiguration;
    import android.view.ViewGroup;
    import android.view.animation.Animation;
    import android.view.animation.DecelerateInterpolator;
    import android.view.animation.Interpolator;
    import android.view.animation.Transformation;
    import android.widget.AbsListView;
    import android.widget.ImageView;
    
    import java.security.InvalidParameterException;
    
    import refresh_view.BaseRefreshView;
    import refresh_view.SunRefreshView;
    import util.Utils;
    
    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 STYLE_JET = 1;
        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;
                case STYLE_JET:
                    // TODO
                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(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();
        }
    
        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);
            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();
        }
    
    }

    下载地址:http://download.csdn.net/detail/lj419855402/8421179

  • 相关阅读:
    [转]BIOS中断汇编函数---留用
    SWT/JFace 按键、事件、监听
    erlang局域网内通信
    ios热修复
    swift里面!和?的作用
    AFNetworking上传下载图片
    横向滚动的UITableView
    判断iphone手机型号
    iPhone屏幕尺寸、分辨率及适配
    UITapGestureRecognizer 和UIPanGestureRecognizer的使用,触摸和滑动
  • 原文地址:https://www.cnblogs.com/LIANQQ/p/4271157.html
Copyright © 2011-2022 走看看