Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 自定義View UC下拉刷新效果(一)

Android 自定義View UC下拉刷新效果(一)

編輯:關於Android編程

啦啦啦,今天給大家帶來最近弄的CircleProgress相關的效果。這裡的效果圖可能還看不出是UC浏覽器的那個下拉刷新的效果,不過首先還是要說說這個進度條,在下一篇中將實現真正的下拉刷新!
話不多說,直接上圖:

seo=" src="/uploadfile/Collfiles/20160809/201608090936031694.gif" title="\" />

特點:就是一個進度條

1、可以設置多種顏色。
2、可以顯示多種狀態(LOADING、SUCCESS、ERROR,其實遠不止這幾種)
3、可以控制是否顯示箭頭

相關准備工作

知識點:

1.Canvas裡面相關方法
2.drawArc()畫圓弧的方法
3.drawPath()畫路徑的方法
4.屬性動畫使用

結果的鉤鉤或者那個叉叉還有那個箭頭都是使用drawPath()來完成的。

在onDraw裡面對應有四個相關的方法:

1.drawArc(Canvas canvas):畫對應的進度
2.drawTriangle(Canvas c, float startAngle, float sweepAngle):畫箭頭
3.drawHook(Canvas canvas):畫鉤鉤
4.drawError(Canvas canvas):畫叉叉

三個動畫控制:

兩個來控制進度條的 startAngle和sweepAngle,一個用來控制畫鉤鉤或者畫叉叉的時候的漸變效果!

相關代碼

三支畫筆
    mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setStrokeCap(Cap.ROUND);
    mPaint.setStrokeWidth(mBorderWidth);
    mPaint.setColor(mColors[mCurrentColorIndex]);

    mHookPaint = new Paint(mPaint);
    mArrowPaint = new Paint(mPaint);
三個動畫
  private void setupAnimations() {
    mObjectAnimatorAngle = ObjectAnimator.ofFloat(this, mAngleProperty, 360f);
    mObjectAnimatorAngle.setInterpolator(ANGLE_INTERPOLATOR);
    mObjectAnimatorAngle.setDuration(ANGLE_ANIMATOR_DURATION);
    mObjectAnimatorAngle.setRepeatMode(ValueAnimator.RESTART);
    mObjectAnimatorAngle.setRepeatCount(ValueAnimator.INFINITE);

    mObjectAnimatorSweep = ObjectAnimator.ofFloat(this, mSweepProperty, 360f - MIN_SWEEP_ANGLE * 2);
    mObjectAnimatorSweep.setInterpolator(SWEEP_INTERPOLATOR);
    mObjectAnimatorSweep.setDuration(SWEEP_ANIMATOR_DURATION);
    mObjectAnimatorSweep.setRepeatMode(ValueAnimator.RESTART);
    mObjectAnimatorSweep.setRepeatCount(ValueAnimator.INFINITE);
    mObjectAnimatorSweep.addListener(new SimpleAnimatorListener() {
        @Override
        public void onAnimationRepeat(Animator animation) {
            toggleAppearingMode();
        }
    });
    fractionAnimator = ValueAnimator.ofInt(0, 255);
    fractionAnimator.setInterpolator(ANGLE_INTERPOLATOR);
    fractionAnimator.setDuration(100);
    fractionAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            fraction = animation.getAnimatedFraction();
            mHookPaint.setAlpha((Integer) animation.getAnimatedValue());
            invalidate();
        }
    });
}
四個draw相關方法
 private void drawError(Canvas canvas) {
    mError.reset();
    mError.moveTo(fBounds.centerX() + fBounds.width() * 0.2f * fraction, fBounds.centerY() - fBounds.height() * 0.2f * fraction);
    mError.lineTo(fBounds.centerX() - fBounds.width() * 0.2f * fraction, fBounds.centerY() + fBounds.height() * 0.2f * fraction);
    mError.moveTo(fBounds.centerX() - fBounds.width() * 0.2f * fraction, fBounds.centerY() - fBounds.height() * 0.2f * fraction);
    mError.lineTo(fBounds.centerX() + fBounds.width() * 0.2f * fraction, fBounds.centerY() + fBounds.height() * 0.2f * fraction);
    mHookPaint.setColor(mColors[3]);
    canvas.drawPath(mError, mHookPaint);
    canvas.drawArc(fBounds, 0, 360, false, mHookPaint);
}

