How to make line to curve shape to fill the image - android

I used square progress bar library from Github android square progress bar, everything is working fine but i want to make the bar should fill my image.. anyone having idea regarding this.???
import java.text.DecimalFormat;
import net.yscs.android.square_progressbar.utils.CalculationUtil;
import net.yscs.android.square_progressbar.utils.PercentStyle;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.View;
public class SquareProgressView extends View {
private double progress;
private final Paint progressBarPaint;
private final Paint outlinePaint;
private final Paint textPaint;
private float widthInDp = 10;
private float strokewidth = 0;
private Canvas canvas;
private boolean outline = false;
private boolean startline = false;
private boolean showProgress = false;
private PercentStyle percentSettings = new PercentStyle(Align.CENTER, 150,
true);
private boolean clearOnHundred = false;
public SquareProgressView(Context context) {
super(context);
progressBarPaint = new Paint();
progressBarPaint.setColor(context.getResources().getColor(
android.R.color.holo_green_dark));
progressBarPaint.setStrokeWidth(CalculationUtil.convertDpToPx(
widthInDp, getContext()));
progressBarPaint.setAntiAlias(true);
progressBarPaint.setStyle(Style.STROKE);
outlinePaint = new Paint();
outlinePaint.setColor(context.getResources().getColor(
android.R.color.black));
outlinePaint.setStrokeWidth(1);
outlinePaint.setAntiAlias(true);
outlinePaint.setStyle(Style.STROKE);
textPaint = new Paint();
textPaint.setColor(context.getResources().getColor(
android.R.color.black));
textPaint.setAntiAlias(true);
textPaint.setStyle(Style.STROKE);
}
public SquareProgressView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
progressBarPaint = new Paint();
progressBarPaint.setColor(context.getResources().getColor(
android.R.color.holo_green_dark));
progressBarPaint.setStrokeWidth(CalculationUtil.convertDpToPx(
widthInDp, getContext()));
progressBarPaint.setAntiAlias(true);
progressBarPaint.setStyle(Style.STROKE);
outlinePaint = new Paint();
outlinePaint.setColor(context.getResources().getColor(
android.R.color.black));
outlinePaint.setStrokeWidth(1);
outlinePaint.setAntiAlias(true);
outlinePaint.setStyle(Style.STROKE);
textPaint = new Paint();
textPaint.setColor(context.getResources().getColor(
android.R.color.black));
textPaint.setAntiAlias(true);
textPaint.setStyle(Style.STROKE);
}
public SquareProgressView(Context context, AttributeSet attrs) {
super(context, attrs);
progressBarPaint = new Paint();
progressBarPaint.setColor(context.getResources().getColor(
android.R.color.holo_green_dark));
progressBarPaint.setStrokeWidth(CalculationUtil.convertDpToPx(
widthInDp, getContext()));
progressBarPaint.setAntiAlias(true);
progressBarPaint.setStyle(Style.STROKE);
outlinePaint = new Paint();
outlinePaint.setColor(context.getResources().getColor(
android.R.color.black));
outlinePaint.setStrokeWidth(1);
outlinePaint.setAntiAlias(true);
outlinePaint.setStyle(Style.STROKE);
textPaint = new Paint();
textPaint.setColor(context.getResources().getColor(
android.R.color.black));
textPaint.setAntiAlias(true);
textPaint.setStyle(Style.STROKE);
}
#Override
protected void onDraw(Canvas canvas) {
this.canvas = canvas;
super.onDraw(canvas);
strokewidth = CalculationUtil.convertDpToPx(widthInDp, getContext());
float scope = canvas.getWidth() + canvas.getHeight()
+ canvas.getHeight() + canvas.getWidth();
float percent = (scope / 100) * Float.valueOf(String.valueOf(progress));
float halfOfTheImage = canvas.getWidth() / 2;
if (outline) {
drawOutline();
}
if (isStartline()) {
drawStartline();
}
if (showProgress) {
drawPercent(percentSettings);
}
if (clearOnHundred && progress == 100.0) {
return;
}
Path path = new Path();
if (percent > halfOfTheImage) {
paintFirstHalfOfTheTop(canvas);
float second = percent - halfOfTheImage;
if (second > canvas.getHeight()) {
paintRightSide(canvas);
float third = second - canvas.getHeight();
if (third > canvas.getWidth()) {
paintBottomSide(canvas);
float forth = third - canvas.getWidth();
if (forth > canvas.getHeight()) {
paintLeftSide(canvas);
float fifth = forth - canvas.getHeight();
if (fifth == halfOfTheImage) {
paintSecondHalfOfTheTop(canvas);
} else {
path.moveTo(strokewidth, (strokewidth / 2));
path.lineTo(strokewidth + fifth, (strokewidth / 2));
canvas.drawPath(path, progressBarPaint);
}
} else {
path.moveTo((strokewidth / 2), canvas.getHeight()
- strokewidth);
path.lineTo((strokewidth / 2), canvas.getHeight()
- forth);
canvas.drawPath(path, progressBarPaint);
}
} else {
path.moveTo(canvas.getWidth() - strokewidth,
canvas.getHeight() - (strokewidth / 2));
path.lineTo(canvas.getWidth() - third, canvas.getHeight()
- (strokewidth / 2));
canvas.drawPath(path, progressBarPaint);
}
} else {
path.moveTo(canvas.getWidth() - (strokewidth / 2), strokewidth);
path.lineTo(canvas.getWidth() - (strokewidth / 2), strokewidth
+ second);
canvas.drawPath(path, progressBarPaint);
}
} else {
path.moveTo(halfOfTheImage, strokewidth / 2);
path.lineTo(halfOfTheImage + percent, strokewidth / 2);
canvas.drawPath(path, progressBarPaint);
}
}
private void drawStartline() {
Path outlinePath = new Path();
outlinePath.moveTo(canvas.getWidth() / 2, 0);
outlinePath.lineTo(canvas.getWidth() / 2, strokewidth);
canvas.drawPath(outlinePath, outlinePaint);
}
private void drawOutline() {
Path outlinePath = new Path();
outlinePath.moveTo(0, 0);
outlinePath.lineTo(canvas.getWidth(), 0);
outlinePath.lineTo(canvas.getWidth(), canvas.getHeight());
outlinePath.lineTo(0, canvas.getHeight());
outlinePath.lineTo(0, 0);
canvas.drawPath(outlinePath, outlinePaint);
}
public void paintFirstHalfOfTheTop(Canvas canvas) {
Path path = new Path();
path.moveTo(canvas.getWidth() / 2, strokewidth / 2);
path.lineTo(canvas.getWidth() + strokewidth, strokewidth / 2);
canvas.drawPath(path, progressBarPaint);
}
public void paintRightSide(Canvas canvas) {
Path path = new Path();
path.moveTo(canvas.getWidth() - (strokewidth / 2), strokewidth);
path.lineTo(canvas.getWidth() - (strokewidth / 2), canvas.getHeight());
canvas.drawPath(path, progressBarPaint);
}
public void paintBottomSide(Canvas canvas) {
Path path = new Path();
path.moveTo(canvas.getWidth() - strokewidth, canvas.getHeight()
- (strokewidth / 2));
path.lineTo(0, canvas.getHeight() - (strokewidth / 2));
canvas.drawPath(path, progressBarPaint);
}
public void paintLeftSide(Canvas canvas) {
Path path = new Path();
path.moveTo((strokewidth / 2), canvas.getHeight() - strokewidth);
path.lineTo((strokewidth / 2), 0);
canvas.drawPath(path, progressBarPaint);
}
public void paintSecondHalfOfTheTop(Canvas canvas) {
Path path = new Path();
path.moveTo(strokewidth, (strokewidth / 2));
path.lineTo(canvas.getWidth() / 2, (strokewidth / 2));
canvas.drawPath(path, progressBarPaint);
}
public double getProgress() {
return progress;
}
public void setProgress(double progress) {
this.progress = progress;
this.invalidate();
}
public void setColor(int color) {
progressBarPaint.setColor(color);
this.invalidate();
}
/**
* #return the border
*/
public float getWidthInDp() {
return widthInDp;
}
/**
* #return the border
*/
public void setWidthInDp(int width) {
this.widthInDp = width;
progressBarPaint.setStrokeWidth(CalculationUtil.convertDpToPx(
widthInDp, getContext()));
this.invalidate();
}
public boolean isOutline() {
return outline;
}
public void setOutline(boolean outline) {
this.outline = outline;
this.invalidate();
}
public boolean isStartline() {
return startline;
}
public void setStartline(boolean startline) {
this.startline = startline;
this.invalidate();
}
private void drawPercent(PercentStyle setting) {
textPaint.setTextAlign(setting.getAlign());
if (setting.getTextSize() == 0) {
textPaint.setTextSize((canvas.getHeight() / 10) * 4);
} else {
textPaint.setTextSize(setting.getTextSize());
}
String percentString = new DecimalFormat("###").format(getProgress());
if (setting.isPercentSign()) {
percentString = percentString + percentSettings.getCustomText();
}
textPaint.setColor(percentSettings.getTextColor());
canvas.drawText(
percentString,
canvas.getWidth() / 2,
(int) ((canvas.getHeight() / 2) - ((textPaint.descent() + textPaint
.ascent()) / 2)), textPaint);
}
public boolean isShowProgress() {
return showProgress;
}
public void setShowProgress(boolean showProgress) {
this.showProgress = showProgress;
this.invalidate();
}
public void setPercentStyle(PercentStyle percentSettings) {
this.percentSettings = percentSettings;
this.invalidate();
}
public PercentStyle getPercentStyle() {
return percentSettings;
}
public void setClearOnHundred(boolean clearOnHundred) {
this.clearOnHundred = clearOnHundred;
this.invalidate();
}
public boolean isClearOnHundred() {
return clearOnHundred;
}
}
above code is used to create square shape progressbar.
Thanks in Advance.

