/*
* Copyright (C) 2013 Simon Vig Therkildsen
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.simonvt.cathode.widget;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
import java.util.Locale;
import net.simonvt.cathode.R;
public class CircularProgressIndicator extends View {
private float minValue;
private float maxValue;
private float value;
private String valueString;
private int textSize;
private int textColor;
private int textBackgroundColor;
private final Paint textPaint = new Paint();
private final Rect textBounds = new Rect();
private float textWidth;
private final Rect tempBounds = new Rect();
private int textMargin;
private int strokeWidth;
private final Paint circlePaint = new Paint();
private final RectF circleBounds = new RectF();
private int circleBackgroundColor;
private int circleColor;
private int minPadding;
public CircularProgressIndicator(Context context) {
this(context, null);
}
public CircularProgressIndicator(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircularProgressIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircularProgressIndicator,
R.attr.circularProgressIndicatorStyle, R.style.Widget_CircularProgressIndicator);
final Resources res = getResources();
final DisplayMetrics dm = res.getDisplayMetrics();
final int defTextMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 12, dm);
textMargin =
a.getDimensionPixelSize(R.styleable.CircularProgressIndicator_textMargin, defTextMargin);
final int defTextColor = 0xFF000000;
textColor = a.getColor(R.styleable.CircularProgressIndicator_textColor, defTextColor);
final int defTextSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12, dm);
textSize = a.getDimensionPixelSize(R.styleable.CircularProgressIndicator_textSize, defTextSize);
textBackgroundColor = a.getColor(R.styleable.CircularProgressIndicator_textBackgroundColor, 0);
final int defStrokeWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, dm);
strokeWidth = a.getDimensionPixelSize(R.styleable.CircularProgressIndicator_circleStrokeWidth,
defStrokeWidth);
maxValue = a.getFloat(R.styleable.CircularProgressIndicator_maxValue, 10.0f);
final int defCircleColor = res.getColor(android.R.color.holo_green_dark);
circleColor = a.getColor(R.styleable.CircularProgressIndicator_circleColor, defCircleColor);
circleBackgroundColor =
a.getColor(R.styleable.CircularProgressIndicator_circleBackgroundColor, 0);
a.recycle();
minPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, dm);
textPaint.setAntiAlias(true);
textPaint.setTextSize(textSize);
textPaint.setColor(textColor);
circlePaint.setAntiAlias(true);
circlePaint.setStrokeWidth(strokeWidth);
setValue(0.0f);
}
public void setValue(float value) {
this.value = value;
valueString = String.format(Locale.US, "%.1f", value);
textPaint.getTextBounds(valueString, 0, valueString.length(), textBounds);
textWidth = textPaint.measureText(valueString);
invalidate();
requestLayout();
}
@Override protected void onDraw(Canvas canvas) {
final int width = getWidth();
final int height = getHeight();
circlePaint.setColor(textBackgroundColor);
circlePaint.setStyle(Paint.Style.FILL);
canvas.drawArc(circleBounds, 0, 360, false, circlePaint);
circlePaint.setStyle(Paint.Style.STROKE);
circlePaint.setColor(circleBackgroundColor);
canvas.drawArc(circleBounds, 0, 360, false, circlePaint);
circlePaint.setColor(circleColor);
final int endAngle = (int) (360.0f / maxValue * value);
canvas.drawArc(circleBounds, -90, endAngle, false, circlePaint);
final float textX = width / 2 - textWidth / 2;
final float textY = height / 2 + textBounds.height() / 2;
canvas.drawText(valueString, textX, textY, textPaint);
}
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width = -1;
int height = -1;
if (widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY) {
width = widthSize;
height = heightSize;
} else if (widthMode == MeasureSpec.EXACTLY) {
width = widthSize;
height = widthSize;
} else if (heightMode == MeasureSpec.EXACTLY) {
width = heightSize;
height = heightSize;
}
String maxValue = String.valueOf(this.maxValue);
textPaint.getTextBounds(maxValue, 0, maxValue.length(), tempBounds);
final int textWidth = tempBounds.width();
final int textHeight = tempBounds.height();
float c = (float) Math.sqrt(Math.pow(textWidth, 2) + Math.pow(textHeight, 2));
if (width == -1) {
width = (int) (c + textMargin + strokeWidth + 2 * minPadding);
height = width;
} else {
width = Math.max(width, height);
height = width;
}
final int halfStrokeWidth = strokeWidth / 2;
final int circleSize = (int) (c + textMargin + halfStrokeWidth);
final int halfCircleSize = circleSize / 2;
final int halfWidth = width / 2;
final int halfHeight = height / 2;
circleBounds.left = halfWidth - halfCircleSize;
circleBounds.top = halfHeight - halfCircleSize;
circleBounds.right = halfWidth + halfCircleSize;
circleBounds.bottom = halfHeight + halfCircleSize;
setMeasuredDimension(width, height);
}
}