設計圖
這是設計給的設計圖,也是做出來的效果圖。不看教程的可以直接拉到最後參考代碼
嘰嘰喳喳的分析
別怪我廢話多,因爲畫這個圖老費勁了,你說平時敲代碼百度搜搜,參考參考,啥都有了。可是這圓弧兩端再加倆圓可愁死我了,啥都搜不到。第三方的那些框架長得也不像啊。於是自己進行數學分析。
開始畫:
1.繪製步驟
首先畫一個灰色的圓圈,作爲背景(灰色圓)
然後是覆蓋一段圓弧作爲進度條(藍色圓弧)
然後是最小圓的繪製,進度條開始端(薑黃圓)
然後是進度條末端圓的繪製(明黃圓)
2.分析,下圖是我分析的產物,邏輯設計圖,哈哈哈哈:
注意: 有一個需要提醒一下的是,繪製的時候,需要設置筆觸寬度,也就是setStrokeWidth這個方法。筆觸的寬度,並不是往筆觸內側增加寬度的,而是往外側增加一半,往內側增加一半。
舉例: 直線,紅色那條線纔是真正的落筆處。黃色和綠色是兩側拓寬的寬度。
如果線寬爲10,則綠色和黃色各自的寬度爲5
圓的繪製,同理
說到這裏是因爲想告訴大家,在繪製的過程中,各圓的圓心位置的確定,還需要考慮到筆觸的寬度。
爲了讓大家看明白,我專門花了幾個輔助理解的圓圈
也分別用小紅點標出了主要繪製的四個圓(灰\藍\薑黃\明黃)的圓心位置(灰原和藍弧大小一樣,圓心位置也是重合的)。
腦瓜疼的,就是那個明黃點圓心位置的確定,因爲它是動態的。
如下圖,紅色那個圓環就是我上文中提到的灰圓和藍弧所在位置。下面表述,皆用紅環來表示。紅環之間的那條黑線纔是真正落筆之處。
所以薑黃圓和明黃圓的圓心都應該在這條黑線上。
首先已知整個圖的寬度width,設筆觸的寬度爲stroke
薑黃圓根據圖示,它應該包含在紅環裏,所以它的直徑,應該爲紅環筆觸(也就是灰原和藍弧的筆觸)的寬度。
minRadius=stroke/2;
而明黃圓的直徑,我這裏想畫一個比薑黃圓的直徑大一倍的圓,所以它的直徑是薑黃圓的兩倍。
yellowRadius=stroke=2minRadius;
則紅環的半徑爲(即紅環中黑線到圓心的距離),radius=(width-4minRadius)/2;
綜上,第一個圓的圓心座標爲(半徑+2minRadius,半徑+2minRadius),最小圓圓心爲(半徑+2minRadius,2minRadius)
最重要的明黃圓的圓心,利用三角函數
x=(radius + 2 * minRadius + radius * Math.sin(360 * progress / max * Math.PI / 180))
y=(radius + 2 * minRadius - radius * Math.cos(360 * progress / max * Math.PI / 180))
這樣就可以了。。感覺自己廢話連篇
三角函數的求圓心示意圖
a和c的夾角α我們知道,斜邊c也知道,根據sinα=b/c;cosα=a/c。a和b就可以用已知條件求出來了。
over.
常識
Paint.Style.STROKE 只繪製圖形輪廓(描邊)
Paint.Style.FILL 只繪製圖形內容
Paint.Style.FILL_AND_STROKE 既繪製輪廓也繪製內容
不看教程的可以直接拉到最後參考代碼
代碼寫得是不是很蠢啊,求大佬給意見>~<
最後要插入代碼:
mark一個畫弧鏈接
未完待續–》有空的時候,記得加自定義屬性,把筆觸什麼的設置爲變量
package com.snap.awesomeserial.ui.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
public class CircleProgressView extends View {
int progress = 0;
private String text = "0%";
private int max = 100;
public CircleProgressView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public CircleProgressView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CircleProgressView(Context context) {
super(context);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Style.STROKE);
int stroke=10;//筆觸,是最小圓半徑的兩倍
int minRadius=stroke/2;
float width = getMeasuredWidth();
float radius = (width - minRadius*4) / 2;//最大圓的半徑
paint.setStrokeWidth(stroke);
paint.setColor(0xFFDBDBDB);//灰色
canvas.drawCircle(radius + 2*minRadius, radius + 2*minRadius, radius, paint);
paint.setStrokeWidth(stroke);
RectF oval = new RectF(2*minRadius, 2*minRadius, radius * 2 + 2*minRadius, radius * 2 + 2*minRadius);
paint.setColor(0xFF4080F4);//藍色
//這是畫藍弧,第三個參數false是指,不連接到圓心
canvas.drawArc(oval, -90, 360 * progress / max, false, paint);
paint.setStrokeWidth(stroke);
paint.setStyle(Style.FILL);//設置畫筆類型爲填充
paint.setColor(0xFFD3623E);//薑黃
RectF point = new RectF(radius + minRadius,minRadius, radius + 3*minRadius, 3*minRadius);
//畫一個跨度360的弧,那肯定是個圓了,然後第三個參數爲true,表示連接到圓心,這就變成了一個實心圓。你也可以直接drawCircle
canvas.drawArc(point, 0, 360, true, paint);//畫一個點
paint.setStrokeWidth(2*stroke);
paint.setColor(0xFFEDBC40);//明黃
canvas.drawCircle((float) (radius + 2*minRadius + radius * Math.sin(360 * progress / max * Math.PI / 180)), (float) (radius + 2*minRadius - radius * Math.cos(360 * progress / max * Math.PI / 180)), stroke, paint);
paint.setStyle(Paint.Style.STROKE);
paint.setTextSize(14);
paint.setStrokeWidth(1.0f);
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);
paint.setColor(Color.GRAY);
paint.setStyle(Style.FILL);
canvas.drawText(text, width / 2 - bounds.width() / 2,
width / 2 + bounds.height() / 2, paint);
}
/**
* 初始設置當前進度的最大值-默認100
*
* @param max
*/
public void setMax(int max) {
this.max = max;
}
/**
* 更新進度和文字
*
* @param progress
* @param text
*/
public void setProgressAndText(int progress, String text) {
this.progress = progress;
this.text = text;
postInvalidate();
}
}
教程就是把其他人當傻子,所以即使調用簡單,我也要寫一遍。
隨便哪個xml文件
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent"
android:background="#000000">
<!--這裏是調用-->
<com.snap.awesomeserial.ui.widget.CircleProgressView
android:id="@+id/circleView"
android:layout_width="500dp"
android:layout_height="500dp" />
</LinearLayout>
然後xml對應的activity裏
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
circleView = (CircleProgressView) findViewById(R.id.circleView);
circleView.setMax(100);
int progress=75;
String text ="當前溫度"+progress+"C";
circleView.setProgressAndText(progress, text);
}
好啦成品圖