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
Related
I'm trying to figure out how to fill an View clockwise.
I figured out how to rotate an image but not sure how to rotate and fill.
Used this class to create a circle:
public class Circle extends View {
private static final int START_ANGLE_POINT = 270;
private final Paint paint;
private RectF rect;
private float angle;
public Circle(Context context, AttributeSet attrs) {
super(context, attrs);
final int strokeWidth = 60;
Point[] points = new Point[3];
points[0] = new Point(7, 13);
points[1] = new Point(13, 19);
points[2] = new Point(21, 9);
paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.FILL);
//Circle color
paint.setColor(Theme.darkRedColour());
//Initial Angle (optional, it can be zero)
angle = 0;
}
#Override
protected void onDraw(Canvas canvas) {
if (rect == null) {
DisplayMetrics metrics = App.getAppContext().getResources().getDisplayMetrics();
int densityDpi = (int)metrics.density;
densityDpi = 3;
int canvasW = getWidth();
int canvasH = getHeight();
Point centerOfCanvas = new Point(canvasW / 2, canvasH / 2);
int rectW = 100; // * (densityDpi - 1);
int rectH = 100; // * (densityDpi - 1);
int left = centerOfCanvas.x - (rectW / 2);
int top = centerOfCanvas.y - (rectH / 2);
int right = centerOfCanvas.x + (rectW / 2);
int bottom = centerOfCanvas.y + (rectH / 2);
rect = new RectF(left, top, right, bottom);
}
super.onDraw(canvas);
canvas.drawArc(rect, START_ANGLE_POINT, angle, true, paint);
}
public float getAngle() {
return angle;
}
public void setAngle(float angle) {
this.angle = angle;
}
}
Then used an AnimiationListener and updated the angle.
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.
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);
}
}
Hi i have implemented Progress bar and it is working fine, but my problem is i need to give a only border to circle using paint. I worked on that but it is taking all the area of circle, i need only border.
My paint code:
mCirclePaint = new Paint();
mCirclePaint.setAntiAlias(true);
mCirclePaint.setDither(true);
mCirclePaint.setColor(mCircleColor);
mCirclePaint.setStrokeWidth(mCircleStrokeWidth);
mCirclePaint.setStyle(Paint.Style.STROKE);
mCirclePaint.setStrokeJoin(Paint.Join.MITER);
// mCirclePaint.setShadowLayer(4.0f, 0.0f, 2.0f, Color.BLACK);
mCirclePaint.setStrokeCap(Paint.Cap.SQUARE);
canvas.drawPath(mCirclePath, mCirclePaint)
try this ,
paint = new Paint();
paint.setColor(Color.GREEN);
paint.setStrokeWidth(2);
paint.setStyle(Paint.Style.STROKE);
canvas.drawCircle(0, 0, (float) (width1/(1.4)), paint);
and refer this , might be help full to you .Android : canvas.drawBitmap() method not working properly
This is my code for your solution. Just copy this class and try to understand what your were doing wrong. This view will draw progress bar in center of view.
/**
* Created by GIGAMOLE on 23.01.2016.
*/
public class StrokeProgressBar extends View {
private final static float BAR_STROKE = 10.0f;
private final static float BAR_HEIGHT = 60.0f;
private final static float BAR_PADDING = 100.0f;
private final Paint mProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG) {
{
setDither(true);
setAntiAlias(true);
setColor(Color.BLUE);
setStyle(Style.FILL);
}
};
// private final Paint mBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG) {
// {
// setDither(true);
// setAntiAlias(true);
// setColor(Color.GRAY);
// setStyle(Style.FILL);
// }
// };
private final Paint mBgStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG) {
{
setDither(true);
setAntiAlias(true);
setColor(Color.BLUE);
setStyle(Style.STROKE);
setStrokeWidth(BAR_STROKE);
setStrokeCap(Cap.SQUARE);
}
};
public StrokeProgressBar(final Context context) {
this(context, null);
}
public StrokeProgressBar(final Context context, final AttributeSet attrs) {
this(context, attrs, 0);
}
public StrokeProgressBar(final Context context, final AttributeSet attrs, final int defStyleAttr) {
super(context, attrs, defStyleAttr);
// Draw always
setWillNotDraw(false);
}
#Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
#Override
protected void onDraw(final Canvas canvas) {
super.onDraw(canvas);
final float height = canvas.getClipBounds().height();
final float width = canvas.getClipBounds().width();
// Background rect
final Rect bgRect = new Rect(
(int) BAR_PADDING,
(int) (height / 2.0f - BAR_HEIGHT / 2.0f),
(int) (width - BAR_PADDING),
(int) (height / 2.0f + BAR_HEIGHT / 2.0f)
);
// Progress bar rect
final Rect progressRect = new Rect(
(int) BAR_PADDING,
(int) (height / 2.0f - BAR_HEIGHT / 2.0f),
(int) ((width - BAR_PADDING) * 0.7f), // 0.7f is the fraction of progress == 70%
(int) (height / 2.0f + BAR_HEIGHT / 2.0f)
);
// At first draw stroke
canvas.drawRect(
bgRect,
mBgStrokePaint
);
// // At second draw bg
// canvas.drawRect(
// bgRect,
// mBgPaint
// );
// At third draw progress
canvas.drawRect(
progressRect,
mProgressPaint
);
}
}
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));