內(nèi)容簡概
一、畫線、圓、扇形
二、扇形動(dòng)畫
具體內(nèi)容
一、畫線、圓、扇形、圓弧
(一)創(chuàng)建一個(gè)類(繼承View)用于測試
在這個(gè)類中,我們放置線、圓、扇形、圓弧。
public class TestView extends View {
// 實(shí)現(xiàn)View的兩個(gè)方法
public TestView(Context context) {
super(context);
}
public TestView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
// 畫線
// 1. 準(zhǔn)備畫筆 抗鋸齒
Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setTextSize(70);
mPaint.setColor(Color.BLACK); // 設(shè)置畫筆顏色
mPaint.setStrokeWidth(20); // 設(shè)置畫筆粗細(xì)
// 2.在畫布上畫線
canvas.drawLine(50,50,300,400,mPaint);
// x,y為開頭文字左下角左標(biāo)
canvas.drawText("↑",200,600,mPaint);
canvas.drawText("drawLine",50,700,mPaint);
//3.畫圓
// 這里的top是圓心坐標(biāo),
canvas.drawArc(600,50,1000,450,0,300,true,mPaint);
canvas.drawText("↑",770,600,mPaint);
canvas.drawText("drawArc",650,700,mPaint);
// useCenter = false
canvas.drawArc(50,800,450,1200,0,300,false,mPaint);
canvas.drawText("↑",200,1300,mPaint);
canvas.drawText("drawArc",50,1400,mPaint);
canvas.drawText("useCenter=false",50,1500,mPaint);
// 畫圓的另一種方法
canvas.drawCircle(800,1000,200,mPaint);
canvas.drawText("↑",770,1300,mPaint);
canvas.drawText("drawCircle",650,1400,mPaint);
}
}
這里的圓是實(shí)心的,如果想要畫空心的圓或者圓弧怎么辦呢?只要多加一句mPaint.setStyle(Paint.Style.STROKE);就可以了,系統(tǒng)默認(rèn)的style為FILL(實(shí)心)。
(二) xml(使用RelativeLayout)
<com.example.test.TestView
android:layout_width="match_parent"
android:layout_height="match_parent"/>
(三)運(yùn)行結(jié)果圖
左邊為實(shí)心,右邊為空心??招木褪敲枥L外輪廓。(請(qǐng)忽略空心的丑陋文字)。
二、扇形動(dòng)畫
扇形動(dòng)畫是扇形的半徑不變,轉(zhuǎn)的角度在變。下面我用兩個(gè)類分別實(shí)現(xiàn)兩種動(dòng)畫,一種是點(diǎn)擊展開的扇形,一種是自動(dòng)展開的扇形。前者可以用onTouchEvent方法實(shí)現(xiàn),后者可以用Timer(定時(shí)器)或?qū)傩詣?dòng)畫實(shí)現(xiàn)。
(一)點(diǎn)擊展開的扇形
規(guī)定扇形完全展開后就固定為圓形,不再變化。
public class FanAnimation extends View {
int angle; //每次增長之后的值
int speed = 20; //增長速度
public FanAnimation(Context context) {
super(context);
}
public FanAnimation(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
@Override
protected void onDraw(Canvas canvas) {
drawFanChart(canvas,Color.BLACK, (float) (angle/360.0),"點(diǎn)擊展開的扇形");
}
// onDraw方法不能滿足需求,所以自己寫一個(gè)方法
private void drawFanChart(Canvas canvas,int color,float rate,String text){
//畫筆
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setTextSize(70);
paint.setColor(color);
//畫扇形
int endAngle = (int) (360*rate);// 新繪制的扇形endAngle都在增大
canvas.drawArc(50,100,450,500, 0,endAngle, true,paint);
canvas.drawText(text,550,300,paint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN){
// 點(diǎn)擊屏幕 畫一點(diǎn) 這里的angle就是上面的rate
angle += speed;
// 控制最大值
if (angle>360){
angle = 360;
}
// 刷新
invalidate();
}
return true;
}
}
(二)自動(dòng)展開的扇形——Timer
public class AutoFanAnimation extends View {
int angle; //每次增長之后的值
int speed = 5; //增長速度
public AutoFanAnimation(Context context) {
super(context);
}
public AutoFanAnimation(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// 創(chuàng)建定時(shí)器 每個(gè)0.5s 畫一次
final Timer t = new Timer();
t.schedule(new TimerTask() {
@Override
public void run() {
angle += speed;
if (angle > 360){
angle = 0; // 重新開始
// t.cancel();// 關(guān)閉定時(shí)器
}
invalidate(); // 通知系統(tǒng)調(diào)用ondraw
postInvalidate(); // 子進(jìn)程里面
}
},0,100);
}
@Override
protected void onDraw(Canvas canvas) {
drawFanChart(canvas, Color.BLACK, (float) (angle/360.0),"自動(dòng)展開的扇形");
}
// onDraw方法不能滿足需求,所以自己寫一個(gè)方法
private void drawFanChart(Canvas canvas,int color,float rate,String text){
//畫筆
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setTextSize(70);
paint.setColor(color);
//畫扇形
int endAngle = (int) (360*rate);
canvas.drawArc(50,0,450,400, 0,endAngle, true,paint);
canvas.drawText(text,550,300,paint);
}
}
(三)自動(dòng)展開的扇形——valueAnimator屬性動(dòng)畫
和自動(dòng)展開的扇形唯一不同的就是onSizeChanged。
public class ValueAnimator extends View {
int angle; //每次增長之后的值
int speed = 20; //增長速度
public ValueAnimator(Context context) {
super(context);
}
public ValueAnimator(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// 創(chuàng)建ValueAnimator對(duì)象 設(shè)置范圍0-360
android.animation.ValueAnimator va = android.animation.ValueAnimator.ofInt(0,360);
va.setDuration(3000); // 動(dòng)畫時(shí)間
va.setRepeatCount(android.animation.ValueAnimator.INFINITE);
// 設(shè)置監(jiān)聽器 監(jiān)聽值的變化
va.addUpdateListener(new android.animation.ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(android.animation.ValueAnimator valueAnimator) {
// 獲取某一刻的值
angle = (int) valueAnimator.getAnimatedValue();
// 刷新
invalidate();
}
});
// 啟動(dòng)
va.start();
}
@Override
protected void onDraw(Canvas canvas) {
drawFanChart(canvas, Color.BLACK, (float) (angle/360.0),"屬性動(dòng)畫展開的扇形");
}
private void drawFanChart(Canvas canvas,int color,float rate,String text){
//畫筆
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setTextSize(57);
paint.setColor(color);
//畫扇形
int endAngle = (int) (360*rate);// 新繪制的扇形endAngle都在增大
canvas.drawArc(50,0,450,400, 0,endAngle, true,paint);
canvas.drawText(text,550,300,paint);
}
}
(四)xml(使用LinearLayout)
<com.example.test.FanAnimation
android:id="@+id/click"
android:layout_width="wrap_content"
android:layout_height="250dp"/>
<com.example.test.AutoFanAnimation
android:layout_width="wrap_content"
android:layout_height="200dp"/>
<com.example.test.ValueAnimator
android:layout_width="wrap_content"
android:layout_height="220dp"/>
(五)運(yùn)行結(jié)果圖