I thought about adding this possibility to the library a few weeks ago. But the problem is, that I'm using a Path to calculate the progress around the image. And it seems to be difficult to work with paths and arcs when you only draw parts of it (the progress). But I did a bit of research and found these two ways on how you can draw rounded corners in general:
Canvas - drawRoundRect
This (drawRoundRect) is a method that the Canvas offers. But the problem here is that you need to give the method a rectangular which then gets rounded corners. As I said above, I'm using a path to draw the progress. So as far as I can see, you can't use that for my library code to add the possibility for rounded corners.
Path - addArc / arcTo
The path itself has two methods (addArc / arcTo) to work with arcs. But the problem is, that if you use them to apply some rounded corners to the path, you then have the problem of displaying the right percentage. Because you need a different way of calculating how far the arcs can go. So this would be a possibility, but it needs a rewrite/extension of my current progress-calculation.
Maybe there is another solution that I haven't thought off. But for the moment there is no supported way in the library to solve this. But you can try it with the two arc-methods from above. If you want that I (or somebody else) takes a try to add this to the library, please add a new issue to the github repository.

Related

Customizing Circular seek bar for discrete values

I am trying to make a circular seek bar with discrete values.
like this
I have already seen this question previously posted but didn't get any insight.I also have tried a number of circular seekbar examples from GitHub but most of them are with continuous values. can anyone help to build one from scratch or to make the available ones working for discrete values?
Thanks in advance.
You can create it with using paint : See my below attached code for the same.
public class ProgressCircle extends View {
private final RectF mOval = new RectF();
private float mSweepAngle = 0;
private int startAngle = 90;
private int angleGap = 4;
private Bitmap icon;
float mEndAngle = 1.0f;
Paint progressPaint = new Paint();
TextPaint textPaint = new TextPaint();
Paint incompletePaint = new Paint();
Paint percentagePaint = new Paint();
private float strokeWidth = 30.0f;
public ProgressCircle(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.ProgressCircle,
0, 0);
int textColor;
float textSize;
int progressColor;
int incompleteColor;
try {
textColor = a.getColor(R.styleable.ProgressCircle_android_textColor, Color.BLUE);
textSize = a.getDimension(R.styleable.ProgressCircle_android_textSize, 100);
strokeWidth = a.getDimension(R.styleable.ProgressCircle_strokeWidth, 30.0f);
progressColor = a.getColor(R.styleable.ProgressCircle_progressColor, Color.RED);
incompleteColor = a.getColor(R.styleable.ProgressCircle_incompleteProgressColor, Color.GRAY);
} finally {
a.recycle();
}
progressPaint.setColor(progressColor);
progressPaint.setStrokeWidth(strokeWidth);
progressPaint.setStyle(Paint.Style.STROKE);
progressPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
textPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
textPaint.setColor(textColor);
textPaint.setTextSize(textSize);
Typeface tf = Typeface.create("Roboto Condensed Light", Typeface.BOLD);
textPaint.setTypeface(tf);
percentagePaint.setFlags(Paint.ANTI_ALIAS_FLAG);
percentagePaint.setColor(textColor);
percentagePaint.setTextSize(textSize / 3);
incompletePaint.setColor(incompleteColor);
incompletePaint.setStrokeWidth(strokeWidth);
incompletePaint.setStyle(Paint.Style.STROKE);
incompletePaint.setFlags(Paint.ANTI_ALIAS_FLAG);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float currentAngleGap = mSweepAngle == 1.0f || mSweepAngle == 0 ? 0 : angleGap;
mOval.set(strokeWidth / 2, strokeWidth / 2, getWidth() - (strokeWidth / 2), getWidth() - (strokeWidth / 2));
canvas.drawArc(mOval, -startAngle + currentAngleGap, (mSweepAngle * 360) - currentAngleGap, false,
progressPaint);
mOval.set(strokeWidth / 2, strokeWidth / 2, getWidth() - (strokeWidth / 2), getWidth() - (strokeWidth / 2));
canvas.drawArc(mOval, mSweepAngle * 360- startAngle + currentAngleGap, 360 - (mSweepAngle * 360) - currentAngleGap, false,
incompletePaint);
drawText(canvas, textPaint, String.valueOf((int) (mSweepAngle * 100)), percentagePaint);
if(icon != null)
canvas.drawBitmap(icon, canvas.getWidth() / 2 - icon.getWidth() / 2, strokeWidth + (canvas.getHeight() / 15), null);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
}
private void drawText(Canvas canvas, Paint paint, String text, Paint percentagePaint) {
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);
Rect percentageBounds = new Rect();
percentagePaint.getTextBounds("%", 0, 1, percentageBounds);
int x = (canvas.getWidth() / 2) - (bounds.width() / 2) - (percentageBounds.width() / 2);
int y = (canvas.getHeight() / 2) + (bounds.height() / 2);
canvas.drawText(text, x, y, paint);
canvas.drawText("%", x + bounds.width() + percentageBounds.width() / 2, y - bounds.height() + percentageBounds.height(), percentagePaint);
}
public void setTextColor(int color) {
textPaint.setColor(color);
}
public void setProgressColor(int color) {
progressPaint.setColor(color);
}
public void setIncompleteColor(int color) {
incompletePaint.setColor(color);
}
public void setProgress(float progress) {
if (progress > 1.0f || progress < 0) {
throw new RuntimeException("Value must be between 0 and 1: " + progress);
}
mEndAngle = progress;
this.invalidate();
}
public void startAnimation() {
ValueAnimator anim = ValueAnimator.ofFloat(mSweepAngle, mEndAngle);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
ProgressCircle.this.mSweepAngle = (Float) valueAnimator.getAnimatedValue();
ProgressCircle.this.invalidate();
}
});
anim.setDuration(10000);
anim.setInterpolator(new AccelerateDecelerateInterpolator());
anim.start();
}
Output Screen :
See the Complete working example here