private void drawHook(Canvas canvas) {
    mHook.reset();
    mHook.moveTo(fBounds.centerX() - fBounds.width() * 0.25f * fraction, fBounds.centerY());
    mHook.lineTo(fBounds.centerX() - fBounds.width() * 0.1f * fraction, fBounds.centerY() + fBounds.height() * 0.18f * fraction);
    mHook.lineTo(fBounds.centerX() + fBounds.width() * 0.25f * fraction, fBounds.centerY() - fBounds.height() * 0.20f * fraction);
    mHookPaint.setColor(mColors[0]);
    canvas.drawPath(mHook, mHookPaint);
    canvas.drawArc(fBounds, 0, 360, false, mHookPaint);

}

private void drawArc(Canvas canvas) {
    float startAngle = mCurrentGlobalAngle - mCurrentGlobalAngleOffset;
    float sweepAngle = mCurrentSweepAngle;
    if (mModeAppearing) {
        mPaint.setColor(gradient(mColors[mCurrentColorIndex], mColors[mNextColorIndex],
                mCurrentSweepAngle / (360 - MIN_SWEEP_ANGLE * 2)));
        sweepAngle += MIN_SWEEP_ANGLE;
    } else {
        startAngle = startAngle + sweepAngle;
        sweepAngle = 360 - sweepAngle - MIN_SWEEP_ANGLE;
    }
    canvas.drawArc(fBounds, startAngle, sweepAngle, false, mPaint);
    if (showArrow) {
        drawTriangle(canvas, startAngle, sweepAngle);
    }
}

public void drawTriangle(Canvas c, float startAngle, float sweepAngle) {
    if (mArrow == null) {
        mArrow = new Path();
        mArrow.setFillType(Path.FillType.EVEN_ODD);
    } else {
        mArrow.reset();
    }

    float x = (float) (mRingCenterRadius * Math.cos(0) + fBounds.centerX());
    float y = (float) (mRingCenterRadius * Math.sin(0) + fBounds.centerY());
    mArrow.moveTo(0, 0);
    mArrow.lineTo(ARROW_WIDTH * mArrowScale, 0);
    mArrow.lineTo((ARROW_WIDTH * mArrowScale / 2), (ARROW_HEIGHT
            * mArrowScale));
    mArrow.offset(x, y);
    mArrow.close();
    c.rotate(startAngle + sweepAngle, fBounds.centerX(),
            fBounds.centerY());
    c.drawPath(mArrow, mPaint);
}

上面的代碼就是相關核心的方法了,其實對應的進度條效果就是控制 startAngle和sweepAngle這兩個對應的字段,然後不斷的調用drawArc()方法。

對於畫鉤鉤或者畫叉叉,就是一個ValueAnimator,通過百分比控制縮放和畫筆的透明度。

對於drawTriangle()方法,如果你覺得很眼熟的話也很正常,其實這個就是在SwipeRefreshLayout裡面抄過來的。。。。。
一開始,我很糾結這個箭頭怎麼才能跟著進度條一起旋轉,自己寫的也是有各種問題,另外mArrowScale這個參數在裡面其實沒有使用的。
如果沒有offset偏移量,那麼那個path肯定是畫在左上角的。

x=mRingCenterRadius +fBounds.centerX();
y=fBounds.centerY();

通過這個一設置,這個path其實就到了右邊的中間靠著圓弧的內側一點去了(因為這裡的半徑減去了圓弧自己的寬度。。),這麼一來,再根據相關的角度旋轉角度,就有一種跟著進度條一直轉的效果了!

對於drawArc()方法,主要是控制startAngle和sweepAngle這兩個變量,mCurrentGlobalAngle的變化范圍是(0~360),而mCurrentSweepAngle的變化范圍是(0~360f - MIN_SWEEP_ANGLE * 2),為什麼要減去兩個最小值呢?因為sweepAngle總會加一個或者總會減去一個最小值,所以最小間距還是MIN_SWEEP_ANGLE。
至於什麼時候加什麼時候減呢?這裡有一個變量值mModeAppearing提供記錄!那就是當mObjectAnimatorSweep的動畫重復的時候,就需要切換一下了。。

 mObjectAnimatorSweep.addListener(new SimpleAnimatorListener() {
        @Override
        public void onAnimationRepeat(Animator animation) {
            toggleAppearingMode();
        }
    });
private void toggleAppearingMode() {
    mModeAppearing = !mModeAppearing;
    if (mModeAppearing) {
        mCurrentColorIndex = ++mCurrentColorIndex % 4;
        mNextColorIndex = ++mNextColorIndex % 4;
        mCurrentGlobalAngleOffset = (mCurrentGlobalAngleOffset + MIN_SWEEP_ANGLE * 2) % 360;
    }
}

最終效果圖

HeaderRefreshLayout

下一篇Android 自定義View UC下拉刷新效果(二)

介紹剩余的下拉刷新部分,還有就是兩個圓圈的過度效果。。

相關的代碼請移步 我的github。。。

— Edit By Joe —

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved