From 4d3a7c5441fdcaa03ed47d94d9cf6ab5858fc5b0 Mon Sep 17 00:00:00 2001 From: jzeferino Date: Sun, 10 Jul 2016 15:35:51 +0100 Subject: [PATCH] Added inner and outer contour color and sizes. Default idented the code and removed unused import. --- .../circleprogress/CircleProgressView.java | 353 ++++++++++-------- .../src/main/res/values/attrs.xml | 104 +++--- .../src/main/res/layout/activity_main.xml | 74 ++-- 3 files changed, 280 insertions(+), 251 deletions(-) diff --git a/CircleProgressView/src/main/java/at/grabner/circleprogress/CircleProgressView.java b/CircleProgressView/src/main/java/at/grabner/circleprogress/CircleProgressView.java index 3302989..4ea07af 100644 --- a/CircleProgressView/src/main/java/at/grabner/circleprogress/CircleProgressView.java +++ b/CircleProgressView/src/main/java/at/grabner/circleprogress/CircleProgressView.java @@ -19,7 +19,6 @@ import android.graphics.SweepGradient; import android.graphics.Typeface; import android.os.Build; -import android.os.Handler; import android.os.Message; import android.support.annotation.ColorInt; import android.support.annotation.FloatRange; @@ -60,14 +59,31 @@ public class CircleProgressView extends View { private static final boolean DEBUG = false; //---------------------------------- //region members - + //Colors (with defaults) + private final int mBarColorStandard = 0xff009688; //stylish blue + protected int mLayoutHeight = 0; + protected int mLayoutWidth = 0; + //Rectangles + protected RectF mCircleBounds = new RectF(); + protected RectF mInnerCircleBound = new RectF(); + protected PointF mCenter; + /** + * Maximum size of the text. + */ + protected RectF mOuterTextBounds = new RectF(); + /** + * Actual size of the text. + */ + protected RectF mActualTextBounds = new RectF(); + protected RectF mUnitBounds = new RectF(); + protected RectF mCircleOuterContour = new RectF(); + protected RectF mCircleInnerContour = new RectF(); //value animation Direction mDirection = Direction.CW; float mCurrentValue = 42; float mValueTo = 0; float mValueFrom = 0; float mMaxValue = 100; - // spinner animation float mSpinningBarLengthCurrent = 0; float mSpinningBarLengthOrig = 42; @@ -88,21 +104,19 @@ public class CircleProgressView extends View { //The current state of the animation state machine. AnimationState mAnimationState = AnimationState.IDLE; AnimationStateChangedListener mAnimationStateChangedListener; - protected int mLayoutHeight = 0; - protected int mLayoutWidth = 0; private int mBarWidth = 40; private int mRimWidth = 40; private int mStartAngle = 270; - private float mContourSize = 1; + private float mOuterContourSize = 1; + private float mInnerContourSize = 1; //Default text sizes private int mUnitTextSize = 10; private int mTextSize = 10; //Text scale private float mTextScale = 1; private float mUnitScale = 1; - //Colors (with defaults) - private final int mBarColorStandard = 0xff009688; //stylish blue - private int mContourColor = 0xAA000000; + private int mOuterContourColor = 0xAA000000; + private int mInnerContourColor = 0xAA000000; private int mSpinnerColor = mBarColorStandard; //stylish blue private int mBackgroundCircleColor = 0x00000000; //transparent private int mRimColor = 0xAA83d0c9; @@ -122,22 +136,8 @@ public class CircleProgressView extends View { private Paint mRimPaint = new Paint(); private Paint mTextPaint = new Paint(); private Paint mUnitTextPaint = new Paint(); - private Paint mContourPaint = new Paint(); - //Rectangles - protected RectF mCircleBounds = new RectF(); - protected RectF mInnerCircleBound = new RectF(); - protected PointF mCenter; - /** - * Maximum size of the text. - */ - protected RectF mOuterTextBounds = new RectF(); - /** - * Actual size of the text. - */ - protected RectF mActualTextBounds = new RectF(); - protected RectF mUnitBounds = new RectF(); - protected RectF mCircleOuterContour = new RectF(); - protected RectF mCircleInnerContour = new RectF(); + private Paint mOuterContourPaint = new Paint(); + private Paint mInnerContourPaint = new Paint(); //Other // The text to show private String mText = ""; @@ -179,6 +179,99 @@ public class CircleProgressView extends View { //endregion members //---------------------------------- + /** + * The constructor for the CircleView + * + * @param context The context. + * @param attrs The attributes. + */ + public CircleProgressView(Context context, AttributeSet attrs) { + super(context, attrs); + + parseAttributes(context.obtainStyledAttributes(attrs, + R.styleable.CircleProgressView)); + + if (!isInEditMode()) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + setLayerType(View.LAYER_TYPE_HARDWARE, null); + } + } + + mMaskPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mMaskPaint.setFilterBitmap(false); + mMaskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); + setupPaints(); + } + + private static float calcTextSizeForRect(String _text, Paint _textPaint, RectF _rectBounds) { + + Matrix matrix = new Matrix(); + Rect textBoundsTmp = new Rect(); + //replace ones because for some fonts the 1 takes less space which causes issues + String text = _text.replace('1', '0'); + + //get current mText bounds + _textPaint.getTextBounds(text, 0, text.length(), textBoundsTmp); + + RectF textBoundsTmpF = new RectF(textBoundsTmp); + + matrix.setRectToRect(textBoundsTmpF, _rectBounds, Matrix.ScaleToFit.CENTER); + float values[] = new float[9]; + matrix.getValues(values); + return _textPaint.getTextSize() * values[Matrix.MSCALE_X]; + } + + /** + * @param _angle The angle in degree to normalize + * @return the angle between 0 (EAST) and 360 + */ + private static float normalizeAngle(float _angle) { + return (((_angle % 360) + 360) % 360); + } + + /** + * Calculates the angle from centerPt to targetPt in degrees. + * The return should range from [0,360), rotating CLOCKWISE, + * 0 and 360 degrees represents EAST, + * 90 degrees represents SOUTH, etc... + *

+ * Assumes all points are in the same coordinate space. If they are not, + * you will need to call SwingUtilities.convertPointToScreen or equivalent + * on all arguments before passing them to this function. + * + * @param centerPt Point we are rotating around. + * @param targetPt Point we want to calculate the angle to. + * @return angle in degrees. This is the angle from centerPt to targetPt. + */ + public static double calcRotationAngleInDegrees(PointF centerPt, PointF targetPt) { + // calculate the angle theta from the deltaY and deltaX values + // (atan2 returns radians values from [-PI,PI]) + // 0 currently points EAST. + // NOTE: By preserving Y and X param order to atan2, we are expecting + // a CLOCKWISE angle direction. + double theta = Math.atan2(targetPt.y - centerPt.y, targetPt.x - centerPt.x); + + // rotate the theta angle clockwise by 90 degrees + // (this makes 0 point NORTH) + // NOTE: adding to an angle rotates it clockwise. + // subtracting would rotate it counter-clockwise +// theta += Math.PI/2.0; + + // convert from radians to degrees + // this will give you an angle from [0->270],[-180,0] + double angle = Math.toDegrees(theta); + + // convert to positive range [0-360) + // since we want to prevent negative angles, adjust them now. + // we can assume that atan2 will not return a negative value + // greater than one partial rotation + if (angle < 0) { + angle += 360; + } + + return angle; + } + //---------------------------------- //region getter/setter public int[] getBarColors() { @@ -229,35 +322,59 @@ public float getBlockScale() { return mBlockScale; } - public void setBlockScale(@FloatRange(from = 0.0, to=1)float blockScale) { + public void setBlockScale(@FloatRange(from = 0.0, to = 1) float blockScale) { if (blockScale >= 0.0f && blockScale <= 1.0f) { mBlockScale = blockScale; mBlockScaleDegree = mBlockDegree * blockScale; } } - public int getContourColor() { - return mContourColor; + public int getOuterContourColor() { + return mOuterContourColor; } /** * @param _contourColor The color of the background contour of the circle. */ - public void setContourColor(@ColorInt int _contourColor) { - mContourColor = _contourColor; - mContourPaint.setColor(_contourColor); + public void setOuterContourColor(@ColorInt int _contourColor) { + mOuterContourColor = _contourColor; + mOuterContourPaint.setColor(_contourColor); } - public float getContourSize() { - return mContourSize; + public float getOuterContourSize() { + return mOuterContourSize; } /** * @param _contourSize The size of the background contour of the circle. */ - public void setContourSize(@FloatRange(from = 0.0) float _contourSize) { - mContourSize = _contourSize; - mContourPaint.setStrokeWidth(_contourSize); + public void setOuterContourSize(@FloatRange(from = 0.0) float _contourSize) { + mOuterContourSize = _contourSize; + mOuterContourPaint.setStrokeWidth(_contourSize); + } + + public int getInnerContourColor() { + return mInnerContourColor; + } + + /** + * @param _contourColor The color of the background contour of the circle. + */ + public void setInnerContourColor(@ColorInt int _contourColor) { + mInnerContourColor = _contourColor; + mInnerContourPaint.setColor(_contourColor); + } + + public float getInnerContourSize() { + return mInnerContourSize; + } + + /** + * @param _contourSize The size of the background contour of the circle. + */ + public void setInnerContourSize(@FloatRange(from = 0.0) float _contourSize) { + mInnerContourSize = _contourSize; + mInnerContourPaint.setStrokeWidth(_contourSize); } /** @@ -274,7 +391,6 @@ public void setDelayMillis(int delayMillis) { this.mFrameDelayMillis = delayMillis; } - public int getFillColor() { return mBackgroundCirclePaint.getColor(); } @@ -715,6 +831,9 @@ public void setValueAnimated(float _valueFrom, float _valueTo, long _animationDu triggerOnProgressChanged(_valueTo); } + //endregion getter/setter + //---------------------------------- + public DecimalFormat getDecimalFormat() { return decimalFormat; } @@ -735,7 +854,6 @@ public void setValueInterpolator(TimeInterpolator interpolator) { mAnimationHandler.setValueInterpolator(interpolator); } - /** * Sets the interpolator for length changes of the bar. * @@ -745,33 +863,6 @@ public void setLengthChangeInterpolator(TimeInterpolator interpolator) { mAnimationHandler.setLengthChangeInterpolator(interpolator); } - //endregion getter/setter - //---------------------------------- - - /** - * The constructor for the CircleView - * - * @param context The context. - * @param attrs The attributes. - */ - public CircleProgressView(Context context, AttributeSet attrs) { - super(context, attrs); - - parseAttributes(context.obtainStyledAttributes(attrs, - R.styleable.CircleProgressView)); - - if (!isInEditMode()) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - setLayerType(View.LAYER_TYPE_HARDWARE, null); - } - } - - mMaskPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mMaskPaint.setFilterBitmap(false); - mMaskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); - setupPaints(); - } - /** * Parse the attributes passed to the view from the XML * @@ -853,8 +944,11 @@ private void parseAttributes(TypedArray a) { setFillCircleColor(a.getColor(R.styleable.CircleProgressView_cpv_fillColor, mBackgroundCircleColor)); - setContourColor(a.getColor(R.styleable.CircleProgressView_cpv_contourColor, mContourColor)); - setContourSize(a.getDimension(R.styleable.CircleProgressView_cpv_contourSize, mContourSize)); + setOuterContourColor(a.getColor(R.styleable.CircleProgressView_cpv_outerContourColor, mOuterContourColor)); + setOuterContourSize(a.getDimension(R.styleable.CircleProgressView_cpv_outerContourSize, mOuterContourSize)); + + setInnerContourColor(a.getColor(R.styleable.CircleProgressView_cpv_innerContourColor, mInnerContourColor)); + setInnerContourSize(a.getDimension(R.styleable.CircleProgressView_cpv_innerContourSize, mInnerContourSize)); setMaxValue(a.getFloat(R.styleable.CircleProgressView_cpv_maxValue, mMaxValue)); @@ -904,7 +998,6 @@ private void parseAttributes(TypedArray a) { } - // Recycle a.recycle(); } @@ -992,7 +1085,7 @@ private float calcTextSizeForCircle(String _text, Paint _textPaint, RectF _circl private RectF getInnerCircleRect(RectF _circleBounds) { - double circleWidth = +_circleBounds.width() - (Math.max(mBarWidth, mRimWidth)) - (mContourSize * 2); + double circleWidth = +_circleBounds.width() - (Math.max(mBarWidth, mRimWidth)) - mOuterContourSize - mInnerContourSize; double width = ((circleWidth / 2d) * Math.sqrt(2d)); float widthDelta = (_circleBounds.width() - (float) width) / 2f; @@ -1019,90 +1112,19 @@ private RectF getInnerCircleRect(RectF _circleBounds) { } - private static float calcTextSizeForRect(String _text, Paint _textPaint, RectF _rectBounds) { - - Matrix matrix = new Matrix(); - Rect textBoundsTmp = new Rect(); - //replace ones because for some fonts the 1 takes less space which causes issues - String text = _text.replace('1', '0'); - - //get current mText bounds - _textPaint.getTextBounds(text, 0, text.length(), textBoundsTmp); - - RectF textBoundsTmpF = new RectF(textBoundsTmp); - - matrix.setRectToRect(textBoundsTmpF, _rectBounds, Matrix.ScaleToFit.CENTER); - float values[] = new float[9]; - matrix.getValues(values); - return _textPaint.getTextSize() * values[Matrix.MSCALE_X]; - - - } - - private void triggerOnProgressChanged(float value) { if (onProgressChangedListener != null && value != previousProgressChangedValue) { onProgressChangedListener.onProgressChanged(value); previousProgressChangedValue = value; } } + private void triggerReCalcTextSizesAndPositions() { mTextLength = -1; mOuterTextBounds = getInnerCircleRect(mCircleBounds); invalidate(); } - /** - * @param _angle The angle in degree to normalize - * @return the angle between 0 (EAST) and 360 - */ - private static float normalizeAngle(float _angle) { - return (((_angle % 360) + 360) % 360); - } - - /** - * Calculates the angle from centerPt to targetPt in degrees. - * The return should range from [0,360), rotating CLOCKWISE, - * 0 and 360 degrees represents EAST, - * 90 degrees represents SOUTH, etc... - *

- * Assumes all points are in the same coordinate space. If they are not, - * you will need to call SwingUtilities.convertPointToScreen or equivalent - * on all arguments before passing them to this function. - * - * @param centerPt Point we are rotating around. - * @param targetPt Point we want to calculate the angle to. - * @return angle in degrees. This is the angle from centerPt to targetPt. - */ - public static double calcRotationAngleInDegrees(PointF centerPt, PointF targetPt) { - // calculate the angle theta from the deltaY and deltaX values - // (atan2 returns radians values from [-PI,PI]) - // 0 currently points EAST. - // NOTE: By preserving Y and X param order to atan2, we are expecting - // a CLOCKWISE angle direction. - double theta = Math.atan2(targetPt.y - centerPt.y, targetPt.x - centerPt.x); - - // rotate the theta angle clockwise by 90 degrees - // (this makes 0 point NORTH) - // NOTE: adding to an angle rotates it clockwise. - // subtracting would rotate it counter-clockwise -// theta += Math.PI/2.0; - - // convert from radians to degrees - // this will give you an angle from [0->270],[-180,0] - double angle = Math.toDegrees(theta); - - // convert to positive range [0-360) - // since we want to prevent negative angles, adjust them now. - // we can assume that atan2 will not return a negative value - // greater than one partial rotation - if (angle < 0) { - angle += 360; - } - - return angle; - } - private int calcTextColor(double value) { if (mBarColors.length > 1) { double percent = 1f / getMaxValue() * value; @@ -1248,7 +1270,6 @@ private void setUnitTextBoundsAndSizeWithFixedTextSize(float unitGapWidth, float } - /** * Returns the bounding rectangle of the given _text, with the size and style defined in the _textPaint centered in the middle of the _textBounds * @@ -1281,6 +1302,7 @@ private RectF calcTextBounds(String _text, Paint _textPaint, RectF _textBounds) //---------------------------------- //region Setting up stuff + /** * Set the bounds of the component */ @@ -1301,8 +1323,7 @@ private void setupBounds() { int width = getWidth(); //this.getLayoutParams().width; int height = getHeight(); //this.getLayoutParams().height; - - float circleWidthHalf = mBarWidth / 2f > mRimWidth / 2f + mContourSize ? mBarWidth / 2f : mRimWidth / 2f + mContourSize; + float circleWidthHalf = mBarWidth / 2f > mRimWidth / 2f + mOuterContourSize ? mBarWidth / 2f : mRimWidth / 2f + mOuterContourSize; mCircleBounds = new RectF(paddingLeft + circleWidthHalf, paddingTop + circleWidthHalf, @@ -1315,8 +1336,8 @@ private void setupBounds() { width - paddingRight - (mBarWidth), height - paddingBottom - (mBarWidth)); mOuterTextBounds = getInnerCircleRect(mCircleBounds); - mCircleInnerContour = new RectF(mCircleBounds.left + (mRimWidth / 2.0f) + (mContourSize / 2.0f), mCircleBounds.top + (mRimWidth / 2.0f) + (mContourSize / 2.0f), mCircleBounds.right - (mRimWidth / 2.0f) - (mContourSize / 2.0f), mCircleBounds.bottom - (mRimWidth / 2.0f) - (mContourSize / 2.0f)); - mCircleOuterContour = new RectF(mCircleBounds.left - (mRimWidth / 2.0f) - (mContourSize / 2.0f), mCircleBounds.top - (mRimWidth / 2.0f) - (mContourSize / 2.0f), mCircleBounds.right + (mRimWidth / 2.0f) + (mContourSize / 2.0f), mCircleBounds.bottom + (mRimWidth / 2.0f) + (mContourSize / 2.0f)); + mCircleInnerContour = new RectF(mCircleBounds.left + (mRimWidth / 2.0f) + (mInnerContourSize / 2.0f), mCircleBounds.top + (mRimWidth / 2.0f) + (mInnerContourSize / 2.0f), mCircleBounds.right - (mRimWidth / 2.0f) - (mInnerContourSize / 2.0f), mCircleBounds.bottom - (mRimWidth / 2.0f) - (mInnerContourSize / 2.0f)); + mCircleOuterContour = new RectF(mCircleBounds.left - (mRimWidth / 2.0f) - (mOuterContourSize / 2.0f), mCircleBounds.top - (mRimWidth / 2.0f) - (mOuterContourSize / 2.0f), mCircleBounds.right + (mRimWidth / 2.0f) + (mOuterContourSize / 2.0f), mCircleBounds.bottom + (mRimWidth / 2.0f) + (mOuterContourSize / 2.0f)); mCenter = new PointF(mCircleBounds.centerX(), mCircleBounds.centerY()); } @@ -1354,18 +1375,26 @@ private void setupBarPaint() { public void setupPaints() { setupBarPaint(); setupBarSpinnerPaint(); - setupContourPaint(); + setupOuterContourPaint(); + setupInnerContourPaint(); setupUnitTextPaint(); setupTextPaint(); setupBackgroundCirclePaint(); setupRimPaint(); } - private void setupContourPaint() { - mContourPaint.setColor(mContourColor); - mContourPaint.setAntiAlias(true); - mContourPaint.setStyle(Style.STROKE); - mContourPaint.setStrokeWidth(mContourSize); + private void setupOuterContourPaint() { + mOuterContourPaint.setColor(mOuterContourColor); + mOuterContourPaint.setAntiAlias(true); + mOuterContourPaint.setStyle(Style.STROKE); + mOuterContourPaint.setStrokeWidth(mOuterContourSize); + } + + private void setupInnerContourPaint() { + mInnerContourPaint.setColor(mInnerContourColor); + mInnerContourPaint.setAntiAlias(true); + mInnerContourPaint.setStyle(Style.STROKE); + mInnerContourPaint.setStrokeWidth(mInnerContourSize); } private void setupUnitTextPaint() { @@ -1392,7 +1421,6 @@ private void setupTextPaint() { } - private void setupBackgroundCirclePaint() { mBackgroundCirclePaint.setColor(mBackgroundCircleColor); mBackgroundCirclePaint.setAntiAlias(true); @@ -1441,12 +1469,16 @@ protected void onDraw(Canvas canvas) { drawBlocks(canvas, mCircleBounds, mStartAngle, 360, false, mRimPaint); } } - //Draw contour - if (mContourSize > 0) { - canvas.drawArc(mCircleOuterContour, 360, 360, false, mContourPaint); - canvas.drawArc(mCircleInnerContour, 360, 360, false, mContourPaint); + + //Draw outer contour + if (mOuterContourSize > 0) { + canvas.drawArc(mCircleOuterContour, 360, 360, false, mOuterContourPaint); } + //Draw outer contour + if (mInnerContourSize > 0) { + canvas.drawArc(mCircleInnerContour, 360, 360, false, mInnerContourPaint); + } //Draw spinner if (mAnimationState == AnimationState.SPINNING || mAnimationState == AnimationState.END_SPINNING) { @@ -1638,11 +1670,6 @@ private void drawBar(Canvas _canvas, float _degrees) { //---------------------------------- - - - - - /** * Turn off spinning mode */ @@ -1658,7 +1685,6 @@ public void spin() { } - //---------------------------------- //region touch input @Override @@ -1713,7 +1739,6 @@ private float getRotationAngleForPointFromStart(PointF point) { //region listener for progress change - public interface OnProgressChangedListener { void onProgressChanged(float value); } diff --git a/CircleProgressView/src/main/res/values/attrs.xml b/CircleProgressView/src/main/res/values/attrs.xml index 2657df3..c13a0e6 100644 --- a/CircleProgressView/src/main/res/values/attrs.xml +++ b/CircleProgressView/src/main/res/values/attrs.xml @@ -2,81 +2,85 @@ - - - - - - - - - + + + + + + + + + - - - - - - + + + + + + - - + + - - - - - - - - + + + + + + + + - - - + + + - - - - + + + + - - + + - - - + + + + + + + - + - + - - + + - - - + + + - - - - - - + + + + + + diff --git a/ExampleApp/src/main/res/layout/activity_main.xml b/ExampleApp/src/main/res/layout/activity_main.xml index 894e06b..2cdec74 100644 --- a/ExampleApp/src/main/res/layout/activity_main.xml +++ b/ExampleApp/src/main/res/layout/activity_main.xml @@ -1,68 +1,68 @@ - + + CircleProgressView:cpv_value="10" /> + android:gravity="center_horizontal" + android:orientation="vertical"> + android:textAppearance="?android:attr/textAppearanceMedium" /> + android:layout_marginRight="20dp" /> + android:textAppearance="?android:attr/textAppearanceMedium" /> + android:layout_marginRight="20dp" /> + android:text="Spin" /> + android:text="Show Unit" /> + android:text="Unit Position" + android:textAppearance="?android:attr/textAppearanceMedium" />