How to bring canvas on top of other views

I am using magnifier view for my application which is a library I got from here :
https://github.com/nomanr/android-image-magnifier
I have modified this class to extend FrameLayout (It was ImageView before) to work on my FrameLayout.
It's working well except the painted canvas view stays back of all the views which are added in that custom view.
How to bring that canvas on front of those added views?
Custom view class that i am using :
public class ImageMagnifier extends FrameLayout {
private PointF zoomPos;
private boolean zooming = false;
private Matrix matrix;
private Paint paint;
private Bitmap bitmap;
private BitmapShader shader;
private int sizeOfMagnifier = 300;
int cheight, cwidth;
Context con;
C c = C.getInstance();
public ImageMagnifier(Context context) {
super(context);
init();
con=context;
}
public ImageMagnifier(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
con=context;
}
public ImageMagnifier(Context context, AttributeSet attrs) {
super(context, attrs);
init();
con=context;
}
private void init() {
zoomPos = new PointF(0, 0);
matrix = new Matrix();
paint = new Paint();
cwidth = c.Width * 109 / 1280;
cheight = cwidth * 134 / 109;
}
public void otherTouch(int x, int y) {
if (x > c.getwidth1(28) && x < c.getwidth1(921) && y > c.getheight1(135) && y < c.getheight1(560)) {
zoomPos.x = x - 10;
zoomPos.y = y - 75;
zooming = true;
this.invalidate();
} else {
RemoveMagnifire();
}
}
public void RemoveMagnifire() {
zooming = false;
this.invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!zooming) {
buildDrawingCache();
} else {
bitmap = getDrawingCache();
shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP,Shader.TileMode.CLAMP);
paint.setShader(shader);
matrix.reset();
matrix.postScale(2f, 2f, zoomPos.x-10, zoomPos.y+60);
paint.getShader().setLocalMatrix(matrix);
int width = c.Width;
int height = c.Height;
float leftX = zoomPos.x - ((width * 100) / 1280);
float topY = zoomPos.y - ((height * 250) / 720);
float rightX = zoomPos.x + ((width * 100) / 1280);
float bottomY = zoomPos.y - ((height * 100) / 720);
canvas.drawRect(leftX , topY, rightX, bottomY, paint);
}
}
}
A ViewGroup draws its child Views in the dispatchDraw() method. We just need to move the magnifier drawing to after that happens.
The fix is simple. Move everything after the super call in onDraw() to after the super call in dispatchDraw().
...
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// Removed
}
#Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (!zooming) {
buildDrawingCache();
}
else {
bitmap = getDrawingCache();
shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint.setShader(shader);
matrix.reset();
matrix.postScale(2f, 2f, zoomPos.x - 10, zoomPos.y + 60);
paint.getShader().setLocalMatrix(matrix);
int width = c.Width;
int height = c.Height;
float leftX = zoomPos.x - ((width * 100) / 1280);
float topY = zoomPos.y - ((height * 250) / 720);
float rightX = zoomPos.x + ((width * 100) / 1280);
float bottomY = zoomPos.y - ((height * 100) / 720);
canvas.drawRect(leftX , topY, rightX, bottomY, paint);
}
}
...
You can just remove the onDraw() override, if you no longer need it for anything else.

