Android 프로 그래 밍 은 사용자 정의 View 를 기반 으로 화려 한 원형 진도 바 기능 예제 를 실현 합 니 다.
본 고 는 두 개의 구성 요 소 를 포함 하 는데 먼저 효과 도 를 올 립 니 다.
1.ProgressBarView 1(드래그 지원):
2.ProgressBarView 2(진도 값 에 따라 색상 이 다 르 고 드래그 가 지원 되 지 않 음):
코드 가 많 지 않 고 주석 도 상세 해서 모두 붙 였 습 니 다.
(1)ProgressBarView 1:
/**
* ProgressBar.
*/
public class ProgressBarView1 extends View {
/**
*
*/
private static final int ARC_FULL_DEGREE = 300;
/**
*
*/
private int STROKE_WIDTH;
/**
* ,
*/
private int width, height;
/**
*
*/
private float max, progress;
/**
*
*/
private boolean draggingEnabled = false;
/**
*
*/
private RectF circleRectF;
/**
*
*/
private Paint progressPaint;
/**
*
*/
private Paint textPaint;
/**
*
*/
private Paint thumbPaint;
/**
*
*/
private int circleRadius;
/**
*
*/
private int centerX, centerY;
public ProgressBarView1(Context context) {
super(context);
init();
}
public ProgressBarView1(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ProgressBarView1(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
progressPaint = new Paint();
progressPaint.setAntiAlias(true);
textPaint = new Paint();
textPaint.setColor(Color.WHITE);
textPaint.setAntiAlias(true);
thumbPaint = new Paint();
thumbPaint.setAntiAlias(true);
//
textPaint.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "fangz.ttf"));
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (width == 0 || height == 0) {
width = getWidth();
height = getHeight();
//
circleRadius = Math.min(width, height) / 2;
STROKE_WIDTH = circleRadius / 12;
circleRadius -= STROKE_WIDTH;
centerX = width / 2;
centerY = height / 2;
//
circleRectF = new RectF();
circleRectF.left = centerX - circleRadius;
circleRectF.top = centerY - circleRadius;
circleRectF.right = centerX + circleRadius;
circleRectF.bottom = centerY + circleRadius;
}
}
private Rect textBounds = new Rect();
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float start = 90 + ((360 - ARC_FULL_DEGREE) >> 1); //
float sweep1 = ARC_FULL_DEGREE * (progress / max); //
float sweep2 = ARC_FULL_DEGREE - sweep1; //
//
progressPaint.setColor(Color.WHITE);
progressPaint.setStrokeWidth(0);
progressPaint.setStyle(Paint.Style.FILL);
float radians = (float) (((360.0f - ARC_FULL_DEGREE) / 2) / 180 * Math.PI);
float startX = centerX - circleRadius * (float) Math.sin(radians);
float startY = centerY + circleRadius * (float) Math.cos(radians);
canvas.drawCircle(startX, startY, STROKE_WIDTH / 2, progressPaint);
//
progressPaint.setStrokeWidth(STROKE_WIDTH);
progressPaint.setStyle(Paint.Style.STROKE);//
canvas.drawArc(circleRectF, start, sweep1, false, progressPaint);
//
progressPaint.setColor(Color.parseColor("#d64444"));
canvas.drawArc(circleRectF, start + sweep1, sweep2, false, progressPaint);
//
progressPaint.setStrokeWidth(0);
progressPaint.setStyle(Paint.Style.FILL);
float endX = centerX + circleRadius * (float) Math.sin(radians);
float endY = centerY + circleRadius * (float) Math.cos(radians);
canvas.drawCircle(endX, endY, STROKE_WIDTH / 2, progressPaint);
//
textPaint.setTextSize(circleRadius >> 1);
String text = (int) (100 * progress / max) + "";
float textLen = textPaint.measureText(text);
//
textPaint.getTextBounds("8", 0, 1, textBounds);
float h1 = textBounds.height();
//% ,
float extra = text.startsWith("1") ? -textPaint.measureText("1") / 2 : 0;
canvas.drawText(text, centerX - textLen / 2 + extra, centerY - 30 + h1 / 2, textPaint);
//
textPaint.setTextSize(circleRadius >> 2);
canvas.drawText("%", centerX + textLen / 2 + extra + 5, centerY - 30 + h1 / 2, textPaint);
//
textPaint.setTextSize(circleRadius / 5);
text = " ";
textLen = textPaint.measureText(text);
textPaint.getTextBounds(text, 0, text.length(), textBounds);
float h2 = textBounds.height();
canvas.drawText(text, centerX - textLen / 2, centerY + h1 / 2 + h2, textPaint);
// ,
float progressRadians = (float) (((360.0f - ARC_FULL_DEGREE) / 2 + sweep1) / 180 * Math.PI);
float thumbX = centerX - circleRadius * (float) Math.sin(progressRadians);
float thumbY = centerY + circleRadius * (float) Math.cos(progressRadians);
thumbPaint.setColor(Color.parseColor("#33d64444"));
canvas.drawCircle(thumbX, thumbY, STROKE_WIDTH * 2.0f, thumbPaint);
thumbPaint.setColor(Color.parseColor("#99d64444"));
canvas.drawCircle(thumbX, thumbY, STROKE_WIDTH * 1.4f, thumbPaint);
thumbPaint.setColor(Color.WHITE);
canvas.drawCircle(thumbX, thumbY, STROKE_WIDTH * 0.8f, thumbPaint);
}
private boolean isDragging = false;
@Override
public boolean onTouchEvent(@NonNull MotionEvent event) {
if (!draggingEnabled) {
return super.onTouchEvent(event);
}
//
float currentX = event.getX();
float currentY = event.getY();
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
// thumb
if (checkOnArc(currentX, currentY)) {
float newProgress = calDegreeByPosition(currentX, currentY) / ARC_FULL_DEGREE * max;
setProgressSync(newProgress);
isDragging = true;
}
break;
case MotionEvent.ACTION_MOVE:
if (isDragging) {
//
if (checkOnArc(currentX, currentY)) {
setProgressSync(calDegreeByPosition(currentX, currentY) / ARC_FULL_DEGREE * max);
} else {
isDragging = false;
}
}
break;
case MotionEvent.ACTION_UP:
isDragging = false;
break;
}
return true;
}
private float calDistance(float x1, float y1, float x2, float y2) {
return (float) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
/**
* ( )
*/
private boolean checkOnArc(float currentX, float currentY) {
float distance = calDistance(currentX, currentY, centerX, centerY);
float degree = calDegreeByPosition(currentX, currentY);
return distance > circleRadius - STROKE_WIDTH * 5 && distance < circleRadius + STROKE_WIDTH * 5
&& (degree >= -8 && degree <= ARC_FULL_DEGREE + 8);
}
/**
* , 。
*/
private float calDegreeByPosition(float currentX, float currentY) {
float a1 = (float) (Math.atan(1.0f * (centerX - currentX) / (currentY - centerY)) / Math.PI * 180);
if (currentY < centerY) {
a1 += 180;
} else if (currentY > centerY && currentX > centerX) {
a1 += 360;
}
return a1 - (360 - ARC_FULL_DEGREE) / 2;
}
public void setMax(int max) {
this.max = max;
invalidate();
}
public void setProgress(float progress) {
final float validProgress = checkProgress(progress);
//
new Thread(new Runnable() {
@Override
public void run() {
float oldProgress = ProgressBarView1.this.progress;
for (int i = 1; i <= 100; i++) {
ProgressBarView1.this.progress = oldProgress + (validProgress - oldProgress) * (1.0f * i / 100);
postInvalidate();
SystemClock.sleep(20);
}
}
}).start();
}
public void setProgressSync(float progress) {
this.progress = checkProgress(progress);
invalidate();
}
// progress [0,max]
private float checkProgress(float progress) {
if (progress < 0) {
return 0;
}
return progress > max ? max : progress;
}
public void setDraggingEnabled(boolean draggingEnabled) {
this.draggingEnabled = draggingEnabled;
}
}
(2)ProgressBarView 2:
/**
* ProgressBar.
*/
public class ProgressBarView2 extends View {
/**
*
*/
private static final int ARC_FULL_DEGREE = 300;
//
private static final int COUNT = 100;
//
private static final float ARC_EACH_PROGRESS = ARC_FULL_DEGREE * 1.0f / (COUNT - 1);
/**
*
*/
private int ARC_LINE_LENGTH;
/**
*
*/
private int ARC_LINE_WIDTH;
/**
* ,
*/
private int width, height;
/**
*
*/
private float max, progress;
/**
*
*/
private Paint progressPaint;
/**
*
*/
private Paint textPaint;
/**
*
*/
private Paint textBgPaint;
/**
*
*/
private int circleRadius;
/**
*
*/
private int centerX, centerY;
public ProgressBarView2(Context context) {
super(context);
init();
}
public ProgressBarView2(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ProgressBarView2(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
progressPaint = new Paint();
progressPaint.setAntiAlias(true);
textPaint = new Paint();
textPaint.setColor(Color.WHITE);
textPaint.setAntiAlias(true);
textBgPaint = new Paint();
textBgPaint.setAntiAlias(true);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (width == 0 || height == 0) {
width = getWidth();
height = getHeight();
//
circleRadius = Math.min(width, height) / 2;
ARC_LINE_LENGTH = circleRadius / 6;
ARC_LINE_WIDTH = ARC_LINE_LENGTH / 8;
centerX = width / 2;
centerY = height / 2;
}
}
private Rect textBounds = new Rect();
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float start = (360 - ARC_FULL_DEGREE) >> 1; //
float sweep1 = ARC_FULL_DEGREE * (progress / max); //
//
progressPaint.setColor(Color.parseColor(calColor(progress / max, "#ffff0000", "#ff00ff00")));
progressPaint.setStrokeWidth(ARC_LINE_WIDTH);
float drawDegree = 1.6f;
while (drawDegree <= ARC_FULL_DEGREE) {
double a = (start + drawDegree) / 180 * Math.PI;
float lineStartX = centerX - circleRadius * (float) Math.sin(a);
float lineStartY = centerY + circleRadius * (float) Math.cos(a);
float lineStopX = lineStartX + ARC_LINE_LENGTH * (float) Math.sin(a);
float lineStopY = lineStartY - ARC_LINE_LENGTH * (float) Math.cos(a);
if (drawDegree > sweep1) {
//
progressPaint.setColor(Color.parseColor("#88aaaaaa"));
progressPaint.setStrokeWidth(ARC_LINE_WIDTH >> 1);
}
canvas.drawLine(lineStartX, lineStartY, lineStopX, lineStopY, progressPaint);
drawDegree += ARC_EACH_PROGRESS;
}
//
textBgPaint.setStyle(Paint.Style.FILL);//
textBgPaint.setColor(Color.parseColor("#41668b"));
canvas.drawCircle(centerX, centerY, (circleRadius - ARC_LINE_LENGTH) * 0.8f, textBgPaint);
textBgPaint.setStyle(Paint.Style.STROKE);//
textBgPaint.setStrokeWidth(2);
textBgPaint.setColor(Color.parseColor("#aaaaaaaa"));
canvas.drawCircle(centerX, centerY, (circleRadius - ARC_LINE_LENGTH) * 0.8f, textBgPaint);
//
textPaint.setTextSize(circleRadius >> 1);
String text = (int) (100 * progress / max) + "";
float textLen = textPaint.measureText(text);
//
textPaint.getTextBounds("8", 0, 1, textBounds);
float h1 = textBounds.height();
canvas.drawText(text, centerX - textLen / 2, centerY - circleRadius / 10 + h1 / 2, textPaint);
//
textPaint.setTextSize(circleRadius >> 3);
textPaint.getTextBounds(" ", 0, 1, textBounds);
float h11 = textBounds.height();
canvas.drawText(" ", centerX + textLen / 2 + 5, centerY - circleRadius / 10 + h1 / 2 - (h1 - h11), textPaint);
//
textPaint.setTextSize(circleRadius / 6);
text = " ";
textLen = textPaint.measureText(text);
canvas.drawText(text, centerX - textLen / 2, centerY + circleRadius / 2.5f, textPaint);
}
public void setMax(int max) {
this.max = max;
invalidate();
}
// ( )
public void setProgress(final float progress) {
new Thread(new Runnable() {
@Override
public void run() {
float oldProgress = ProgressBarView2.this.progress;
for (int i = 1; i <= 100; i++) {
ProgressBarView2.this.progress = oldProgress + (progress - oldProgress) * (1.0f * i / 100);
postInvalidate();
SystemClock.sleep(20);
}
}
}).start();
}
// ( )
public void setProgressSync(float progress) {
this.progress = progress;
invalidate();
}
/**
* 。
* #aarrggbb , #ccc9c9b2
*/
public String calColor(float fraction, String startValue, String endValue) {
int start_a, start_r, start_g, start_b;
int end_a, end_r, end_g, end_b;
//start
start_a = getIntValue(startValue, 1, 3);
start_r = getIntValue(startValue, 3, 5);
start_g = getIntValue(startValue, 5, 7);
start_b = getIntValue(startValue, 7, 9);
//end
end_a = getIntValue(endValue, 1, 3);
end_r = getIntValue(endValue, 3, 5);
end_g = getIntValue(endValue, 5, 7);
end_b = getIntValue(endValue, 7, 9);
return "#" + getHexString((int) (start_a + fraction * (end_a - start_a)))
+ getHexString((int) (start_r + fraction * (end_r - start_r)))
+ getHexString((int) (start_g + fraction * (end_g - start_g)))
+ getHexString((int) (start_b + fraction * (end_b - start_b)));
}
// #AARRGGBB , int.
private int getIntValue(String hexValue, int start, int end) {
return Integer.parseInt(hexValue.substring(start, end), 16);
}
private String getHexString(int value) {
String a = Integer.toHexString(value);
if (a.length() == 1) {
a = "0" + a;
}
return a;
}
}
더 많은 안 드 로 이 드 관련 내용 에 관심 이 있 는 독자 들 은 본 사이트 의 주 제 를 볼 수 있다.,,,,,,,본 고 에서 말 한 것 이 여러분 의 안 드 로 이 드 프로 그래 밍 에 도움 이 되 기 를 바 랍 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Bitrise에서 배포 어플리케이션 설정 테스트하기이 글은 Bitrise 광고 달력의 23일째 글입니다. 자체 또는 당사 등에서 Bitrise 구축 서비스를 사용합니다. 그나저나 며칠 전 Bitrise User Group Meetup #3에서 아래 슬라이드를 발표했...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.