還是老規(guī)矩先看看動畫效果
car.gif
分析狀態(tài)值及邏輯事件:0荸百、初始狀態(tài)1茂契、點擊實現(xiàn)旋轉(zhuǎn)動畫 2载慈、長按倒計時動畫(類似于uber取消訂單的效果)
實現(xiàn)步驟
1、來分析下我們自定義view需要的屬性
1褒纲、內(nèi)圓的半徑round_radius
2、外圓環(huán)的寬度ring_width
3钥飞、內(nèi)圓與外圓環(huán)之間的間距space_inner_out
4莺掠、未點擊時剛開始的狀態(tài)下的顏色start_round_color(我們這個動畫其實只用到了兩周顏色,所以就定為開始的顏色和過程中的顏色)
5读宙、點擊開始動畫的顏色centre_round_color
6彻秆、文字的大小text_size
7、文字的顏色text_color
2结闸、定義view的屬性唇兑,創(chuàng)建一個名字叫MyProgressView的類繼承自view,這里提前創(chuàng)建它桦锄,只是為了我們在創(chuàng)建attrs資源文件自定義view屬性的時方便命名
<resources>
<declare-styleable name="MyProgressView">
<attr name="space_inner_out" format="integer"/>
<attr name="round_radius" format="integer"/>
<attr name="ring_width" format="integer"/>
<attr name="text_size" format="integer"/>
<attr name="text_color" format="color"/>
<attr name="start_round_color" format="color"/>
<attr name="centre_round_color" format="color"/>
</declare-styleable>
</resources>
3扎附、我們就該來實現(xiàn)自定義view的功能了
首先獲取自定義屬性
private void init(Context context, AttributeSet attrs) {
//獲取自定義屬性值
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyProgressView);
screenWidth = ScreenUtils.getScreenWidth(context);
round_radius = a.getInt(R.styleable.MyProgressView_round_radius, screenWidth / 14);//默認(rèn)大小為屏幕寬度的6分之一
ring_width = a.getInt(R.styleable.MyProgressView_ring_width, 16);//默認(rèn)外圓的寬度為20
space_inner_out = a.getInt(R.styleable.MyProgressView_space_inner_out, 30);
//獲取文字的大小,默認(rèn)為30
text_size = a.getInt(R.styleable.MyProgressView_text_size, 30);
text_color = a.getColor(R.styleable.MyProgressView_text_color, Color.WHITE);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
start_round_color = a.getColor(R.styleable.MyProgressView_start_round_color,Color.BLUE);
centre_round_color = a.getColor(R.styleable.MyProgressView_centre_round_color,Color.RED);
calculate();
}
/**
* 計算
*/
public void calculate() {
//計算view的大小
viewSizw = round_radius * 2 + ring_width * 2 + space_inner_out * 2;
//獲取bitmap
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.yuanhuan);
progress_bitmap = Bitmap.createScaledBitmap(bitmap, viewSizw, viewSizw, true);
//繪制旋轉(zhuǎn)動畫用到的matrix
matrix = new Matrix();
}
添加一個設(shè)置stute的方法
/**
* 設(shè)置狀態(tài)值
* @param stute
*/
public void setStute(int stute) {
this.stute = stute;
if (stute == 1) {
if (animator_stute2 != null) {//當(dāng)前是stute=2向stute=1轉(zhuǎn)時结耀,結(jié)束上一個動畫
animator_stute2.cancel();
}
startAnimator();
} else if (stute == 2) {
if (animator_stute1 != null)//當(dāng)前是stute=1向stute=2轉(zhuǎn)時留夜,結(jié)束上一個動畫
animator_stute1.cancel();
startCountDown();
}
}
重寫on Measure()
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(viewSizw, viewSizw);//設(shè)置view的大小是上面計算的
//圓環(huán)的位置
ring_rect = new RectF(0+ring_width/2, 0+ring_width/2,getWidth()-ring_width/2,getHeight()-ring_width/2);
width = getWidth();
height = getHeight();
//圓心
cx = width / 2;
cy = height / 2;
}
繪制
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
switch (stute) {
case 0://開始
//繪制內(nèi)圓
mPaint.setColor(start_round_color);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawCircle(cx, cy, round_radius, mPaint);//繪制內(nèi)圓
//繪制外圓環(huán)
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(ring_width);
canvas.drawCircle(cx, cy, width / 2 - ring_width / 2, mPaint);
//繪制文字
mPaint.setStrokeWidth(0);
mPaint.setColor(text_color);
mPaint.setTextSize(text_size);
float v = mPaint.measureText(START_TEXT);
canvas.drawText(START_TEXT, width / 2 - v / 2, height / 2 + text_size / 2, mPaint);
break;
case 1:
//繪制內(nèi)圓
mPaint.setColor(centre_round_color);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawCircle(cx, cy, round_radius, mPaint);//繪制內(nèi)圓
//繪制文字
mPaint.setStrokeWidth(0);
mPaint.setColor(text_color);
mPaint.setTextSize(text_size);
float v1 = mPaint.measureText(CENTRE_TEXT);
canvas.drawText(CENTRE_TEXT, width / 2 - v1 / 2, height / 2 + text_size / 2, mPaint);
//繪制外圓環(huán)
canvas.drawBitmap(progress_bitmap, matrix, mPaint);
break;
case 2:
//繪制內(nèi)圓
mPaint.setColor(centre_round_color);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawCircle(cx, cy, round_radius, mPaint);//繪制內(nèi)圓
//繪制外圓環(huán)
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(ring_width);
canvas.drawArc(ring_rect, 270, index, false, mPaint);
//繪制文字
mPaint.setStrokeWidth(0);
mPaint.setColor(text_color);
mPaint.setTextSize(text_size);
float v2 = mPaint.measureText(CENTRE_TEXT);
canvas.drawText(CENTRE_TEXT, width / 2 - v2 / 2, height / 2 + text_size / 2, mPaint);
break;
}
}
還有兩個動畫的實現(xiàn)
/**
* 開啟動畫
*/
private void startAnimator() {
animator_stute1 = ValueAnimator.ofInt(360);
animator_stute1.setDuration(2000);
animator_stute1.setInterpolator(new LinearInterpolator());
animator_stute1.setRepeatCount(ValueAnimator.INFINITE);
animator_stute1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
//這里使用來實現(xiàn)旋轉(zhuǎn)動畫
matrix.postRotate(DEGREES, progress_bitmap.getWidth() / 2, progress_bitmap.getHeight() / 2);
postInvalidate();
}
});
animator_stute1.start();
}
/**
* 停止的動畫
*/
private void startCountDown() {
index=360;//將index設(shè)置為初始值
animator_stute2 = ValueAnimator.ofInt(360);
animator_stute2.setDuration(TIME_FOR_SOTP);
animator_stute2.setInterpolator(new LinearInterpolator());
animator_stute2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
index -= S;
if (index <= 0) {
stute = 0;//設(shè)置為初始狀態(tài)
index = 360;//將index設(shè)置為初始狀態(tài)
is_stop = true;//停止動畫結(jié)束
}
postInvalidate();
}
});
animator_stute2.start();
}
旋轉(zhuǎn)動畫實現(xiàn)的主要方法
matrix.postRotate(DEGREES, progress_bitmap.getWidth() / 2, progress_bitmap.getHeight() / 2);//這里這是旋轉(zhuǎn)的角度DEGREES,旋轉(zhuǎn)中心就是圖片的中心
這里就是繪制旋轉(zhuǎn)后的圖片
//繪制外圓環(huán) canvas.drawBitmap(progress_bitmap, matrix, mPaint);
在mainactivity中的使用
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final MyProgressView m = (MyProgressView) findViewById(R.id.mp);
m.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (m.getStute()==1){//如果當(dāng)前已經(jīng)是開始狀態(tài)图甜,則return
return;
}
m.setStute(1);
}
});
m.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
if (m.getStute()==1){//如果當(dāng)前是開始狀態(tài)才觸發(fā)停止動畫
m.setStute(2);
}
return false;
}
});
}
當(dāng)然還要重寫view的onTouchEvent()方法
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP && !is_stop && stute == 2) {
setStute(1);//沒有結(jié)束停止動畫碍粥,就返回出車動畫
index=360;
} else if (event.getAction() == MotionEvent.ACTION_UP && is_stop && stute == 0) {
is_stop = false;//當(dāng)前停止動畫已經(jīng)結(jié)束,則將is_stop設(shè)置為初始值
return true;
}
return super.onTouchEvent(event);
}
xml中的布局
<com.dituwuyou.myapplication.MyProgressView
android:id="@+id/mp"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:text_color="@android:color/white"
app:text_size="30"
app:space_inner_out="30"
app:round_radius="150"
app:ring_width="20"
app:centre_round_color="@color/color_ff4631"
app:start_round_color="@color/color_3F51B5"/>
接下來我貼出整個自定義view的代碼
/**
* Created by Laer on 2016/10/24.
*/
public class MyProgressView extends View {
private int space_inner_out;//外圓環(huán)和內(nèi)圓的間距(不提供大小設(shè)置黑毅,代碼計算)
private int round_radius;//內(nèi)圓的半徑
private int ring_width;//外圓環(huán)的寬度
private int text_size;//文字的大小
private int text_color;//文字的顏色
private int centre_round_color;//開始動畫的內(nèi)圓顏色值
private int start_round_color;//沒開始的內(nèi)圓顏色值
//常量
private static final String START_TEXT = "開始";
private static final String CENTRE_TEXT = "停止";
private static final int S = 3;//減少時的速率
private static final int DEGREES =2;//旋轉(zhuǎn)動畫的速率
private static final int TIME_FOR_SOTP = 3000;//長按停止出車的時間,這里默認(rèn)是3秒
//畫筆
private Paint mPaint;
private RectF ring_rect;
//標(biāo)識
private boolean is_stop;//是否停止出車
private boolean is_start_animotor;//是否開啟動畫
//
private int screenWidth;
private int viewSizw;//當(dāng)前view的大小
private Bitmap progress_bitmap;
private Matrix matrix;
private int index = 360;//當(dāng)前倒計時的進(jìn)度值
private int stute = 0;//當(dāng)前的狀態(tài)值
private ValueAnimator animator_stute1;
private ValueAnimator animator_stute2;
private int width;//當(dāng)前view的寬度
private int height;//當(dāng)前view的高度
private int cx;//圓心的x坐標(biāo)
private int cy;//圓心的y坐標(biāo)
public MyProgressView(Context context) {
super(context);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
}
public MyProgressView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
/**
* 獲取當(dāng)前狀態(tài)值
* @return
*/
public int getStute() {
return stute;
}
/**
* 設(shè)置狀態(tài)值
* @param stute
*/
public void setStute(int stute) {
this.stute = stute;
if (stute == 1) {
if (animator_stute2 != null) {//當(dāng)前是stute=2向stute=1轉(zhuǎn)時嚼摩,結(jié)束上一個動畫
animator_stute2.cancel();
}
startAnimator();
} else if (stute == 2) {
if (animator_stute1 != null)//當(dāng)前是stute=1向stute=2轉(zhuǎn)時,結(jié)束上一個動畫
animator_stute1.cancel();
startCountDown();
}
}
/**
* 開啟動畫
*/
private void startAnimator() {
animator_stute1 = ValueAnimator.ofInt(360);
animator_stute1.setDuration(2000);
animator_stute1.setInterpolator(new LinearInterpolator());
animator_stute1.setRepeatCount(ValueAnimator.INFINITE);
animator_stute1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
matrix.postRotate(DEGREES, progress_bitmap.getWidth() / 2, progress_bitmap.getHeight() / 2);
postInvalidate();
}
});
animator_stute1.start();
}
/**
* 停止的動畫
*/
private void startCountDown() {
index=360;//將index設(shè)置為初始值
animator_stute2 = ValueAnimator.ofInt(360);
animator_stute2.setDuration(TIME_FOR_SOTP);
animator_stute2.setInterpolator(new LinearInterpolator());
animator_stute2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
index -= S;
if (index <= 0) {
stute = 0;//設(shè)置為初始狀態(tài)
index = 360;//將index設(shè)置為初始狀態(tài)
is_stop = true;//停止動畫結(jié)束
}
postInvalidate();
}
});
animator_stute2.start();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP && !is_stop && stute == 2) {
setStute(1);//沒有結(jié)束停止動畫博肋,就返回出車動畫
index=360;
} else if (event.getAction() == MotionEvent.ACTION_UP && is_stop && stute == 0) {
is_stop = false;//當(dāng)前停止動畫已經(jīng)結(jié)束低斋,則將is_stop設(shè)置為初始值
return true;
}
return super.onTouchEvent(event);
}
private void init(Context context, AttributeSet attrs) {
//獲取自定義屬性值
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyProgressView);
screenWidth = ScreenUtils.getScreenWidth(context);
round_radius = a.getInt(R.styleable.MyProgressView_round_radius, screenWidth / 14);//默認(rèn)大小為屏幕寬度的6分之一
ring_width = a.getInt(R.styleable.MyProgressView_ring_width, 16);//默認(rèn)外圓的寬度為20
space_inner_out = a.getInt(R.styleable.MyProgressView_space_inner_out, 30);
//獲取文字的大小,默認(rèn)為30
text_size = a.getInt(R.styleable.MyProgressView_text_size, 30);
text_color = a.getColor(R.styleable.MyProgressView_text_color, Color.WHITE);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
start_round_color = a.getColor(R.styleable.MyProgressView_start_round_color,Color.BLUE);
centre_round_color = a.getColor(R.styleable.MyProgressView_centre_round_color,Color.RED);
calculate();
}
/**
* 計算
*/
public void calculate() {
//計算view的大小
viewSizw = round_radius * 2 + ring_width * 2 + space_inner_out * 2;
//獲取bitmap
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.yuanhuan);
progress_bitmap = Bitmap.createScaledBitmap(bitmap, viewSizw, viewSizw, true);
//繪制旋轉(zhuǎn)動畫用到的matrix
matrix = new Matrix();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(viewSizw, viewSizw);//設(shè)置view的大小是上面計算的
//圓環(huán)的位置
ring_rect = new RectF(0+ring_width/2, 0+ring_width/2,getWidth()-ring_width/2,getHeight()-ring_width/2);
width = getWidth();
height = getHeight();
//圓心
cx = width / 2;
cy = height / 2;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
switch (stute) {
case 0://開始
//繪制內(nèi)圓
mPaint.setColor(start_round_color);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawCircle(cx, cy, round_radius, mPaint);//繪制內(nèi)圓
//繪制外圓環(huán)
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(ring_width);
canvas.drawCircle(cx, cy, width / 2 - ring_width / 2, mPaint);
//繪制文字
mPaint.setStrokeWidth(0);
mPaint.setColor(text_color);
mPaint.setTextSize(text_size);
float v = mPaint.measureText(START_TEXT);
canvas.drawText(START_TEXT, width / 2 - v / 2, height / 2 + text_size / 2, mPaint);
break;
case 1:
//繪制內(nèi)圓
mPaint.setColor(centre_round_color);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawCircle(cx, cy, round_radius, mPaint);//繪制內(nèi)圓
//繪制文字
mPaint.setStrokeWidth(0);
mPaint.setColor(text_color);
mPaint.setTextSize(text_size);
float v1 = mPaint.measureText(CENTRE_TEXT);
canvas.drawText(CENTRE_TEXT, width / 2 - v1 / 2, height / 2 + text_size / 2, mPaint);
//繪制外圓環(huán)
canvas.drawBitmap(progress_bitmap, matrix, mPaint);
break;
case 2:
//繪制內(nèi)圓
mPaint.setColor(centre_round_color);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawCircle(cx, cy, round_radius, mPaint);//繪制內(nèi)圓
//繪制外圓環(huán)
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(ring_width);
canvas.drawArc(ring_rect, 270, index, false, mPaint);
//繪制文字
mPaint.setStrokeWidth(0);
mPaint.setColor(text_color);
mPaint.setTextSize(text_size);
float v2 = mPaint.measureText(CENTRE_TEXT);
canvas.drawText(CENTRE_TEXT, width / 2 - v2 / 2, height / 2 + text_size / 2, mPaint);
break;
}
}
}