Custom Progress as Step - Android

I need to make something like this:
I'd try to draw this using Canvas.drawArc(...) but I failed.
Can anyone help me?
I created a view that can draw the shape that you want.
It starts by creating a path for one of the quarters, and rotating the canvas by 90 degrees to draw the path 4 times. The Paint used to draw the Path is determined by the progress / maxProgress.
I used a second path to denote the region of the canvas to clip out when drawing, so that there are empty spaces between the quarters.
Finally, the text can be drawn in the middle after restoring the canvas rotation and clipping.
public class CustomProgressView extends View {
private int progress;
private int maxProgress;
private float arcWidth;
private float arcPadding;
private Paint paintPositive;
private Paint paintNegative;
private Paint paintText;
private Path path;
private Path clipPath;
private ProgressListener listener;
public CustomProgressView(Context context) {
super(context);
init();
}
public CustomProgressView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomProgressView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
arcWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 25, getResources().getDisplayMetrics());
arcPadding = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 6, getResources().getDisplayMetrics());
paintPositive = new Paint();
paintPositive.setColor(Color.RED);
paintPositive.setStyle(Paint.Style.FILL_AND_STROKE);
paintPositive.setAntiAlias(true);
paintNegative = new Paint();
paintNegative.setColor(Color.BLUE);
paintPositive.setStyle(Paint.Style.FILL_AND_STROKE);
paintNegative.setAntiAlias(true);
paintText = new Paint();
paintText.setColor(Color.BLACK);
paintText.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 24, getResources().getDisplayMetrics()));
progress = 0;
maxProgress = 10;
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
float diameter = Math.min(getWidth(), getHeight());
RectF ovalOuter = new RectF(0, 0, diameter, diameter);
RectF ovalInner = new RectF(ovalOuter.left + arcWidth, ovalOuter.top + arcWidth, ovalOuter.right - arcWidth, ovalOuter.bottom - arcWidth);
path = new Path();
path.moveTo(ovalOuter.centerX(), ovalOuter.top);
path.addArc(ovalOuter, 270, 90);
path.lineTo(ovalInner.right, ovalInner.centerY());
path.addArc(ovalInner, 0, -90);
path.lineTo(ovalOuter.centerX(), ovalOuter.top);
clipPath = new Path();
clipPath.addRect(ovalOuter.left, ovalOuter.centerY() - arcPadding / 2, ovalOuter.right, ovalOuter.centerY() + arcPadding / 2, Path.Direction.CW);
clipPath.addRect(ovalOuter.centerX() - arcPadding / 2, ovalOuter.top, ovalOuter.centerX() + arcPadding / 2, ovalOuter.bottom, Path.Direction.CW);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float perc = (float) progress / (float) maxProgress;
int state = 0;
if (perc < 0.25) {
state = 1;
} else if (perc < 0.5) {
state = 2;
} else if (perc < 0.75) {
state = 3;
} else {
state = 4;
}
RectF bounds = new RectF();
path.computeBounds(bounds, true);
// Draw Circle
canvas.save();
// Clip padding
canvas.clipPath(clipPath, Region.Op.DIFFERENCE);
canvas.drawPath(path, state == 1 ? paintPositive : paintNegative);
canvas.rotate(90, bounds.left, bounds.bottom);
canvas.drawPath(path, state == 2 ? paintPositive : paintNegative);
canvas.rotate(90, bounds.left, bounds.bottom);
canvas.drawPath(path, state == 3 ? paintPositive : paintNegative);
canvas.rotate(90, bounds.left, bounds.bottom);
canvas.drawPath(path, state == 4 ? paintPositive : paintNegative);
canvas.restore();
// Draw Progress
String text = String.valueOf(progress);
Rect textBounds = new Rect();
paintText.getTextBounds(text, 0, text.length(), textBounds);
float x = bounds.left - textBounds.width() / 2;
float y = bounds.bottom + textBounds.height() / 2;
canvas.drawText(text, x, y, paintText);
}
public int getProgress() {
return progress;
}
public void setProgress(int progress) {
int oldProgress = this.progress;
this.progress = progress;
if (listener != null) {
listener.onProgressChanged(oldProgress, progress);
}
invalidate();
}
public int getMaxProgress() {
return maxProgress;
}
public void setMaxProgress(int maxProgress) {
this.maxProgress = maxProgress;
invalidate();
}
public ProgressListener getListener() {
return listener;
}
public void setListener(ProgressListener listener) {
this.listener = listener;
}
public interface ProgressListener {
void onProgressChanged(int oldProgress, int newProgress);
}
}

