日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

android自定义圆圈动画,自定义view实现动画数字圆圈

發布時間:2024/9/27 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android自定义圆圈动画,自定义view实现动画数字圆圈 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

我們要實現的是如下的效果,

1.該view在設置屬性之后時候會有數字和圓圈不斷增長的效果

2.該view在按下和放開狀態下顯示不同的樣式。

這種效果邏輯上并不復雜,底層灰色圓圈和藍色扇形圓圈都是用canvas.drawArc()繪制出來的,中間的數字用drawtext繪制,數字不斷增長的效果用了繼承Animation的動畫類;在按下和放開狀態下顯示不同的樣式是重寫了View 的setPressed()方法。

先貼出所有代碼,再一一解釋import com.jcodecraeer.util.MyUtils;

import android.content.Context;

import android.content.res.TypedArray;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.Path;

import android.graphics.Rect;

import android.graphics.RectF;

import android.graphics.Typeface;

import android.graphics.Paint.Align;

import android.graphics.Paint.Style;

import android.graphics.drawable.Drawable;

import android.util.AttributeSet;

import android.util.Log;

import android.view.View;

import android.view.animation.Animation;

import android.view.animation.Transformation;

public class CircleBar extends View {

private RectF mColorWheelRectangle = new RectF();

private Paint mDefaultWheelPaint;

private Paint mColorWheelPaint;

private Paint textPaint;

private float mColorWheelRadius;

private float circleStrokeWidth;

private float pressExtraStrokeWidth;

private String mText;

private int mCount;

private float mSweepAnglePer;

private float mSweepAngle;

private int mTextSize;

BarAnimation anim;

public CircleBar(Context context) {

super(context);

init(null, 0);

}

public CircleBar(Context context, AttributeSet attrs) {

super(context, attrs);

init(attrs, 0);

}

public CircleBar(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

init(attrs, defStyle);

}

private void init(AttributeSet attrs, int defStyle) {

circleStrokeWidth = MyUtils.dip2px(getContext(), 10);

pressExtraStrokeWidth = MyUtils.dip2px(getContext(), 2);

mTextSize = MyUtils.dip2px(getContext(), 40);

mColorWheelPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

mColorWheelPaint.setColor(0xFF29a6f6);

mColorWheelPaint.setStyle(Paint.Style.STROKE);

mColorWheelPaint.setStrokeWidth(circleStrokeWidth);

mDefaultWheelPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

mDefaultWheelPaint.setColor(0xFFeeefef);

mDefaultWheelPaint.setStyle(Paint.Style.STROKE);

mDefaultWheelPaint.setStrokeWidth(circleStrokeWidth);

textPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.LINEAR_TEXT_FLAG);

textPaint.setColor(0xFF333333);

textPaint.setStyle(Style.FILL_AND_STROKE);

textPaint.setTextAlign(Align.LEFT);

textPaint.setTextSize(mTextSize);

mText = "0";

mSweepAngle = 0;

anim = new BarAnimation();

anim.setDuration(2000);

}

@Override

protected void onDraw(Canvas canvas) {

canvas.drawArc(mColorWheelRectangle, -90, 360, false, mDefaultWheelPaint);

canvas.drawArc(mColorWheelRectangle, -90, mSweepAnglePer, false, mColorWheelPaint);

Rect bounds = new Rect();

String textstr=mCount+"";

textPaint.getTextBounds(textstr, 0, textstr.length(), bounds);

canvas.drawText(

textstr+"",

(mColorWheelRectangle.centerX())

- (textPaint.measureText(textstr) / 2),

mColorWheelRectangle.centerY() + bounds.height() / 2,

textPaint);

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int height = getDefaultSize(getSuggestedMinimumHeight(),

heightMeasureSpec);

int width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);

int min = Math.min(width, height);

setMeasuredDimension(min, min);

mColorWheelRadius = min - circleStrokeWidth -pressExtraStrokeWidth ;

mColorWheelRectangle.set(circleStrokeWidth+pressExtraStrokeWidth, circleStrokeWidth+pressExtraStrokeWidth,

mColorWheelRadius, mColorWheelRadius);

}

