android 曲线进度条,Android自定义View——使用贝塞尔曲线实现流量进度条
第一次寫帶圖片的博客,多少還是有點緊張,效果不好,請將就著看,前面的圖是今天要寫的控件的效果圖,元素不多,分別是一個按鈕和一個自定義的控件。
在此以前,我看過許多的書,比如《Android群英傳》、《第一行代碼》等,也看了很多大神的博客,但是即便是這樣,當我看到這么多代碼的時候,一直都沒有真正的動手去敲過這些代碼,以至于我總是覺得自定義View是一個多么高深莫測的技術,我們這些小白是難以觸及的,但是當昨晚看了一篇雞湯之后,覺得人還是要學會專注,要耐得住寂寞,要沉得住氣。所以在未來的幾天,我也會持續的更新自己的博客,希望能夠得到大家的監督,也希望能夠一起成長。
一般來說,不到迫不得已,還是不要去自定義自己的控件,畢竟現在Android API已經給我提供了功能這么強大的控件了,而且你也能夠發現,就算是這么強大的谷歌,很多控件也還是有自己的bug,更何況我們自己寫的控件,當然了,通過自定義控件,來加深我們對Android系統的控件的了解,這也是進階的一個好方法。好了,廢話我先說到這里,下面開始今天的主題。
新建一個Class文件,命名為MyLineView,讓它繼承View,實現它的三個構造函數,緊接著初始化一些畫筆、Path,圓等數據。代碼如下:
1.定義變量
private Paint mPaint, mPaint2;
private Path mPath = new Path();
protected int mViewWidth, mViewHeight;
protected int mWidth, mHeight;
private float r, rArc, x;
private float percent = 0.5f;
private RectF rectF;
private PointF mPointF = new PointF(0, 0);
在構造函數里面初始化數據
public MyLineView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(3);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setTextSize(100);
mPaint2 = new Paint();
mPaint2.setColor(Color.CYAN);
mPaint2.setStrokeWidth(8);
mPaint2.setStyle(Paint.Style.FILL);
}
準備工作已經做好了,緊接著我們復寫View的一個onSizeChanged()方法,故名思議,就是當控件的大小發生改變的時候調用。我們在這里對變量進行賦值,代碼如下:
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
/**控件的高寬*/
mViewWidth = w;
mViewHeight = h;
/**與屏幕左邊的距離和距離右邊的距離*/
mWidth = mViewWidth - getPaddingLeft() - getPaddingRight();
mHeight = mViewHeight - getPaddingTop() - getPaddingBottom();
/**定義半徑*/
r = Math.min(mWidth, mHeight) * 0.4f;
rectF = new RectF(-r, -r, r, r);
}
好了,這個時候的變量已經擁有值了,那可以開始寫最重要的操作了,開始寫onDraw();
@Override
protected void onDraw(Canvas canvas) {
// super.onDraw(canvas);
/** * 畫曲線和外圍的圓 */
canvas.translate(mViewWidth / 2, mViewHeight / 2);
canvas.drawCircle(0, 0, r, mPaint);
rArc = r * (1 - 2 * percent);
double angle = Math.acos((double) rArc / r);
x = r * (float) Math.sin(angle);
mPath.addArc(rectF, 90 - (float) Math.toDegrees(angle),
(float) Math.toDegrees(angle) * 2);
mPath.moveTo(-x, rArc);
mPath.rQuadTo(x / 2, -r / 8, x, 0);
mPath.rQuadTo(x / 2, r / 8, x, 0);
canvas.drawPath(mPath, mPaint2);
mPath.rewind();
/** * 畫文字 */
NumberFormat numberFormat = NumberFormat.getPercentInstance();
numberFormat.setMinimumFractionDigits(1);
textCenter(new String[] { numberFormat.format(percent) }, mPaint,
canvas, mPointF, Paint.Align.CENTER);
}
文字的處理:
/** * 多行文本居中、居右、居左 * *@param strings * 文本字符串列表 *@param paint * 畫筆 *@param canvas * 畫布 *@param point * 點的坐標 *@param align * 居中、居右、居左 */
protected void textCenter(String[] strings, Paint paint, Canvas canvas,
PointF point, Paint.Align align) {
paint.setTextAlign(align);
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
float top = fontMetrics.top;
float bottom = fontMetrics.bottom;
int length = strings.length;
float total = (length - 1) * (-top + bottom)
+ (-fontMetrics.ascent + fontMetrics.descent);
float offset = total / 2 - bottom;
for (int i = 0; i < length; i++) {
float yAxis = -(length - i - 1) * (-top + bottom) + offset;
canvas.drawText(strings[i], point.x, point.y + yAxis, paint);
}
}
好了,截止目前已經把控件寫好了,但是作為一個控件,數據不可能固定不變,所以向外暴露一個方法,用于改變進度的大小;
public void setProgress(float percent) {
if (percent != 0) {
this.percent = percent;
} else {
this.percent = 0;
}
/**重繪*/
invalidate();
}
好了全部流程都在這里了,最后再貼上全部的代碼;
package com.example.view.weight;
import java.text.NumberFormat;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
/** * 貝塞爾曲線 * *@author cheng * */
public class MyLineView extends View {
private Paint mPaint, mPaint2;
private Path mPath = new Path();
protected int mViewWidth, mViewHeight;
protected int mWidth, mHeight;
private float r, rArc, x;
private float percent = 0.5f;
private RectF rectF;
private PointF mPointF = new PointF(0, 0);
public MyLineView(Context context) {
this(context, null);
}
public MyLineView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(3);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setTextSize(100);
mPaint2 = new Paint();
mPaint2.setColor(Color.CYAN);
mPaint2.setStrokeWidth(8);
mPaint2.setStyle(Paint.Style.FILL);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mViewWidth = w;
mViewHeight = h;
mWidth = mViewWidth - getPaddingLeft() - getPaddingRight();
mHeight = mViewHeight - getPaddingTop() - getPaddingBottom();
r = Math.min(mWidth, mHeight) * 0.4f;
rectF = new RectF(-r, -r, r, r);
}
@Override
protected void onDraw(Canvas canvas) {
// super.onDraw(canvas);
/** * 畫曲線和外圍的圓 */
canvas.translate(mViewWidth / 2, mViewHeight / 2);
canvas.drawCircle(0, 0, r, mPaint);
rArc = r * (1 - 2 * percent);
double angle = Math.acos((double) rArc / r);
x = r * (float) Math.sin(angle);
mPath.addArc(rectF, 90 - (float) Math.toDegrees(angle),
(float) Math.toDegrees(angle) * 2);
mPath.moveTo(-x, rArc);
mPath.rQuadTo(x / 2, -r / 8, x, 0);
mPath.rQuadTo(x / 2, r / 8, x, 0);
canvas.drawPath(mPath, mPaint2);
mPath.rewind();
/** * 畫文字 */
NumberFormat numberFormat = NumberFormat.getPercentInstance();
numberFormat.setMinimumFractionDigits(1);
textCenter(new String[] { numberFormat.format(percent) }, mPaint,
canvas, mPointF, Paint.Align.CENTER);
}
/** * 多行文本居中、居右、居左 * *@param strings * 文本字符串列表 *@param paint * 畫筆 *@param canvas * 畫布 *@param point * 點的坐標 *@param align * 居中、居右、居左 */
protected void textCenter(String[] strings, Paint paint, Canvas canvas,
PointF point, Paint.Align align) {
paint.setTextAlign(align);
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
float top = fontMetrics.top;
float bottom = fontMetrics.bottom;
int length = strings.length;
float total = (length - 1) * (-top + bottom)
+ (-fontMetrics.ascent + fontMetrics.descent);
float offset = total / 2 - bottom;
for (int i = 0; i < length; i++) {
float yAxis = -(length - i - 1) * (-top + bottom) + offset;
canvas.drawText(strings[i], point.x, point.y + yAxis, paint);
}
}
public void setProgress(float percent) {
if (percent != 0) {
this.percent = percent;
} else {
this.percent = 0;
}
invalidate();
}
}
布局里面的代碼:
android:id="@+id/view_line"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center" />
總結
以上是生活随笔為你收集整理的android 曲线进度条,Android自定义View——使用贝塞尔曲线实现流量进度条的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vue实现表格的‘模板下载‘功能
- 下一篇: android sina oauth2.