I can not draw a round edge at the progress bar

I create custom progress in my programm.
But i can't create Semi Circle parts. I want create parts similar progress which is selected in the pictire on the top box.
My code:
public class SemiCircleProgressBarView extends View {
private Path mClippingPath;
private float mPivotX;
private float mPivotY;
private Context context;
private float progress = 0.0f;
private float thickness;
public SemiCircleProgressBarView(Context context) {
super(context);
this.context = context;
initializeImage();
}
public SemiCircleProgressBarView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
initializeImage();
}
private void initializeImage() {
mClippingPath = new Path();
mPivotX = 0;
mPivotY = 0;
}
public void setClipping(float progress) {
this.progress = progress;
mClippingPath.reset();
thickness = 0.25f * getHeight();
mClippingPath.setFillType(Path.FillType.INVERSE_WINDING);
mClippingPath.addCircle(0.5f * getWidth(), getHeight(), getHeight() - thickness, Path.Direction.CCW);
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float angle = (progress * 180) / 100;
RectF oval = new RectF(mPivotX, mPivotY, mPivotX + getWidth(), mPivotY + 2.0f * getHeight());
Paint p = new Paint();
p.setColor(context.getResources().getColor(R.color.progress));
Paint pbg = new Paint();
pbg.setColor(context.getResources().getColor(R.color.progress_bg));
// Paint cr = new Paint();
// cr.setColor(Color.RED);
canvas.clipPath(mClippingPath);
canvas.drawArc(oval, 180, 360, true, pbg);
canvas.drawArc(oval, 180, angle, true, p);
// canvas.drawCircle(0.5f * thickness,getHeight(),30,cr);
double radAngle = Math.toRadians(angle);
float px = getWidth () - (float)Math.cos(radAngle) * ((float)getWidth() - thickness);
float py = getHeight() - (float)Math.sin(radAngle) * ((float)getHeight() - 0.5f * thickness);
canvas.drawCircle(0.5f * px, py, 0.5f * thickness, p);
}
}
part in the bottoms select rectangles will be simular progress on the top select rectangles

