I created an rotated imageview with background rotation but the result is "aliased".
The usual way is to create a Paint with anti-alias flag then use it to draw bitmap.
However, the background is draw by the view's draw(Canvas canvas) method, so i can't use a paint with canvas.drawBitmap method.
Here my code to rotate the imageview including the background :
#Override
public void draw(Canvas canvas)
{
canvas.save();
canvas.rotate(mAngle%360, canvas.getClipBounds().exactCenterX(), canvas.getClipBounds().exactCenterY());
canvas.scale(scaleWidth, scaleHeight, canvas.getClipBounds().exactCenterX(), canvas.getClipBounds().exactCenterY());
super.draw(canvas);
canvas.restore();
}
and my onMeasure method which adapts the height and the width depending of the angle
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int w = getDrawable().getIntrinsicWidth();
int h = getDrawable().getIntrinsicHeight();
double a = Math.toRadians(mAngle);
int width = (int) (Math.abs(w * Math.cos(a)) + Math.abs(h * Math.sin(a)));
int height = (int) (Math.abs(w * Math.sin(a)) + Math.abs(h * Math.cos(a)));
scaleWidth = (width != 0) ? ((float) w) / width : 1;
scaleHeight = (height != 0) ? ((float) h) / height : 1;
setMeasuredDimension(width, height);
}
So, How can i "enable" anti aliasing on this rotation?
Maybe use setDrawFilter on the canvas?
A DrawFilter subclass can be installed in a Canvas. When it is present, it can modify the paint that is used to draw (temporarily). With this, a filter can disable/enable antialiasing, or change the color for everything this is drawn.
edit: see here: https://stackoverflow.com/a/13191948/1954497
Related
I would like to create a custom bullet points in android using canvas.
Following is my code.
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
int x = getWidth();
int y = getHeight();
int radius;
radius = 100;
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.WHITE);
canvas.drawPaint(paint);
// Use Color.parseColor to define HTML colors
paint.setColor(Color.parseColor("#CD5C5C"));
canvas.drawCircle(x / 2, y / 2, radius, paint);
}
But it doesn't produce the view that Im trying to get. Im enclosing a image as a reference. I wish to get such view.
I think what is going wrong in this case is you getting width and height to draw your circle in the center, please try to get your width and height of you parent view like this:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
this.setMeasuredDimension(parentWidth/2, parentHeight);
this.setLayoutParams(new *ParentLayoutType*.LayoutParams(parentWidth/2,parentHeight));
}
And take these values for alignment of your circle,
let me know if this was your problem.
I am writing a custom view in android. I want to draw a circle that cover all width and height of my view. this is my code
private void init() {
bgpaint = new Paint();
bgpaint.setColor(bgColor);
bgpaint.setAntiAlias(true);
bgpaint.setStyle(Paint.Style.STROKE);
bgpaint.setStrokeWidth(strokeWidth);
rect = new RectF();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// draw background circle anyway
int strokeWidth = 50;
rect.set(strokeWidth, strokeWidth, getwidth()- strokeWidth,
getheight() - strokeWidth);
canvas.drawArc(rect, -90, 360, fill, bgpaint);
}
But when I run result will be like this
I want be like this
What the problem with my code?
Probem is in setting your rectangle's coordinates. You must set half of stroke width, not whole stroke width.
float left=strokeWidth / 2;
float top=strokeWidth / 2;
float right=minDimen - strokeWidth/ 2;
float bottom=minDimen - strokeWidth / 2;
rect.set(left, top, right,bottom);
Because it comes to circle, I assume your width and height of your circleView are the same dimension. That is minDimen in my code. Because I use smaller dimension of those two.
final int minDimen = Math.min(width, height);
setMeasuredDimension(minDimen, minDimen);
(this must be called in onMeasure method)
Anyway, it's good method to set width and height in same dimensions.
I read different questions here about this topic, but I still can't find an answer. Feel free to close this question for any reason.
I have a simple Circle class that extends View.
The code for this class is:
public class ProgressCircle extends View {
Paint mCirclePaint;
float extRadius;
float viewWidth, viewHeight;
float centerX, centerY;
public ProgressCircle(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(false);
init();
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
float xpad = (float) getPaddingLeft() + getPaddingRight();
float ypad = (float) getPaddingTop() + getPaddingBottom();
float ww = (float)w - xpad; float hh = (float)h - ypad;
extRadius = Math.min(ww, hh) / 2;
viewWidth = this.getWidth();
viewHeight = this.getHeight();
centerX = viewWidth / 2; centerY = viewHeight / 2;
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(centerX, centerY, extRadius, mCirclePaint);
canvas.drawText("ciao", 0, 0, mCirclePaint);
}
private void init() {
mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mCirclePaint.setColor(0x666666);
mCirclePaint.setStyle(Paint.Style.FILL_AND_STROKE);
}
I confirmed that every method in this classed is called when the main activity is created (through the use of some Log.d()s). I added a <com.mypackage.Circle> element in my main activity's LinearLayout and after that I added a sample testing button.
What I achieved is that the button is shown while my Circle isn't, but still the button (which in the LinearLayout comes after the Circle) is not the first element of the layout: that makes me think that something actually happens, but nothing gets drawn.
It was just a silly problem: the color in mCirclePaint.setColor(0x666666) was an invalid one. It worked with mCirclePaint.setColor(Color.RED) or with any other color defined in the res folder.
If you need to specify a color value, you'll have to include the transparency byte (otherwise it is not a 32bit integer that you are specifying, but a 24bit). So 0x666666 is invalid, but 0xff666666 is a valid color and will draw.
After reading the documentation(http://developer.android.com/guide/topics/graphics/2d-graphics.html):
The Android framework will only call onDraw() as necessary. Each time
that your application is prepared to be drawn, you must request your
View be invalidated by calling invalidate(). This indicates that you'd
like your View to be drawn and Android will then call your onDraw()
method (though is not guaranteed that the callback will be
instantaneous).
Also another thing worth checking is the dimensions you're drawing insure nothing is invalid like a height of 0 etc..
I notice you're not overriding View.onMeasure().
Because you're not overriding this method onsizeChanged() might be passed size 0. You can check this by putting a breakpoint in the onSizechanged() method or printing to Logcat.
I have an ImageView subclass that is supposed to display a logo in the bottom corner of the displayed image. I have this onDraw code to draw the icon on top of the image. It works fine on ICS+ but nothing lower. Does anyone know the reason for this?
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int canvasHeight = canvas.getHeight();
int canvasWidth = canvas.getWidth();
Drawable icon = getResources().getDrawable(R.id.icon);
int width = icon.getIntrinsicWidth();
int height = iconcon.getIntrinsicHeight();
int x = canvasWidth - width - PADDING;
int y = canvasHeight - height - PADDING;
icon.setBounds(x, y, canvasWidth - PADDING, canvasHeight - PADDING);
icon.draw(canvas);
}
you may want to ignore canvas.getWidth() and canvas.getHeight() and use the values received in onSizeChanged(int w, int h, int oldw, int oldh) instead, because sometimes they don't match and canvas.getWidth()/getHeight() gives strange results.
I am new to android graphic programming.
I want to put a bitmap in the centre of my canvas. Hence, i use :
public void onDraw(Canvas canvas) {
float canvasx = (float) canvas.getWidth();
float canvasy = (float) canvas.getHeight();
Then i call the bitmap i want to use,
Bitmap myBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.myBitmap);
Then i find the coordinate location for my bitmap by using these,
float bitmapx = (float) myBitmap.getWidth();
float bitmapy = (float) myBitmap.getHeight();
float boardPosX = (canvasx - bitmapx) / 2;
float boardPosY = (canvasy - bitmapy) / 2;
Finally, i draw the bitmap using,
canvas.drawBitmap(myBitmap, boardPosX, boardPosY, null);
But, the bitmap is not in the center of the canvas. It's a little bit below the position which i reckon should be the center of the canvas.
Is it correct to get the canvas height and width inside the onDraw() method ?
Any idea what's wrong ?
Thanks in advance.
*Edit :
Finally, i make it work by changing
public void onDraw(Canvas canvas) {
float canvasx = (float) canvas.getWidth();
float canvasy = (float) canvas.getHeight();
to
public void onDraw(Canvas canvas) {
float canvasx = (float) getWidth();
float canvasy = (float) getHeight();
However, i dont know why the change fixes my problem.
Use this:
float boardPosX = ((canvasx/2) - (bitmapx / 2));
float boardPosY = ((canvasy/2) - (bitmapy / 2));
private int mWidth;
private int mHeight;
private float mAngle;
#Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
mWidth = View.MeasureSpec.getSize(widthMeasureSpec);
mHeight = View.MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(mWidth, mHeight);
}
#Override protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
Bitmap myBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.compass);
// Here's the magic. Whatever way you do it, the logic is:
// space available - bitmap size and divide the result by two.
// There must be an equal amount of pixels on both sides of the image.
// Therefore whatever space is left after displaying the image, half goes to
// left/up and half to right/down. The available space you get by subtracting the
// image's width/height from the screen dimensions. Good luck.
int cx = (mWidth - myBitmap.getWidth()) >> 1; // same as (...) / 2
int cy = (mHeight - myBitmap.getHeight()) >> 1;
if (mAngle > 0) {
canvas.rotate(mAngle, mWidth >> 1, mHeight >> 1);
}
canvas.drawBitmap(myBitmap, cx, cy, null);
}