@Override

public void setPressed(boolean pressed) {

Log.i(TAG,"call setPressed ");

if (pressed) {

mColorWheelPaint.setColor(0xFF165da6);

textPaint.setColor(0xFF070707);

mColorWheelPaint.setStrokeWidth(circleStrokeWidth+pressExtraStrokeWidth);

mDefaultWheelPaint.setStrokeWidth(circleStrokeWidth+pressExtraStrokeWidth);

textPaint.setTextSize(mTextSize-pressExtraStrokeWidth);

} else {

mColorWheelPaint.setColor(0xFF29a6f6);

textPaint.setColor(0xFF333333);

mColorWheelPaint.setStrokeWidth(circleStrokeWidth);

mDefaultWheelPaint.setStrokeWidth(circleStrokeWidth);

textPaint.setTextSize(mTextSize);

}

super.setPressed(pressed);

this.invalidate();

}

public void startCustomAnimation(){

this.startAnimation(anim);

}

public void setText(String text){

mText = text;

this.startAnimation(anim);

}

public void setSweepAngle(float sweepAngle){

mSweepAngle = sweepAngle;

}

public class BarAnimation extends Animation {

/**

* Initializes expand collapse animation, has two types, collapse (1) and expand (0).

* @param view The view to animate

* @param type The type of animation: 0 will expand from gone and 0 size to visible and layout size defined in xml.

* 1 will collapse view and set to gone

*/

public BarAnimation() {

}

@Override

protected void applyTransformation(float interpolatedTime, Transformation t) {

super.applyTransformation(interpolatedTime, t);

if (interpolatedTime < 1.0f) {

mSweepAnglePer = interpolatedTime * mSweepAngle;

mCount = (int)(interpolatedTime * Float.parseFloat(mText));

} else {

mSweepAnglePer = mSweepAngle;

mCount = Integer.parseInt(mText);

}

postInvalidate();

}

}

}

屬性變量及其說明

private RectF mColorWheelRectangle = new RectF();圓圈的矩形范圍

private Paint mDefaultWheelPaint; ?繪制底部灰色圓圈的畫筆

private Paint mColorWheelPaint; 繪制藍色扇形的畫筆

private Paint textPaint; 中間文字的畫筆

private float mColorWheelRadius; 圓圈普通狀態下的半徑

private float circleStrokeWidth; 圓圈的線條粗細

private float pressExtraStrokeWidth;按下狀態下增加的圓圈線條增加的粗細

private String mText;中間文字內容

private int mCount; 為了達到數字增加效果而添加的變量,他和mText其實代表一個意思

private float mSweepAnglePer; ?為了達到藍色扇形增加效果而添加的變量,他和mSweepAngle其實代表一個意思

private float mSweepAngle; 扇形弧度

private int mTextSize;文字顏色

BarAnimation anim;動畫類

構造方法調用之后,第一個調用的是init方法,在該方法中初始化了各種畫筆的顏色,風格等,字體大小和線條粗細則使用了我自己定義的工具函數dip2px(),這樣做的目的是在不同分辨率的手機上,相同數值的最終顯示效果差別不大,比如字體大小mTextSize的初始化:mTextSize = MyUtils.dip2px(getContext(), 40);

還定義了動畫對象以及動畫持續時間:anim = new BarAnimation();

anim.setDuration(2000);

其中BarAnimation為自定義的動畫類:public class BarAnimation extends Animation {

/**

* Initializes expand collapse animation, has two types, collapse (1) and expand (0).

* @param view The view to animate

* @param type The type of animation: 0 will expand from gone and 0 size to visible and layout size defined in xml.

* 1 will collapse view and set to gone

*/

public BarAnimation() {

}

@Override

protected void applyTransformation(float interpolatedTime, Transformation t) {

super.applyTransformation(interpolatedTime, t);

if (interpolatedTime < 1.0f) {

mSweepAnglePer = interpolatedTime * mSweepAngle;

mCount = (int)(interpolatedTime * Float.parseFloat(mText));

} else {

mSweepAnglePer = mSweepAngle;

mCount = Integer.parseInt(mText);

}

postInvalidate();

}

}