android : Xfermode masking disappearing on 180 degree rotation of Canvas

I am inspired by the the new Material Design animations and I worked to create a similar drawable that is used in new support v7 Action Bar Drawer Toggle.
I created a CustomDrawable. All I actually did is that I created a Play triangle on canvas and pause logo on the left of the left margin of the visible canvas. I rotate the canvas according to the progress and restore it. Then I used Xfermode to crop the rotated result into a circle.
I cant find the solution to the problem.
The problem is that the xFermode is not applied to the 180 degree rotated result(after calling canvas.restore()).
Here is the code of Activity.
public class MainActivity extends Activity{
ImageView iv;
CustomDrawable drawable = new CustomDrawable();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
iv = (ImageView) findViewById(R.id.button);
iv.setLayerType(View.LAYER_TYPE_HARDWARE, null);
iv.setBackgroundDrawable(drawable);
iv.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
float[] values = { 0, 1 };
if (drawable.getProgress() != 0) {
values[0] = drawable.getProgress();
values[1] = 0;
}
ObjectAnimator animator = ObjectAnimator.ofFloat(drawable,
"progress", values);
animator.setDuration(2000);
animator.start();
}
});
}
}
And the code for the CustomDrawable
public class CustomDrawable extends Drawable {
private float mProgress = 0;
private Paint mPaint = new Paint();
private Path mPath = new Path();
private final float rootTwo = (float) Math.sqrt(2);
private final float rootThree = (float) Math.sqrt(3);
private float radius = 0;
private float side = 0;
private Point[] triangle = new Point[3];
Paint xferpaint = new Paint();
Canvas cropper;
Bitmap bitmap;
Interpolator interpolator = new AnticipateOvershootInterpolator();
private float width;
Rect rec1, rec2;
public CustomDrawable() {
mPaint.setAntiAlias(true);
mPaint.setStyle(Style.FILL);
xferpaint.setColor(Color.RED);
xferpaint.setStyle(Style.FILL);
xferpaint.setAntiAlias(true);
}
#Override
public void draw(Canvas canvas) {
canvas.getClipBounds(bound);
boundsf.set(bound);
if (radius == 0) {
radius = Math.min(bound.centerX(), bound.centerY());
radius -= 5;
bitmap = Bitmap.createBitmap(bound.width(), bound.height(),
Config.ARGB_8888);
cropper = new Canvas(bitmap);
cropper.drawCircle(bound.centerX(), bound.centerY(), radius,
xferpaint);
xferpaint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
side = rootTwo * radius;
triangle[0] = new Point(
(int) (bound.centerX() + (side / rootThree)),
bound.centerY());
triangle[1] = new Point(bound.centerX()
- (int) (side / (2 * rootThree)), bound.centerY()
- (int) (side / 2));
triangle[2] = new Point(bound.centerX()
- (int) (side / (2 * rootThree)), bound.centerY()
+ (int) (side / 2));
width = side / 4;
rec1 = new Rect((int) (-bound.centerX() - (3 * width / 2)),
(int) (bound.centerY() - (side / 2)),
(int) (-bound.centerX() - (width / 2)),
(int) (bound.centerY() + (side / 2)));
rec2 = new Rect((int) (-bound.centerX() + (width / 2)),
(int) (bound.centerY() - (side / 2)),
(int) (-bound.centerX() + (3 * width / 2)),
(int) (bound.centerY() + (side / 2)));
}
mPath.rewind();
mPath.moveTo(triangle[0].x, triangle[0].y);
mPath.lineTo(triangle[1].x, triangle[1].y);
mPath.lineTo(triangle[2].x, triangle[2].y);
mPath.close();
mPaint.setColor(Color.parseColor("#378585"));
canvas.drawPaint(mPaint);
mPaint.setColor(Color.parseColor("#FF0400"));
canvas.rotate(180 * interpolator.getInterpolation(mProgress), 0,
bound.centerY());
canvas.drawPath(mPath, mPaint);
canvas.drawRect(rec1, mPaint);
canvas.drawRect(rec2, mPaint);
canvas.restore();
canvas.drawBitmap(bitmap, 0, 0, xferpaint);
}
#Override
public int getOpacity() {
return mPaint.getAlpha();
}
#Override
public void setAlpha(int alpha) {
mPaint.setAlpha(alpha);
}
#Override
public void setColorFilter(ColorFilter filter) {
mPaint.setColorFilter(filter);
}
public float getProgress() {
return mProgress;
}
public void setProgress(float progress) {
mProgress = progress;
invalidateSelf();
}
}
this is your simplified Drawable:
class CustomDrawable extends Drawable implements ValueAnimator.AnimatorUpdateListener {
private float mProgress = 0;
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Path mPath;
private Path mClipPath;
public CustomDrawable() {
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(0xffFF0400);
}
#Override
protected void onBoundsChange(Rect bounds) {
mClipPath = new Path();
int cx = bounds.centerX();
int cy = bounds.centerY();
int radius = Math.min(cx, cy) - 5;
mClipPath.addCircle(cx, cy, radius, Path.Direction.CCW);
final float rootTwo = (float) Math.sqrt(2);
final float rootThree = (float) Math.sqrt(3);
float side = rootTwo * radius;
mPath = new Path();
mPath.moveTo(cx + (side / rootThree), cy);
mPath.lineTo(cx - side / (2 * rootThree), cy - side / 2);
mPath.lineTo(cx - side / (2 * rootThree), cy + side / 2);
mPath.close();
float width = side / 4;
addRect(-cx - (3 * width / 2), cy - (side / 2), width, side);
addRect(-cx + (width / 2), cy - (side / 2), width, side);
}
private void addRect(float l, float t, float dx, float dy) {
mPath.addRect(l, t, l + dx, t + dy, Path.Direction.CCW);
}
#Override
public void draw(Canvas canvas) {
canvas.clipPath(mClipPath);
canvas.drawColor(0xff378585);
Rect bounds = getBounds();
canvas.rotate(mProgress, 0, bounds.centerY());
canvas.drawPath(mPath, mPaint);
}
public void switchIcons() {
float[] values = { 0, 180 };
if (mProgress != 0) {
values[0] = mProgress;
values[1] = 0;
}
ValueAnimator animator = ValueAnimator.ofFloat(values).setDuration(2000);
animator.setInterpolator(new AnticipateOvershootInterpolator());
animator.addUpdateListener(this);
animator.start();
}
#Override
public void onAnimationUpdate(ValueAnimator animation) {
mProgress = (Float) animation.getAnimatedValue();
invalidateSelf();
}
#Override
public int getOpacity() {
return mPaint.getAlpha();
}
#Override
public void setAlpha(int alpha) {
mPaint.setAlpha(alpha);
}
#Override
public void setColorFilter(ColorFilter filter) {
mPaint.setColorFilter(filter);
}
}
EDIT: this is draw() method without Canvas.clipPath and without creating a "mask" Bitmap:
#Override
public void draw(Canvas canvas) {
canvas.drawColor(0xff378585);
canvas.save();
canvas.rotate(mProgress, 0, cy);
canvas.drawPath(mPath, mPaint);
canvas.restore();
canvas.saveLayer(null, mDstInPaint, 0);
canvas.drawCircle(cx, cy, radius, mPaint);
canvas.restore();
}
where: mDstInPaint is a Paint object with xfermode set in Drawable's constructor:
mDstInPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));

Categories

Resources