package butterflydevs.brainstudio; import android.annotation.SuppressLint; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.Align; import android.graphics.Paint.Style; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Typeface; import android.os.Handler; import android.os.Message; import android.util.AttributeSet; import android.view.View; /** * @author Diogo Bernardino * @email mail@diogobernardino.com * @date 04/2014 */ public class CircularCounter extends View { /** * View starts at 6 o'clock */ private final static float START_DEGREES = 90; /** * Default background */ private int mBackgroundCenter; private int mBackgroundRadius; /** * Current degrees */ private int mOneDegrees; private int mTwoDegrees; private int mThreeDegrees; /** * Current real value */ private int mOneValue = 0; /** * Range of view */ private int mRange; /** * Thickness of flows */ private float mOneWidth; private float mTwoWidth; private float mThreeWidth; /** * Size of text */ private float mTextSize; private float mMetricSize; /** * Color of bars */ private int mOneColor; private int mTwoColor; private int mThreeColor; /** * Color of text */ private int mTextColor = -1; private int mBackgroundColor; /** * Paint objects */ private Paint mOnePaint; private Paint mTwoPaint; private Paint mThreePaint; private Paint mBackgroundPaint; private Paint mTextPaint; private Paint mMetricPaint; /** * Bounds of each flow */ private RectF mOneBounds; private RectF mTwoBounds; private RectF mThreeBounds; /** * Text position */ private float mTextPosY; private float mMetricPosY; private float mMetricPaddingY; /** * Metric in use */ private String mMetricText; /** * Typeface of text */ private Typeface mTypeface; /** * Handler to update the view */ private SpeedHandler mSpinHandler; @SuppressLint("Recycle") public CircularCounter(Context context, AttributeSet attrs) { super(context, attrs); init(context.obtainStyledAttributes(attrs, R.styleable.CircularMeter)); } /** * Setting up variables on attach */ @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); mSpinHandler = new SpeedHandler(this); setupBounds(); setupPaints(); setupTextPosition(); } /** * Free variables on detached */ @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); mSpinHandler = null; mOnePaint = null; mOneBounds = null; mTwoPaint = null; mTwoBounds = null; mBackgroundPaint = null; mTextPaint = null; mMetricPaint = null; } /** * Set up paint variables to be used in onDraw method */ private void setupPaints() { mOnePaint = new Paint(); mOnePaint.setColor(mOneColor); mOnePaint.setAntiAlias(true); mOnePaint.setStyle(Style.STROKE); mOnePaint.setStrokeWidth(mOneWidth); mTwoPaint = new Paint(); mTwoPaint.setColor(mTwoColor); mTwoPaint.setAntiAlias(true); mTwoPaint.setStyle(Style.STROKE); mTwoPaint.setStrokeWidth(mTwoWidth); mThreePaint = new Paint(); mThreePaint.setColor(mThreeColor); mThreePaint.setAntiAlias(true); mThreePaint.setStyle(Style.STROKE); mThreePaint.setStrokeWidth(mThreeWidth); mBackgroundPaint = new Paint(); mBackgroundPaint.setColor(mBackgroundColor); mBackgroundPaint.setAntiAlias(true); mBackgroundPaint.setStyle(Style.FILL); mTextPaint = new Paint(); mTextPaint.setColor(mTextColor); mTextPaint.setStyle(Style.FILL); mTextPaint.setAntiAlias(true); mTextPaint.setTextSize(mTextSize); mTextPaint.setTypeface(mTypeface); mTextPaint.setTextAlign(Align.CENTER); mMetricPaint = new Paint(); mMetricPaint.setColor(mTextColor); mMetricPaint.setStyle(Style.FILL); mMetricPaint.setAntiAlias(true); mMetricPaint.setTextSize(mMetricSize); mMetricPaint.setTypeface(mTypeface); mMetricPaint.setTextAlign(Align.CENTER); } /** * Set the bounds of the bars. */ private void setupBounds() { mBackgroundCenter = this.getLayoutParams().width / 2; mBackgroundRadius = mBackgroundCenter - this.getPaddingTop(); mOneBounds = new RectF(this.getPaddingTop() + mOneWidth / 2, this.getPaddingLeft() + mOneWidth / 2, this.getLayoutParams().width - this.getPaddingRight() - mOneWidth / 2, this.getLayoutParams().height - this.getPaddingBottom() - mOneWidth / 2); mTwoBounds = new RectF( this.getPaddingTop() + mTwoWidth / 2 + mOneWidth, this.getPaddingLeft() + mTwoWidth / 2 + mOneWidth, this.getLayoutParams().width - this.getPaddingRight() - mTwoWidth / 2 - mOneWidth, this.getLayoutParams().height - this.getPaddingBottom() - mTwoWidth / 2 - mOneWidth); mThreeBounds = new RectF(this.getPaddingTop() + mThreeWidth / 2 + mTwoWidth + mOneWidth, this.getPaddingLeft() + mThreeWidth / 2 + mTwoWidth + mOneWidth, this.getLayoutParams().width - this.getPaddingRight() - mThreeWidth / 2 - mTwoWidth - mOneWidth, this.getLayoutParams().height - this.getPaddingBottom() - mThreeWidth / 2 - mTwoWidth - mOneWidth); } /** * Setting up text position */ private void setupTextPosition() { Rect textBounds = new Rect(); mTextPaint.getTextBounds("1", 0, 1, textBounds); mTextPosY = mOneBounds.centerY() + (textBounds.height() / 2f); mMetricPosY = mTextPosY + mMetricPaddingY; } /** * Parse the attributes passed to the view and default values. */ private void init(TypedArray a) { mTextSize = a.getDimension(R.styleable.CircularMeter_textSize, getResources().getDimension(R.dimen.textSize)); mTextColor = a .getColor(R.styleable.CircularMeter_textColor, mTextColor); mMetricSize = a.getDimension(R.styleable.CircularMeter_metricSize, getResources().getDimension(R.dimen.metricSize)); mMetricText = a.getString(R.styleable.CircularMeter_metricText); mMetricPaddingY = getResources().getDimension(R.dimen.metricPaddingY); mRange = a.getInt(R.styleable.CircularMeter_range, 100); mOneWidth = getResources().getDimension(R.dimen.width); mTwoWidth = getResources().getDimension(R.dimen.width); mThreeWidth = getResources().getDimension(R.dimen.width); mOneColor = -1213350; mTwoColor = -7747644; mThreeColor = -1; mOneDegrees = 0; mTwoDegrees = 0; mThreeDegrees = 0; String aux = a.getString(R.styleable.CircularMeter_typeface); if (aux != null) mTypeface = Typeface.createFromAsset(this.getResources() .getAssets(), aux); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawCircle(mBackgroundCenter, mBackgroundCenter, mBackgroundRadius, mBackgroundPaint); canvas.drawArc(mOneBounds, START_DEGREES, mOneDegrees, false, mOnePaint); canvas.drawArc(mTwoBounds, START_DEGREES, mTwoDegrees, false, mTwoPaint); canvas.drawArc(mThreeBounds, START_DEGREES, mThreeDegrees, false, mThreePaint); canvas.drawText(Integer.toString(mOneValue), mOneBounds.centerX(), mTextPosY, mTextPaint); canvas.drawText(mMetricText, mOneBounds.centerX(), mMetricPosY, mMetricPaint); } /* * Setters * */ /** * Set the next values to be drawn * @param v1 * @param v2 * @param v3 */ public void setValues(int v1, int v2, int v3) { if (v1 <= mRange) mOneDegrees = Math.round(((float) v1 * 360) / mRange); else mOneDegrees = 360; if (v2 <= mRange) mTwoDegrees = Math.round(((float) v2 * 360) / mRange); else mTwoDegrees = 360; if (v3 <= mRange) mThreeDegrees = Math.round(((float) v3 * 360) / mRange); else mThreeDegrees = 360; mOneValue = v1; mSpinHandler.sendEmptyMessage(0); } public CircularCounter setRange(int range) { mRange = range; return this; } public CircularCounter setFirstWidth(float width) { mOneWidth = width; return this; } public CircularCounter setSecondWidth(float width) { mTwoWidth = width; return this; } public CircularCounter setThirdWidth(float width) { mThreeWidth = width; return this; } public CircularCounter setTextSize(float size) { mTextSize = size; return this; } public CircularCounter setMetricSize(float size) { mMetricSize = size; return this; } public CircularCounter setFirstColor(int color) { mOneColor = color; return this; } public CircularCounter setSecondColor(int color) { mTwoColor = color; return this; } public CircularCounter setThirdColor(int color) { mThreeColor = color; return this; } public CircularCounter setTextColor(int color) { mTextColor = color; return this; } public CircularCounter setMetricText(String text) { mMetricText = text; return this; } @Override public void setBackgroundColor(int color) { mBackgroundColor = color; } public CircularCounter setTypeface(Typeface typeface) { mTypeface = typeface; return this; } /** * Handles display invalidates */ private static class SpeedHandler extends Handler { private CircularCounter act; public SpeedHandler(CircularCounter act) { super(); this.act = act; } @Override public void handleMessage(Message msg) { act.invalidate(); super.handleMessage(msg); } } }