這個動畫類利用了applyTransformation參數中的interpolatedTime參數(從0到1)的變化特點,實現了該View的某個屬性隨時間改變而改變。原理是在每次系統調用animation的applyTransformation()方法時,改變mSweepAnglePer,mCount的值,然后調用postInvalidate()不停的繪制view。if (interpolatedTime < 1.0f) {

mSweepAnglePer = interpolatedTime * mSweepAngle;

mCount = (int)(interpolatedTime * Float.parseFloat(mText));

}

mSweepAnglePer,mCount這兩個屬性只是動畫過程中要用到的臨時屬性,mText和mSweepAngle才是動畫結束之后表示扇形弧度和中間數值的真實值。

繪制方法

在onDraw方法中我們繪制了圓圈、扇形以及文字,但是繪制需要用到的一些坐標值是經過計算得出的,比如繪制扇形:canvas.drawArc(mColorWheelRectangle, -90, mSweepAnglePer, false, mColorWheelPaint);

mColorWheelRectangle是一個矩形,這個矩形的上下左右邊界都是在onMeasure方法中根據控件所分配的大小得出來的。

具體計算方式在onMeasure的實現中:@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int height = getDefaultSize(getSuggestedMinimumHeight(),

heightMeasureSpec);

int width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);

int min = Math.min(width, height);

setMeasuredDimension(min, min);

mColorWheelRadius = min - circleStrokeWidth -pressExtraStrokeWidth ;

mColorWheelRectangle.set(circleStrokeWidth+pressExtraStrokeWidth, circleStrokeWidth+pressExtraStrokeWidth,

mColorWheelRadius, mColorWheelRadius);

}

從setMeasuredDimension(min, min)可以看出我們強制該View為正方形。上面說到的mColorWheelRectangle矩形區域比控件的實際邊界要小,這樣做的目的是在按下狀態下狀態下讓圓圈的線條變大之后也并不會超出矩形區域。

按下松開view樣式改變的實現

改變樣式很簡單,只需改變畫筆的樣式就可以了,關鍵是在什么地方改變。我們都知道設置背景成selector就能是按下松開狀態下背景改變,但是直接設背景不滿足這里的要求,因為這是個圓圈,如果設置背景那肯定不會緊貼著圓圈邊緣,但是我們可以在不同狀態下更改畫筆然后重繪達到相同的效果。如何檢測到按下與松開呢?

看了view的源碼知道setPressed()方法可以滿足我們的要求:

@Override

public void setPressed(boolean pressed) {

Log.i(TAG,"call setPressed ");

if (pressed) {

mColorWheelPaint.setColor(0xFF165da6);

textPaint.setColor(0xFF070707);

mColorWheelPaint.setStrokeWidth(circleStrokeWidth+pressExtraStrokeWidth);

mDefaultWheelPaint.setStrokeWidth(circleStrokeWidth+pressExtraStrokeWidth);

textPaint.setTextSize(mTextSize-pressExtraStrokeWidth);

} else {

mColorWheelPaint.setColor(0xFF29a6f6);

textPaint.setColor(0xFF333333);

mColorWheelPaint.setStrokeWidth(circleStrokeWidth);

mDefaultWheelPaint.setStrokeWidth(circleStrokeWidth);

textPaint.setTextSize(mTextSize);

}

super.setPressed(pressed);

this.invalidate();

}

每次按下或者松開setPressed都會被調用,我們重寫該方法,但要注意調用super.setPress()不然長按放開之后boolean pressed參數仍然為true,這樣松開之后樣式就保持按下的狀態。具體原因還需要多閱讀view的源碼。

總結

其實這里最主要的是要有耐心了解canvas的一些方法,還有就是要根據自己的需求有針對性的分析view的源碼。

總結

以上是生活随笔為你收集整理的android自定义圆圈动画,自定义view实现动画数字圆圈的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。