精华内容
下载资源
问答
  • Android好的的水滴下拉刷新控件
    千次阅读
    2016-12-30 14:18:49
    自定义View,在项目中添加这2个类
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.Path;
    import android.graphics.PointF;
    import android.graphics.RectF;
    import android.util.AttributeSet;
    import android.util.TypedValue;
    import android.view.View;
    import android.view.ViewGroup;
    
    /**
     * Created by perry on 15/7/18.
     */
    public class AnimationView extends View {
        private static final String TAG = "AnimationView";
        private int PULL_HEIGHT;
        private int PULL_DELTA;
        private float mWidthOffset;
        private AnimatorStatus mAniStatus = AnimatorStatus.PULL_DOWN;
        enum AnimatorStatus {
            PULL_DOWN,
            DRAG_DOWN,
            REL_DRAG,
            SPRING_UP, // rebound to up, the position is less than PULL_HEIGHT
            POP_BALL,
            OUTER_CIR,
            REFRESHING,
            DONE,
            STOP;
    
            @Override
            public String toString() {
                switch (this) {
                    case PULL_DOWN:
                        return "pull down";
                    case DRAG_DOWN:
                        return "drag down";
                    case REL_DRAG:
                        return "release drag";
                    case SPRING_UP:
                        return "spring up";
                    case POP_BALL:
                        return "pop ball";
                    case OUTER_CIR:
                        return "outer circle";
                    case REFRESHING:
                        return "refreshing...";
                    case DONE:
                        return "done!";
                    case STOP:
                        return "stop";
                    default:
                        return "unknown state";
                }
            }
        }
        private Paint mBackPaint;
        private Paint mBallPaint;
        private Paint mOutPaint;
        private Path mPath;
        public AnimationView(Context context) {
            this(context, null, 0);
        }
        public AnimationView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
        public AnimationView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            initView(context, attrs, defStyleAttr);
        }
        private void initView(Context context, AttributeSet attrs, int defStyleAttr) {
            PULL_HEIGHT = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100, context.getResources().getDisplayMetrics());
            PULL_DELTA = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics());
            mWidthOffset = 0.5f;
            mBackPaint = new Paint();
            mBackPaint.setAntiAlias(true);
            mBackPaint.setStyle(Paint.Style.FILL);
            mBackPaint.setColor(0xff8b90af);
            mBallPaint = new Paint();
            mBallPaint.setAntiAlias(true);
            mBallPaint.setColor(0xffffffff);
            mBallPaint.setStyle(Paint.Style.FILL);
            mOutPaint = new Paint();
            mOutPaint.setAntiAlias(true);
            mOutPaint.setColor(0xffffffff);
            mOutPaint.setStyle(Paint.Style.STROKE);
            mOutPaint.setStrokeWidth(5);
            mPath = new Path();
        }
        private int mRadius;
        private int mWidth;
        private int mHeight;
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int height = MeasureSpec.getSize(heightMeasureSpec);
            if (height > PULL_DELTA + PULL_HEIGHT) {
                heightMeasureSpec = MeasureSpec.makeMeasureSpec(PULL_DELTA + PULL_HEIGHT, MeasureSpec.getMode(heightMeasureSpec));
            }
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
        @Override
        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
            super.onLayout(changed, left, top, right, bottom);
            if (changed) {
                mRadius = getHeight() / 6;
                mWidth = getWidth();
                mHeight = getHeight();
                if (mHeight < PULL_HEIGHT) {
                    mAniStatus = AnimatorStatus.PULL_DOWN;
                }
                switch (mAniStatus) {
                    case PULL_DOWN:
                        if (mHeight >= PULL_HEIGHT) {
                            mAniStatus = AnimatorStatus.DRAG_DOWN;
                        }
                        break;
                    case REL_DRAG:
                        break;
                }
            }
        }
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            switch (mAniStatus) {
                case PULL_DOWN:
                    canvas.drawRect(0, 0, mWidth, mHeight, mBackPaint);
                    break;
                case REL_DRAG:
                case DRAG_DOWN:
                    drawDrag(canvas);
                    break;
                case SPRING_UP:
                    drawSpring(canvas, getSpringDelta());
                    invalidate();
                    break;
                case POP_BALL:
                    drawPopBall(canvas);
                    invalidate();
                    break;
                case OUTER_CIR:
                    drawOutCir(canvas);
                    invalidate();
                    break;
                case REFRESHING:
                    drawRefreshing(canvas);
                    invalidate();
                    break;
                case DONE:
                    drawDone(canvas);
                    invalidate();
                    break;
                case STOP:
                    drawDone(canvas);
                    break;
            }
            if (mAniStatus == AnimatorStatus.REL_DRAG) {
                ViewGroup.LayoutParams params = getLayoutParams();
                int height;
                // NOTICE: If the height equals mLastHeight, then the requestLayout() will not work correctly
                do {
                    height = getRelHeight();
                } while (height == mLastHeight && getRelRatio() != 1);
                mLastHeight = height;
                params.height = PULL_HEIGHT + height;
                requestLayout();
            }
        }
        private void drawDrag(Canvas canvas) {
            canvas.drawRect(0, 0, mWidth, PULL_HEIGHT, mBackPaint);
            mPath.reset();
            mPath.moveTo(0, PULL_HEIGHT);
            mPath.quadTo(mWidthOffset * mWidth, PULL_HEIGHT + (mHeight - PULL_HEIGHT) * 2,
                    mWidth, PULL_HEIGHT);
            canvas.drawPath(mPath, mBackPaint);
        }
        private void drawSpring(Canvas canvas, int springDelta) {
            mPath.reset();
            mPath.moveTo(0, 0);
            mPath.lineTo(0, PULL_HEIGHT);
            mPath.quadTo(mWidth / 2, PULL_HEIGHT - springDelta,
                    mWidth, PULL_HEIGHT);
            mPath.lineTo(mWidth, 0);
            canvas.drawPath(mPath, mBackPaint);
            int curH = PULL_HEIGHT - springDelta / 2;
            if (curH > PULL_HEIGHT - PULL_DELTA / 2) {
                int leftX = (int) (mWidth / 2 - 2 * mRadius + getSprRatio() * mRadius);
                mPath.reset();
                mPath.moveTo(leftX, curH);
                mPath.quadTo(mWidth / 2, curH - mRadius * getSprRatio() * 2,
                        mWidth - leftX, curH);
                canvas.drawPath(mPath, mBallPaint);
            } else {
                canvas.drawArc(new RectF(mWidth / 2 - mRadius, curH - mRadius, mWidth / 2 + mRadius, curH + mRadius),
                        180, 180, true, mBallPaint);
            }
        }
        private void drawPopBall(Canvas canvas) {
            mPath.reset();
            mPath.moveTo(0, 0);
            mPath.lineTo(0, PULL_HEIGHT);
            mPath.quadTo(mWidth / 2, PULL_HEIGHT - PULL_DELTA,
                    mWidth, PULL_HEIGHT);
            mPath.lineTo(mWidth, 0);
            canvas.drawPath(mPath, mBackPaint);
            int cirCentStart = PULL_HEIGHT - PULL_DELTA / 2;
            int cirCenY = (int) (cirCentStart - mRadius * 2 * getPopRatio());
            canvas.drawArc(new RectF(mWidth / 2 - mRadius, cirCenY - mRadius, mWidth / 2 + mRadius, cirCenY + mRadius),
                    180, 360, true, mBallPaint);
            if (getPopRatio() < 1) {
                drawTail(canvas, cirCenY, cirCentStart + 1, getPopRatio());
            } else {
                canvas.drawCircle(mWidth / 2, cirCenY, mRadius, mBallPaint);
            }
        }
        private void drawTail(Canvas canvas, int centerY, int bottom, float fraction) {
            int bezier1w = (int) (mWidth / 2 + (mRadius * 3 / 4) * (1 - fraction));
            PointF start = new PointF(mWidth / 2 + mRadius, centerY);
            PointF bezier1 = new PointF(bezier1w, bottom);
            PointF bezier2 = new PointF(bezier1w + mRadius / 2, bottom);
            mPath.reset();
            mPath.moveTo(start.x, start.y);
            mPath.quadTo(bezier1.x, bezier1.y,
                    bezier2.x, bezier2.y);
            mPath.lineTo(mWidth - bezier2.x, bezier2.y);
            mPath.quadTo(mWidth - bezier1.x, bezier1.y,
                    mWidth - start.x, start.y);
            canvas.drawPath(mPath, mBallPaint);
        }
        private void drawOutCir(Canvas canvas) {
            mPath.reset();
            mPath.moveTo(0, 0);
            mPath.lineTo(0, PULL_HEIGHT);
            mPath.quadTo(mWidth / 2, PULL_HEIGHT - (1 - getOutRatio()) * PULL_DELTA,
                    mWidth, PULL_HEIGHT);
            mPath.lineTo(mWidth, 0);
            canvas.drawPath(mPath, mBackPaint);
            int innerY = PULL_HEIGHT - PULL_DELTA / 2 - mRadius * 2;
            canvas.drawCircle(mWidth / 2, innerY, mRadius, mBallPaint);
        }
        private int mRefreshStart = 90;
        private int mRefreshStop = 90;
        private int TARGET_DEGREE = 270;
        private boolean mIsStart = true;
        private boolean mIsRefreshing = true;
        private void drawRefreshing(Canvas canvas) {
            canvas.drawRect(0, 0, mWidth, mHeight, mBackPaint);
            int innerY = PULL_HEIGHT - PULL_DELTA / 2 - mRadius * 2;
            canvas.drawCircle(mWidth / 2, innerY, mRadius, mBallPaint);
            int outerR = mRadius + 10;
            mRefreshStart += mIsStart ? 3 : 10;
            mRefreshStop += mIsStart ? 10 : 3;
            mRefreshStart = mRefreshStart % 360;
            mRefreshStop = mRefreshStop % 360;
            int swipe = mRefreshStop - mRefreshStart;
            swipe = swipe < 0 ? swipe + 360 : swipe;
            canvas.drawArc(new RectF(mWidth / 2 - outerR, innerY - outerR, mWidth / 2 + outerR, innerY + outerR),
                    mRefreshStart, swipe, false, mOutPaint);
            if (swipe >= TARGET_DEGREE) {
                mIsStart = false;
            } else if (swipe <= 10) {
                mIsStart = true;
            }
            if (!mIsRefreshing) {
                applyDone();
    
            }
        }
        // stop refreshing
        public void setRefreshing(boolean isFresh) {
            mIsRefreshing = isFresh;
        }
        private void drawDone(Canvas canvas) {
            int beforeColor = mOutPaint.getColor();
            if (getDoneRatio() < 0.3) {
                canvas.drawRect(0, 0, mWidth, mHeight, mBackPaint);
                int innerY = PULL_HEIGHT - PULL_DELTA / 2 - mRadius * 2;
                canvas.drawCircle(mWidth / 2, innerY, mRadius, mBallPaint);
                int outerR = (int) (mRadius + 10 + 10 * getDoneRatio() / 0.3f);
                int afterColor = Color.argb((int) (0xff * (1 - getDoneRatio() / 0.3f)), Color.red(beforeColor),
                        Color.green(beforeColor), Color.blue(beforeColor));
                mOutPaint.setColor(afterColor);
                canvas.drawArc(new RectF(mWidth / 2 - outerR, innerY - outerR, mWidth / 2 + outerR, innerY + outerR),
                        0, 360, false, mOutPaint);
            }
            mOutPaint.setColor(beforeColor);
            if (getDoneRatio() >= 0.3 && getDoneRatio() < 0.7) {
                canvas.drawRect(0, 0, mWidth, mHeight, mBackPaint);
                float fraction = (getDoneRatio() - 0.3f) / 0.4f;
                int startCentY = PULL_HEIGHT - PULL_DELTA / 2 - mRadius * 2;
                int curCentY = (int) (startCentY + (PULL_DELTA / 2 + mRadius * 2) * fraction);
                canvas.drawCircle(mWidth / 2, curCentY, mRadius, mBallPaint);
                if (curCentY >= PULL_HEIGHT - mRadius * 2) {
                    drawTail(canvas, curCentY, PULL_HEIGHT, (1 - fraction));
                }
            }
            if (getDoneRatio() >= 0.7 && getDoneRatio() <= 1) {
                float fraction = (getDoneRatio() - 0.7f) / 0.3f;
                canvas.drawRect(0, 0, mWidth, mHeight, mBackPaint);
                int leftX = (int) (mWidth / 2 - mRadius - 2 * mRadius * fraction);
                mPath.reset();
                mPath.moveTo(leftX, PULL_HEIGHT);
                mPath.quadTo(mWidth / 2, PULL_HEIGHT - (mRadius * (1 - fraction)),
                        mWidth - leftX, PULL_HEIGHT);
                canvas.drawPath(mPath, mBallPaint);
            }
        }
        private int mLastHeight;
        private int getRelHeight() {
            return (int) (mSpriDeta * (1 - getRelRatio()));
        }
        private int getSpringDelta() {
            return (int) (PULL_DELTA * getSprRatio());
        }
        private static long REL_DRAG_DUR = 200;
        private long mStart;
        private long mStop;
        private int mSpriDeta;
        public void releaseDrag() {
            mStart = System.currentTimeMillis();
            mStop = mStart + REL_DRAG_DUR;
            mAniStatus = AnimatorStatus.REL_DRAG;
            mSpriDeta = mHeight - PULL_HEIGHT;
            requestLayout();
        }
        private float getRelRatio() {
            if (System.currentTimeMillis() >= mStop) {
                springUp();
                return 1;
            }
            float ratio = (System.currentTimeMillis() - mStart) / (float) REL_DRAG_DUR;
            return Math.min(ratio, 1);
        }
        private static long SPRING_DUR = 200;
        private long mSprStart;
        private long mSprStop;
        private void springUp() {
            mSprStart = System.currentTimeMillis();
            mSprStop = mSprStart + SPRING_DUR;
            mAniStatus = AnimatorStatus.SPRING_UP;
            invalidate();
        }
        private float getSprRatio() {
            if (System.currentTimeMillis() >= mSprStop) {
                popBall();
                return 1;
            }
            float ratio = (System.currentTimeMillis() - mSprStart) / (float) SPRING_DUR;
            return Math.min(1, ratio);
        }
        private static final long POP_BALL_DUR = 300;
        private long mPopStart;
        private long mPopStop;
        private void popBall() {
            mPopStart = System.currentTimeMillis();
            mPopStop = mPopStart + POP_BALL_DUR;
            mAniStatus = AnimatorStatus.POP_BALL;
            invalidate();
        }
        private float getPopRatio() {
            if (System.currentTimeMillis() >= mPopStop) {
                startOutCir();
                return 1;
            }
            float ratio = (System.currentTimeMillis() - mPopStart) / (float) POP_BALL_DUR;
            return Math.min(ratio, 1);
        }
        private static final long OUTER_DUR = 200;
        private long mOutStart;
        private long mOutStop;
        private void startOutCir() {
            mOutStart = System.currentTimeMillis();
            mOutStop = mOutStart + OUTER_DUR;
            mAniStatus = AnimatorStatus.OUTER_CIR;
            mRefreshStart = 90;
            mRefreshStop = 90;
            TARGET_DEGREE = 270;
            mIsStart = true;
            mIsRefreshing = true;
            invalidate();
        }
        private float getOutRatio() {
            if (System.currentTimeMillis() >= mOutStop) {
                mAniStatus = AnimatorStatus.REFRESHING;
                mIsRefreshing = true;
                return 1;
            }
            float ratio = (System.currentTimeMillis() - mOutStart) / (float) OUTER_DUR;
            return Math.min(ratio, 1);
        }
        private static final long DONE_DUR = 1000;
        private long mDoneStart;
        private long mDoneStop;
        private void applyDone() {
            mDoneStart = System.currentTimeMillis();
            mDoneStop = mDoneStart + DONE_DUR;
            mAniStatus = AnimatorStatus.DONE;
        }
        private float getDoneRatio() {
            if (System.currentTimeMillis() >= mDoneStop) {
                mAniStatus = AnimatorStatus.STOP;
                if (onViewAniDone != null) {
                    onViewAniDone.viewAniDone();
                }
                return 1;
            }
            float ratio = (System.currentTimeMillis() - mDoneStart) / (float) DONE_DUR;
            return Math.min(ratio, 1);
        }
        private OnViewAniDone onViewAniDone;
        public void setOnViewAniDone(OnViewAniDone onViewAniDone) {
            this.onViewAniDone = onViewAniDone;
        }
        interface OnViewAniDone {
            void viewAniDone();
        }
        public void setAniBackColor(int color) {
            mBackPaint.setColor(color);
        }
        public void setAniForeColor(int color) {
            mBallPaint.setColor(color);
            mOutPaint.setColor(color);
            setBackgroundColor(color);
        }
    
        // the height of view is smallTimes times of circle radius
        public void setRadius(int smallTimes) {
            mRadius = mHeight / smallTimes;
        }
    }
    import android.animation.ValueAnimator;
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.support.annotation.NonNull;
    import android.support.v4.view.ViewCompat;
    import android.util.AttributeSet;
    import android.util.TypedValue;
    import android.view.Gravity;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.animation.DecelerateInterpolator;
    import android.widget.FrameLayout;
    
    /**
     * Created by perry on 15/7/20.
     */
    public class CircleRefreshLayout extends FrameLayout {
        private static String TAG = "pullToRefresh";
        private static final long BACK_TOP_DUR = 600;
        private static final long REL_DRAG_DUR = 200;
        private int mHeaderBackColor = 0xff8b90af;
        private int mHeaderForeColor = 0xffffffff;
        private int mHeaderCircleSmaller = 6;
        private float mPullHeight;
        private float mHeaderHeight;
        private View mChildView;
        private AnimationView mHeader;
        private boolean mIsRefreshing;
        private float mTouchStartY;
        private float mTouchCurY;
        private ValueAnimator mUpBackAnimator;
        private ValueAnimator mUpTopAnimator;
        private DecelerateInterpolator decelerateInterpolator = new DecelerateInterpolator(10);
        public CircleRefreshLayout(Context context) {
            this(context, null, 0);
        }
        public CircleRefreshLayout(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
        public CircleRefreshLayout(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init(context, attrs, defStyleAttr);
        }
        private void init(Context context, AttributeSet attrs, int defStyleAttr) {
            if (getChildCount() > 1) {
                throw new RuntimeException("you can only attach one child");
            }
            setAttrs(attrs);
            mPullHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 150, context.getResources().getDisplayMetrics());
            mHeaderHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100, context.getResources().getDisplayMetrics());
            this.post(new Runnable() {
                @Override
                public void run() {
                    mChildView = getChildAt(0);
                    addHeaderView();
                }
            });
        }
        private void setAttrs(AttributeSet attrs) {
            TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.CirCleRefreshLayout);
            mHeaderBackColor = a.getColor(R.styleable.CirCleRefreshLayout_AniBackColor, mHeaderBackColor);
            mHeaderForeColor = a.getColor(R.styleable.CirCleRefreshLayout_AniForeColor, mHeaderForeColor);
            mHeaderCircleSmaller = a.getInt(R.styleable.CirCleRefreshLayout_CircleSmaller, mHeaderCircleSmaller);
            a.recycle();
        }
        private void addHeaderView() {
            mHeader = new AnimationView(getContext());
            LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0);
            params.gravity = Gravity.TOP;
            mHeader.setLayoutParams(params);
            addViewInternal(mHeader);
            mHeader.setAniBackColor(mHeaderBackColor);
            mHeader.setAniForeColor(mHeaderForeColor);
            mHeader.setRadius(mHeaderCircleSmaller);
            setUpChildAnimation();
        }
        private void setUpChildAnimation() {
            if (mChildView == null) {
                return;
            }
            mUpBackAnimator = ValueAnimator.ofFloat(mPullHeight, mHeaderHeight);
            mUpBackAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float val = (float) animation.getAnimatedValue();
                    if (mChildView != null) {
                        mChildView.setTranslationY(val);
                    }
                }
            });
            mUpBackAnimator.setDuration(REL_DRAG_DUR);
            mUpTopAnimator = ValueAnimator.ofFloat(mHeaderHeight, 0);
            mUpTopAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float val = (float) animation.getAnimatedValue();
                    val = decelerateInterpolator.getInterpolation(val / mHeaderHeight) * val;
                    if (mChildView != null) {
                        mChildView.setTranslationY(val);
                    }
                    mHeader.getLayoutParams().height = (int) val;
                    mHeader.requestLayout();
                }
            });
            mUpTopAnimator.setDuration(BACK_TOP_DUR);
            mHeader.setOnViewAniDone(new AnimationView.OnViewAniDone() {
                @Override
                public void viewAniDone() {
    //                Log.i(TAG, "should invoke");
                    mUpTopAnimator.start();
                }
            });
        }
        private void addViewInternal(@NonNull View child) {
            super.addView(child);
        }
        @Override
        public void addView(View child) {
            if (getChildCount() >= 1) {
                throw new RuntimeException("you can only attach one child");
            }
            mChildView = child;
            super.addView(child);
            setUpChildAnimation();
        }
        private boolean canChildScrollUp() {
            if (mChildView == null) {
                return false;
            }
            return ViewCompat.canScrollVertically(mChildView, -1);
        }
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            if (mIsRefreshing) {
                return true;
            }
            switch (ev.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    mTouchStartY = ev.getY();
                    mTouchCurY = mTouchStartY;
                    break;
                case MotionEvent.ACTION_MOVE:
                    float curY = ev.getY();
                    float dy = curY - mTouchStartY;
                    if (dy > 0 && !canChildScrollUp()) {
                        return true;
                    }
            }
            return super.onInterceptTouchEvent(ev);
        }
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            if (mIsRefreshing) {
                return super.onTouchEvent(event);
            }
            switch (event.getAction()) {
                case MotionEvent.ACTION_MOVE:
                    mTouchCurY = event.getY();
                    float dy = mTouchCurY - mTouchStartY;
                    dy = Math.min(mPullHeight * 2, dy);
                    dy = Math.max(0, dy);
                    if (mChildView != null) {
                        float offsetY = decelerateInterpolator.getInterpolation(dy / 2 / mPullHeight) * dy / 2;
                        mChildView.setTranslationY(offsetY);
                        mHeader.getLayoutParams().height = (int) offsetY;
                        mHeader.requestLayout();
                    }
                    return true;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                    if (mChildView != null) {
                        if (mChildView.getTranslationY() >= mHeaderHeight) {
                            mUpBackAnimator.start();
                            mHeader.releaseDrag();
                            mIsRefreshing = true;
                            if (onCircleRefreshListener!=null) {
                                onCircleRefreshListener.refreshing();
                            }
                        } else {
                            float height = mChildView.getTranslationY();
                            ValueAnimator backTopAni = ValueAnimator.ofFloat(height, 0);
                            backTopAni.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                                @Override
                                public void onAnimationUpdate(ValueAnimator animation) {
                                    float val = (float) animation.getAnimatedValue();
                                    val = decelerateInterpolator.getInterpolation(val / mHeaderHeight) * val;
                                    if (mChildView != null) {
                                        mChildView.setTranslationY(val);
                                    }
                                    mHeader.getLayoutParams().height = (int) val;
                                    mHeader.requestLayout();
                                }
                            });
                            backTopAni.setDuration((long) (height * BACK_TOP_DUR / mHeaderHeight));
                            backTopAni.start();
                        }
                    }
                    return true;
                default:
                    return super.onTouchEvent(event);
            }
        }
        public void finishRefreshing() {
            if (onCircleRefreshListener != null) {
                onCircleRefreshListener.completeRefresh();
            }
            mIsRefreshing = false;
            mHeader.setRefreshing(false);
        }
        private OnCircleRefreshListener onCircleRefreshListener;
        public void setOnRefreshListener(OnCircleRefreshListener onCircleRefreshListener) {
            this.onCircleRefreshListener = onCircleRefreshListener;
        }
        public interface OnCircleRefreshListener {
            void completeRefresh();
            void refreshing();
        }
    }

    然后在xml布局中定义:

    <com.tuesda.walker.circlerefresh.CircleRefreshLayout
            android:id="@+id/refresh_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:AniBackColor="#ff0097cd">
    
            <ListView
                android:id="@+id/list"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="#ffffffff" />
    
        </com.tuesda.walker.circlerefresh.CircleRefreshLayout>

    然后在需要的地方调用:

    import android.os.Handler;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.widget.ArrayAdapter;
    import android.widget.ListView;
    import com.tuesda.walker.circlerefresh.CircleRefreshLayout;
    import java.util.ArrayList;
    import java.util.List;
    import butterknife.Bind;
    import butterknife.ButterKnife;
    
    public class MainActivity extends AppCompatActivity {
        
        @Bind(R.id.refresh_layout)
        CircleRefreshLayout refresh_layout;
        @Bind(R.id.listView)
        ListView listView;
        private List<String> list;
        private ArrayAdapter<String> adapter;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            ButterKnife.bind(this);
            init();
        }
    
        private void init() {
            list = new ArrayList<>();
            list.add("测试数据1");
            list.add("测试数据2");
            list.add("测试数据3");
            adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list);
            listView.setAdapter(adapter);
            adapter.notifyDataSetChanged();
            refresh_layout.setOnRefreshListener(new CircleRefreshLayout.OnCircleRefreshListener() {
                @Override
                public void completeRefresh() {
    
                }
    
                @Override
                public void refreshing() {
                    new Handler().postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            refresh_layout.finishRefreshing();
                        }
                    }, 3000);
                }
            });
        }
    }
    好了,此时可以看到我们的刷新效果如下:




    更多相关内容
  • 水滴效果的下拉刷新

    2018-12-11 10:06:46
    自定义组件实现listview的水滴效果的下拉刷新android组件特效
  • 作者north2016,源码PathRefresh,自定义控件之-高仿Path水滴下拉刷新
  • android 5.0之后效果是个加载圆圈,还可以接受了,现在很多应用都用这个 (5)这时又看到了 baoyongzhang/android-PullRefreshLayout ,This component like SwipeRefreshLayout, it is more beautiful than ...

    android 5.0之后效果是个加载圆圈,还可以接受了,现在很多应用都用这个

    (5)这时又看到了 baoyongzhang/android-PullRefreshLayout ,This component like SwipeRefreshLayout, it is more beautiful than SwipeRefreshLayout.就是比google的跟漂亮。呵呵!

    (6)同时,这里也要提下 liaohuqiu/android-Ultra-Pull-To-Refresh ,已经强大到什么控件都能适用刷新了,相信你也听过了

    (7)看过最有创意的下拉刷新FlyRefresh,一只飞机飞啊飞,然而并没有什么卵用……

    (8)material设计已经深入到开发者的心里,然后 我看到了A pull-down-to-refresh layout inspired by Lollipop overscrolled effects allan1st/JellyRefreshLayout ,我这个也是看人家的代码实现的,十分感谢,啊哈哈

    (9)最近看的下拉刷新也是挺奇怪的,就比如 recruit-lifestyle/BeerSwipeRefresh 啤酒下拉刷新和 recruit-lifestyle/WaveSwipeRefreshLayout 水滴下拉刷新…

    (10)这个是网友推荐的 SuperSwipeRefreshLayout ,顾名思义,是扩展自SwipeRefreshLayout。

    (11)这个是Yalantis公司开发的下拉刷新,其中它的很多东西动画这块,做的非常漂亮Yalantis/Phoenix

    Taurus又是飞机飞啊飞…

    (12) tuesda/CircleRefreshLayout 的下拉刷新,动画做的很不错,设计图来源

    https://dribbble.com/shots/1797373-Pull-Down-To-Refresh

    (13) BeautifulRefreshLayoutForFood

    看到一个很漂亮的美食下拉刷新 (来源地址) ,可惜技术水平菜菜的,只能模仿一下下,啊哈哈。。。源码下载地址download

    [图片上传失败…(image-ea20fa-1525245291742)]

    (14) BeautifulRefreshLayoutForNaruto

    闲着蛋疼,写了个血轮眼下拉刷新的,虽然火影漫画完结了,但是动画还在继续,真的是挂漫天飞。。。。

    (15) bingoogolapple/BGARefreshLayout-Android 多种下拉刷新效果、上拉加载更多、可配置自定义头部广告位…

    (16) BeautifulRefreshLayoutForGirl

    这是一个小清新的下拉刷新,纯代码绘制,无需任何图片,Recyclerview中item展示的妹子图来自 http://gank.io/

    设计图来源,当然我实现的效果做了一些修改,希望你喜欢,呵呵。。。源码下载地址download pull to refresh by Michael Lanning

    截图

    (17) BeautifulRefreshLayoutForRain


    这是一个下雨刷新,你没听错,确实一刷新就下雨,为什么会出现,只是我的好奇心而做的东西,见怪不怪了,呵呵。。。


    (18) Android-MaterialRefreshLayout 是我最近写的, it is more beautiful and powerful than SwipeRefreshLayout , 下拉刷新拥有侵入式,非侵入式,覆盖式,非覆盖式,自动刷新,上拉加载更多,自动加载等功能……

    (19) WaveRefreshForAndroid 这个是基于 Android-PullToRefresh 修改的而成的水波纹下拉刷新…可能作者主攻ios,所以ios的效果看起来好看点WaveRefresh…

    (20)WaterDropListView如果你用过ios的qq,那应该很熟悉这种刷新了,效果还是蛮不错的,就是不知道为什么android版本的qq不用,呵呵。。。

    《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

    开源分享完整内容戳这里

    (21) SwipeRefreshRecyclerView 一个展示 RecyclerView 下拉刷新和上拉加载更多的 Demo 完全使用原生控件实现非侵入式的下拉刷新和加载更多。 同时也是 Ailurus 练习 RxJava 的小例子。 使用HeaderViewRecyclerAdapter完成了加载更多的进度展示

    (22)阿拉灯神灯写的两个下拉库 AutoHomeRefreshListView 仿汽车之家下拉刷新和 MeiTuanRefreshListView 仿美团下拉刷新。。。

    (23)XRecyclerViewa RecyclerView that implements pullrefresh and loadingmore featrues.you can use it like a standard RecyclerView

    (24) ChromeLikeSwipeLayout 这个效果蛮赞的,细节做的很好。。。。Pull down, and execute more action!

    (25)下拉玩消格子游戏HitBlockRefresh, 一边下拉刷新,一边打砖块.

    温馨提示:如需RecyclerView加载更多,请参考:

    展开全文
  • 代码为仿IOS水滴版Listview的实例代码,有问题请博客留言:http://blog.csdn.net/seven2729/article/details/48544473
  • android 水滴动画版下拉刷新

    热门讨论 2015-09-14 10:31:11
    代码为博客的实例代码,有问题请博客留言:http://blog.csdn.net/seven2729/article/details/48435523
  • Android 酷炫水滴效果的下拉刷新 源码,效果非常不错。
  • Android几种强大的下拉刷新

    千次阅读 2019-02-07 13:08:09
    2. Android-PullToRefresh 3. ActionBar-PullToRefresh 4.SwipeRefreshLayoutDemo  5.android-PullRefreshLayout 6.android-Ultra-Pull-To-Refresh 7.FlyRefresh 8.JellyRefreshLayout ...

    目录

    1.PullToRefresh 

    2. Android-PullToRefresh

    3. ActionBar-PullToRefresh

    4.SwipeRefreshLayoutDemo 

    5.android-PullRefreshLayout

    6.android-Ultra-Pull-To-Refresh

    7.FlyRefresh

    8.JellyRefreshLayout

    9.BeerSwipeRefresh

    10.SuperSwipeRefreshLayout 

    11.https://github.com/Yalantis/Phoenix

    12.CircleRefreshLayout 

    13.BeautifulRefreshLayoutForFood

    14. BeautifulRefreshLayoutForNaruto

    15.bingoogolapple/BGARefreshLayout-Android 

    16.BeautifulRefreshLayoutForGirl

    17. BeautifulRefreshLayoutForRain

    18.Android-MaterialRefreshLayout 

    19. WaveRefreshForAndroid

    20.WaterDropListView

    21.SwipeRefreshRecyclerView 

    22.AutoHomeRefreshListView 

    23.XRecyclerViewa

    24.ChromeLikeSwipeLayout 


    转载:https://www.cnblogs.com/foxy/p/7825073.html

    1.PullToRefresh 

    在我刚学android的时候,用的是XListView,在github上搜索有 MarkMjw/PullToRefresh ,根据Maxwin的XListView改造而来,完善下拉刷新上拉加载更多的功能并实现自动刷新以及自动加载等功能, 并增加对ScrollView的支持。 原XListView参考链接: https://github.com/Maxwin-z/XListView-Android(听说原作者停

    止维护了)

     

    2. Android-PullToRefresh

    然后又学了 chrisbanes/Android-PullToRefresh 的那个库,这个库牛逼到要死,支持ListView、ExpandableListView、GridView、WebView、ScrollView、HorizontalScrollView、ViewPager、ListFragment、、、

     

     

    自己也侮辱了这个库,改的乱七八糟 https://github.com/android-cjj/ComicReader/tree/master/YinHunPulltoRefreshLibrary,增加了支持瀑布流刷新的功能和下拉动画效果的。。。。

     

    3. ActionBar-PullToRefresh

    那时候看了知乎的客户端,下拉刷新很炫,查了下是用什么实现的,最终知道是用 chrisbanes/ActionBar-PullToRefresh 的库可以实现那种效果,又去学了,啊哈哈,然而过些日子也没见人用了,啊哈哈哈

     

     

    4.SwipeRefreshLayoutDemo 

    这时候google也有自己的下拉控件SwipeRefreshLayout,刚出来的效果,一条加载直线,个人觉得,一般到要死。 stormzhang/SwipeRefreshLayoutDemo 写了demo。

     

     

    android 5.0之后效果是个加载圆圈,还可以接受了,现在很多应用都用这个

     

     

    5.android-PullRefreshLayout

    这时又看到了 baoyongzhang/android-PullRefreshLayout ,This component like SwipeRefreshLayout, it is more beautiful than SwipeRefreshLayout.就是比google的跟漂亮。呵呵!

     

     

    6.android-Ultra-Pull-To-Refresh

    同时,这里也要提下 liaohuqiu/android-Ultra-Pull-To-Refresh ,已经强大到什么控件都能适用刷新了,相信你也听过了

    7.FlyRefresh

    看过最有创意的下拉刷新FlyRefresh,一只飞机飞啊飞,然而并没有什么卵用…..

     

    8.JellyRefreshLayout

    material设计已经深入到开发者的心里,然后 我看到了A pull-down-to-refresh layout inspired by Lollipop overscrolled effects allan1st/JellyRefreshLayout ,我这个也是看人家的代码实现的,十分感谢,啊哈哈

     

    9.BeerSwipeRefresh

    最近看的下拉刷新也是挺奇怪的,就比如 recruit-lifestyle/BeerSwipeRefresh 啤酒下拉刷新和 recruit-lifestyle/WaveSwipeRefreshLayout 水滴下拉刷新…

     

     

    10.SuperSwipeRefreshLayout 

    这个是网友推荐的 SuperSwipeRefreshLayout ,顾名思义,是扩展自SwipeRefreshLayout。

    11.https://github.com/Yalantis/Phoenix

    (11)这个是Yalantis公司开发的下拉刷新,其中它的很多东西动画这块,做的非常漂亮Yalantis/Phoenix

     

    Taurus又是飞机飞啊飞…

     

     

    12.CircleRefreshLayout 

    tuesda/CircleRefreshLayout 的下拉刷新,动画做的很不错,设计图来源 https://dribbble.com/shots/1797373-Pull-Down-To-Refresh

     

     

    13.BeautifulRefreshLayoutForFood

    看到一个很漂亮的美食下拉刷新 (来源地址) ,可惜技术水平菜菜的,只能模仿一下下,啊哈哈。。。源码下载地址download

     

     

    14. BeautifulRefreshLayoutForNaruto

    闲着蛋疼,写了个血轮眼下拉刷新的,虽然火影漫画完结了,但是动画还在继续,真的是挂漫天飞。。。。 

     

    15.bingoogolapple/BGARefreshLayout-Android 

    bingoogolapple/BGARefreshLayout-Android 多种下拉刷新效果、上拉加载更多、可配置自定义头部广告位…

     

     

    16.BeautifulRefreshLayoutForGirl

    这是一个小清新的下拉刷新,纯代码绘制,无需任何图片,Recyclerview中item展示的妹子图来自 http://gank.io/

    设计图来源,当然我实现的效果做了一些修改,希望你喜欢,呵呵。。。源码下载地址download pull to refresh by Michael Lanning

    截图

     

     

    17. BeautifulRefreshLayoutForRain

    这是一个下雨刷新,你没听错,确实一刷新就下雨,为什么会出现,只是我的好奇心而做的东西,见怪不怪了,呵呵。。。

    18.Android-MaterialRefreshLayout 

     Android-MaterialRefreshLayout 是我最近写的, it is more beautiful and powerful than SwipeRefreshLayout , 下拉刷新拥有侵入式,非侵入式,覆盖式,非覆盖式,自动刷新,上拉加载更多,自动加载等功能……

     

    19. WaveRefreshForAndroid

    WaveRefreshForAndroid 这个是基于 Android-PullToRefresh 修改的而成的水波纹下拉刷新…可能作者主攻ios,所以ios的效果看起来好看点WaveRefresh…

     

     

    20.WaterDropListView

    WaterDropListView如果你用过ios的qq,那应该很熟悉这种刷新了,效果还是蛮不错的,就是不知道为什么android版本的qq不用,呵呵。。。

     

    21.SwipeRefreshRecyclerView 

    SwipeRefreshRecyclerView 一个展示 RecyclerView 下拉刷新和上拉加载更多的 Demo 完全使用原生控件实现非侵入式的下拉刷新和加载更多。 同时也是 Ailurus 练习 RxJava 的小例子。 使用HeaderViewRecyclerAdapter完成了加载更多的进度展示

    22.AutoHomeRefreshListView 

    阿拉灯神灯写的两个下拉库 AutoHomeRefreshListView 仿汽车之家下拉刷新和 MeiTuanRefreshListView 仿美团下拉刷新。。。

     

     

     

    23.XRecyclerViewa

    XRecyclerViewa RecyclerView that implements pullrefresh and loadingmore featrues.you can use it like a standard RecyclerView

     

    24.ChromeLikeSwipeLayout 

     ChromeLikeSwipeLayout 这个效果蛮赞的,细节做的很好。。。。Pull down, and execute more action!

     

    (25)下拉玩消格子游戏HitBlockRefresh, 一边下拉刷新,一边打砖块.

     

    展开全文
  • listview 下拉刷新的时候 一滴水滴滴入屏幕中央 开始转圈刷新
  • 众多优秀的下拉刷新(除了我写的之外T_T) 说起下拉刷新,好像经历一段历史的洗礼。。。 (1)在我刚学android的时候,用的是XListView,在github上搜索有 MarkMjw/PullToRefresh ,根据Maxwin的XListView...

    众多优秀的下拉刷新(除了我写的之外T_T)


    说起下拉刷新,好像经历一段历史的洗礼。。。

    (1)在我刚学android的时候,用的是XListView,在github上搜索有 MarkMjw/PullToRefresh ,根据Maxwin的XListView改造而来,完善下拉刷新上拉加载更多的功能并实现自动刷新以及自动加载等功能, 并增加对ScrollView的支持。 原XListView

    参考链接:

    https://github.com/Maxwin-z/XListView-Android(听说原作者停止维护了)

    (2)然后又学了 chrisbanes/Android-PullToRefresh 的那个库,这个库牛逼到要死,支持ListView、ExpandableListView、GridView、WebView、ScrollView、HorizontalScrollView、ViewPager、ListFragment、、、

    自己也侮辱了这个库,改的乱七八糟

    https://github.com/androidcjj/ComicReader/tree/master/YinHunPulltoRefreshLibrary ,增加了支持瀑布流刷新的功能和下拉动画效果的。。。。

    (3)那时候看了知乎的客户端,下拉刷新很炫,查了下是用什么实现的,最终知道是用 chrisbanes/ActionBar-PullToRefresh 的库可以实现那种效果,又去学了,啊哈哈,然而过些日子也没见人用了,啊哈哈哈

    (4)这时候google也有自己的下拉控件SwipeRefreshLayout,刚出来的效果,一条加载直线,个人觉得,一般到要死。 stormzhang/SwipeRefreshLayoutDemo 写了demo。

    android 5.0之后效果是个加载圆圈,还可以接受了,现在很多应用都用这个

    (5)这时又看到了 baoyongzhang/android-PullRefreshLayout ,This component like SwipeRefreshLayout, it is more beautiful than SwipeRefreshLayout.就是比google的跟漂亮。呵呵!

    (6)同时,这里也要提下 liaohuqiu/android-Ultra-Pull-To-Refresh ,已经强大到什么控件都能适用刷新了,相信你也听过了

    (7)看过最有创意的下拉刷新FlyRefresh,一只飞机飞啊飞,然而并没有什么卵用……

    (8)material设计已经深入到开发者的心里,然后 我看到了A pull-down-to-refresh layout inspired by Lollipop overscrolled effects allan1st/JellyRefreshLayout ,我这个也是看人家的代码实现的,十分感谢,啊哈哈

    (9)最近看的下拉刷新也是挺奇怪的,就比如 recruit-lifestyle/BeerSwipeRefresh 啤酒下拉刷新和 recruit-lifestyle/WaveSwipeRefreshLayout 水滴下拉刷新…

    (10)这个是网友推荐的 SuperSwipeRefreshLayout ,顾名思义,是扩展自SwipeRefreshLayout。

    (11)这个是Yalantis公司开发的下拉刷新,其中它的很多东西动画这块,做的非常漂亮Yalantis/Phoenix

    Taurus又是飞机飞啊飞…

    (12) tuesda/CircleRefreshLayout 的下拉刷新,动画做的很不错,设计图来源

    https://dribbble.com/shots/1797373-Pull-Down-To-Refresh

    (13) BeautifulRefreshLayoutForFood

    看到一个很漂亮的美食下拉刷新 (来源地址) ,可惜技术水平菜菜的,只能模仿一下下,啊哈哈。。。源码下载地址download

    [图片上传失败…(image-ea20fa-1525245291742)]

    (14) BeautifulRefreshLayoutForNaruto

    闲着蛋疼,写了个血轮眼下拉刷新的,虽然火影漫画完结了,但是动画还在继续,真的是挂漫天飞。。。。

    《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

    【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享

    (15) bingoogolapple/BGARefreshLayout-Android 多种下拉刷新效果、上拉加载更多、可配置自定义头部广告位…

    (16) BeautifulRefreshLayoutForGirl

    这是一个小清新的下拉刷新,纯代码绘制,无需任何图片,Recyclerview中item展示的妹子图来自 http://gank.io/

    设计图来源,当然我实现的效果做了一些修改,希望你喜欢,呵呵。。。源码下载地址download pull to refresh by Michael Lanning

    截图

    (17) BeautifulRefreshLayoutForRain

    展开全文
  • WaveSwipeRefreshLayout水滴状的下拉刷新效果.rar,太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行参考学习。
  • Android之下拉刷新下拉加载 我的是AndroidX,其他的没测过 我这个按钮是额外加的,请忽略 最近才发现,还有好多好看的header(本条可忽略) 把上面那个header换成下面的更好玩 ...
  •  //第一步 导入依赖   implementation 'com.github.recruit-lifestyle:WaveSwipeRefreshLayout:1.6' ...jp.co.recruit_lifestyle.android.widget.WaveSwipeRefreshLayout android:layout_...
  • Android水滴落下的下拉刷新

    千次阅读 2016-08-16 16:40:31
    Android水滴落下的下拉刷新 非常逼真的水滴落下的下拉刷新。你可以配合ListView一起使用。 项目library下载地址:源码下载地址 我的demo下载地址(包含异步):水滴落下下拉刷新demo 效果图:
  • Android 超炫水滴效果的下拉刷新 源码,移植eclipse和android studio 都很简单,配置一下就可以
  • 下拉刷新的实现效果https://www.cnblogs.com/foxy/p/7825073.html 我是选了水滴的github项目 https://github.com/THEONE10211024/WaterDropListView,先是看了这里https://blog.csdn.net/z...
  • 一个 Android 下拉刷新和上拉加载的库基于官方SwipeRefreshLayout修改,并添加上拉功能,可自定义头部和尾部目前只支持 RecyclerView(LinearLayoutManager-VERTICAL 模式)使用方法:项目根目录的 build.gradle 添加...
  • 仿ios水滴下拉刷新,上拉加载更多,效果非常好,集成非常简单,下载直接用AS打开即可。
  • 基于XListView的基础上,把它的头部刷新换成自己定义的控件,这与IOS版上的QQ刷新类似。效果如下: 水滴效果可以看我的上一篇博客 水滴效果实现一、代码由于这是基于XListView 的,所以大部分代码就不贴了,只是把...
  • SmartRefreshLayout下载地址...SmartRefreshLayout是一个“聪明”或者说“智能”的下拉刷新布局,由于它的“智能”,它不只是如其它的刷新布局所说的支持所有的View,还支持多层嵌套的视图结构。 除了“聪明”之外,Sma
  • SmartRefreshLayout智能下拉刷新框架

    千次阅读 2019-06-27 17:17:57
    前面写了一个自定义的RecyclerView适配器,实现RecyclerView的下拉刷新有两种方式. 1、重写RecyclerView.Adapter的 getItemViewType(int position)方法,根据不同位置返回不同类型即可。可以利用这个特性把第0个位置...
  • 一个下拉刷新的实现,水滴效果。 activity_main.xml xmlns:app="http://schemas.android.com/apk/res-auto" app:AniBackColor="#e8eae9" app:AniForeCol
  • 几种下拉刷新

    2019-12-17 11:37:18
    1、 chrisbanes/Android-PullToRefresh 地址 支持ListView、ExpandableListView、GridView、WebView、ScrollView、HorizontalScrollView、ViewPager、ListFragment、、、 2、 chrisbanes/ActionBar-PullToRefresh ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 856
精华内容 342
关键字:

下拉刷新水滴android