I am unable set image instead of close text using canvas.Close
text is created using below method.
private void drawCenterText(Canvas canvas, Paint paint) {
paint.setColor(mToggleMenuTextColor);
switch (mOrientation) {
case VERTICAL_RIGHT:
canvas.drawText(openMenuText,
getWidth() - paint.measureText(openMenuText),
getHeight() / 2, paint);
break;
case VERTICAL_LEFT:
canvas.drawText(openMenuText, 2, getHeight() / 2, paint);
break;
case HORIZONTAL_TOP:
canvas.drawText(openMenuText,
(getWidth() / 2) - (paint.measureText(openMenuText) / 2),
textSize, paint);
break;
case HORIZONTAL_BOTTOM:
canvas.drawText(openMenuText,
(getWidth() / 2) - (paint.measureText(openMenuText) / 2),
getHeight() - (textSize), paint);
break;
}
}
I hope this should help you out, I have not tried it but it should let you get going.
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getWidth();
int height = getHeight();
int bitWidth = b.getWidth();
int bitHeight = b.getHeight();
if (width > 0 && height > 0)
canvas.drawBitmap(b, (width / 2) - (bitWidth / 2), height - (bitHeight), mPaint);
else
canvas.drawBitmap(b, 0, 0, mPaint);
}
Where b is my bitmap with any icon initialized as
b = BitmapFactory.decodeResource(getResources(), R.drawable.icon);
Related
I'm trying to animate a background in a game I'm making.
https://imgur.com/kQGWsLu
Should look like this(terrible recording quality)
My first attempt work well on my phone but a lot of people saw their fps cut in half:
public void draw(Canvas canvas, Paint paint) {
if (mPaint == null) {
mPaint = new Paint();
mPaint.setColor(Color.GRAY);
mPaint.setStrokeWidth(1);
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setShader(new RadialGradient(canvas.getWidth() / 4, canvas.getHeight() / 3,
Math.max(1, canvas.getHeight() / 2), Color.rgb(5, 12, 127), Color.rgb(32, 36, 100), Shader.TileMode.REPEAT));
}
width = canvas.getWidth();
height = canvas.getHeight();
canvas.save();
rotation += 4;
if (rotation > 360)
rotation = 0;
canvas.rotate(rotation, width / 2, height / 2);
canvas.drawCircle(width / 2, height / 2, height * 1.3f, mPaint);
canvas.restore();
}
So now I'm thinking about of pre rendering a image and drawing it as a bitmap that covers the screen and rotates instead. I also cut the calculations to only update every other frame instead.
public void draw(Canvas canvas, Paint paint) {
if (!initiated) {
centerX = (int) (canvas.getWidth() / 2);
centerY = (int) (canvas.getHeight() / 2);
width = (int) (canvas.getWidth() * 2f);
height = (int) (canvas.getHeight() * 2f);
map = factory.GFX().getBackground();
initiated = true;
}
if (!skipUpdate) {
x = CalculatorService.getXCircle(rotation, distance, centerX);
y = CalculatorService.getYCircle(rotation, distance, centerY);
body.set((int) x - width / 2,
(int) y - height / 2,
(int) x + (width / 2),
(int) y + (height / 2));
rotation += rotationSpeed;
if (rotation > 360)
rotation = 0;
}
skipUpdate = !skipUpdate;
canvas.drawBitmap(map, null, body, paint);
}
Though since the image is small in size 320*320 I had to scale it up and draw it bigger then the screen to avoid it moving out of bounds and showing the basic black background, and I'm not sure if this is really a improvement, do anyone have a better way of doing it or any advice on how I can improve?
This is how my custom drawable looks by default.
But when scrolled, it overlaps with the AppBarLayout.
The code for the Drawable goes like this:
#Override
public void draw(#NonNull Canvas canvas) {
// get drawable dimensions
Rect bounds = getBounds();
float width = bounds.right - bounds.left;
float height = bounds.bottom - bounds.top;
float w2 = width / 2;
float h2 = height / 2;
float radius = Math.min(w2, h2) - mStrokeWidth / 2;
mPath.reset();
mPath.addCircle(width / 2, height / 2, radius, Path.Direction.CW);
canvas.clipPath(mPath);
// draw background gradient
float barHeight = height / themeColors.length;
mRectF.left = 0;
mRectF.top = 0;
mRectF.right = width;
mRectF.bottom = height;
for (int i = 0; i < themeColors.length; i++) {
mPaint.setColor(themeColors[i]);
canvas.drawRect(0, i * barHeight, width, (i + 1) * barHeight, mPaint);
}
mRectF.set(0, 0, width, height);
canvas.clipRect(mRectF, Region.Op.REPLACE);
if (mStrokeWidth != 0)
canvas.drawCircle(width / 2, height / 2, width / 2 - mStrokeWidth / 2, mStrokePaint);
}
Support Library Version: 25.3.1, 26.1.0
What I've tried:
- Different Region values for clipping path instead of REPLACE
- Clipping path rectangle first and then clipping circle.
How do I fix this ?
I am posting my solution as answer.
The reason it was getting overlapped was because the canvas was getting clipped twice without saving it.
I removed this statement:
canvas.clipRect(mRectF, Region.Op.REPLACE);
and before clipping the canvas for the first time
i saved its state using
canvas.save();
canvas.clipPath(mPath);
and then when i was drawing the stroke, i need the original canvas so i restored it
canvas.restore();
if (mStrokeWidth != 0)
canvas.drawCircle(width / 2, height / 2, width / 2 - mStrokeWidth / 2, mStrokePaint);
This fixed the issue.
Final Drawable Code:
#Override
public void draw(#NonNull Canvas canvas) {
// get drawable dimensions
Rect bounds = getBounds();
float width = bounds.right - bounds.left;
float height = bounds.bottom - bounds.top;
float w2 = width / 2;
float h2 = height / 2;
float radius = Math.min(w2, h2) - mStrokeWidth / 2;
mPath.reset();
mPath.addCircle(width / 2, height / 2, radius, Path.Direction.CW);
canvas.save();
canvas.clipPath(mPath);
// draw background gradient
float barHeight = height / themeColors.length;
mRectF.left = 0;
mRectF.top = 0;
mRectF.right = width;
mRectF.bottom = height;
for (int i = 0; i < themeColors.length; i++) {
mPaint.setColor(themeColors[i]);
canvas.drawRect(0, i * barHeight, width, (i + 1) * barHeight, mPaint);
}
mRectF.set(0, 0, width, height);
//canvas.clipRect(mRectF, Region.Op.REPLACE);
canvas.restore();
if (mStrokeWidth != 0)
canvas.drawCircle(width / 2, height / 2, width / 2 - mStrokeWidth / 2, mStrokePaint);
}
How to centerCrop an image like the same method "centerCrop" do in xml android ? I don't want to crop the center of the image .I have tried the below code but ,it was cropping the center portion of the image,and it produce a square shaped image,I want the same centerCrop function to use in a Canvas on android.Can anyone help?? Hope my question is clear to you.
Bitmap bitmap=BitmapFactory.decodeResource(res, (R.drawable.ice));
Bitmap cropBmp;
if (bitmap.getWidth() >= bitmap.getHeight()){
cropBmp = Bitmap.createBitmap(
bitmap,
bitmap.getWidth()/2 - bitmap.getHeight()/2,
0,
bitmap.getHeight(),
bitmap.getHeight()
);
}else{
cropBmp = Bitmap.createBitmap(
bitmap,
0,
bitmap.getHeight()/2 - bitmap.getWidth()/2,
bitmap.getWidth(),
bitmap.getWidth()
);
}
dstRectForRender.set(50,20 ,500 ,360 );
canvas2.drawBitmap(cropBmp, null, dstRectForRender, paint);
If you want to do same effect (exactly same effect), you can watch how Android do it here: https://github.com/android/platform_frameworks_base/blob/3f453164ec884d26a556477027b430cb22a9b7e3/core/java/android/widget/ImageView.java
Interesting part of code about CENTER_CROP:
[...]
mDrawMatrix = mMatrix;
float scale;
float dx = 0, dy = 0;
if (dwidth * vheight > vwidth * dheight) {
scale = (float) vheight / (float) dheight;
dx = (vwidth - dwidth * scale) * 0.5f;
} else {
scale = (float) vwidth / (float) dwidth;
dy = (vheight - dheight * scale) * 0.5f;
}
mDrawMatrix.setScale(scale, scale);
mDrawMatrix.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));
[...]
I'm starting with Android Wear and I want to make a circle animation, making grow.
I know how to do it, I think, but it's doing it very very slow, hope you can help me
I have this class variable
Paint mAnimation;
intialized on the method OnCreate
mAnimation = new Paint(Paint.ANTI_ALIAS_FLAG);
mAnimation.setStyle(Paint.Style.FILL);
mAnimation.setColor(Color.GREEN);
and on the OnDraw method I have
#Override
public void onDraw(Canvas canvas, Rect bounds) {
int width = bounds.width();
int height = bounds.height();
float centerX = width / 2f;
float centerY = height / 2f;
// Draw the background.
canvas.drawRect(0, 0, bounds.width(), bounds.height(), mBackgroundPaint);
canvas.drawCircle(0, centerY, radiusPlus, mAnimation);
radiusPlus += 20;
}
The animation is "correct", but is very slow, like if was paused.
Thanks!!
EDIT
I found a example and now I finally found why. I didn't invalidate the view at the end of the OnDraw. Now It's working fine. Thanks.
#Override
public void onDraw(Canvas canvas, Rect bounds) {
int width = bounds.width();
int height = bounds.height();
float centerX = width / 2f;
float centerY = height / 2f;
// Draw the background.
canvas.drawRect(0, 0, bounds.width(), bounds.height(), mBackgroundPaint);
canvas.drawCircle(0, centerY, radiusPlus, mAnimation);
radiusPlus += 5;
if (isVisible() && !isInAmbientMode()) {
invalidate();
}
}
I now have a View that is added programically after the onCreate (Depending on some other variables). Everything works as it should and it draws part of a circle.
But my question is how do i redraw it later on ? I need to change the angle in the circle after some data is fetched.
Code for the WindRose :
public class WindRose extends View {
public WindRose(Context context) {
super(context);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvasTest = canvas;
float height = (float) getHeight();
float width = (float) getWidth();
float radius;
if (width > height) {
radius = height / 2;
} else {
radius = width / 2;
}
// radius = (height )/ 2;
Path path = new Path();
path.addCircle(width, height, radius, Path.Direction.CCW);
// / 2
Resources resources = getResources();
int color = resources.getColor(R.color.green_back);
paint.setColor(color);
paint.setStrokeWidth(5);
paint.setStyle(Paint.Style.FILL);
float center_x, center_y;
center_x = width / 2;
center_y = height / 2;
//Formulas :
//SD = Start Degree
//ED = End Degree
//If cakepiece passes 0 (East)
//SD, 360-(SD+ED)
//Else :
//SD, (ED-SD)
oval.set(center_x - radius, center_y - radius, center_x + radius, center_y + radius);
if (End > Start) {
canvas.drawArc(oval, Start, (End - Start), true, paint);
} else if (End < Start) {
canvas.drawArc(oval, Start, ((360 - Start) + End), true, paint);
}
}
}
If i update the Start and End variables nothing happens. i have also tried to call invalidate on the class but also there i dont get any redrawing.
Invalidate that i've tried :
WindRose windrose = new WindRose(this);
windrose.invalidate();
Was called from the main class which WindRose is part of.
How should i do this correctly ?
Maybe calling the invalidate() method of the view will help.
You can read more here(http://developer.android.com/reference/android/view/View.html), but:
"To force a view to draw, call invalidate()."
Note, also that you can invalidate only parts of a view