As I am a beginner of Android developement, I need someone to give me an answer or any comments on my question.
When I draw a simple rectangle on a view with the following code, the rectangle doesn't show in the way in which I would expect.
canvas.drawLine(0, 0, getWidth(), getHeight(), framePaint);
wrong
But when I changed it like this, it shows properly.
canvas.drawRect(1, 0, getWidth(), getHeight()-1, framePaint);
Correct
That looks like the left and the bottom lines are clipped out of the view.
I was expecting that the position of view starts zero-indexed such as 0 ~ (size of view)-1. Do I understand wrong or did i do something wrong?
The framePaint is configured like this;
framePaint = new Paint();
framePaint.setColor(Color.rgb(255,0,0));
framePaint.setStrokeWidth(1);
framePaint.setStyle(Paint.Style.STROKE);
Here's what happens:
When you subtract one from the total pixels, it draws the line(s) in the image, not outside of it.
Also the "1" at the start also helps the code stay in the canvas.
You may want to try replacing the 1's in the code with 2's, as the canvas uses an extra pixel to automatically remove "aliasing".
Related
So this is a weird thing I want to do that would look amazing in my app, but for the life of me cannot figure out how.
Let's say I have a background on my screen like so:
I then add a view to it that can have any number of subviews/content. This view naturally obscures the background:
So far so good. Now comes the tricky part. I want to implement something that will allow me to "see through" part of this view. Essentially it will make the view appear invisible but only in one specific area. Here is what it would look like:
I have not found any way to do this so far.
You could use the Bitmap Masking technique to accomplish what you want. Something like the below in your onDraw() method.
Paint paint = new Paint();
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
setLayerType(LAYER_TYPE_HARDWARE,paint); // if hardware acceleration is on
// canvas.saveLayer(0, 0, canvas.getWidth(), canvas.getHeight(), paint); // Use this if hardware acceleration is off.
canvas.drawRect(200, 200, 400, 400, paint); // This will be HOLE in the VIEW
For more info read this: https://stackoverflow.com/a/33483016/4747587
Henry mentioned a good solution. Another easy solution is often to just use a PNG-drawable or a 9-patch-drawable. If the area of your overlay is always the same the PNG gives you full flexibility in what you want to have as transparent and the rest stays as you define it. You can scale the PNG or - if you want only specific areas to scale, use a 9-patch-drawable.
I am trying to draw a heart shaped Canvas using Path in Android. The code is as follows :
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// Fill the canvas with background color
canvas.drawColor(Color.WHITE);
// paint.setShader(null);
// Defining of the heart path starts
path.moveTo(left + WIDTH / 2, top + HEIGHT / 4); // Starting point
// Create a cubic Bezier cubic left path
path.cubicTo(left+WIDTH/5,top,
left+WIDTH/4,top+4*HEIGHT/5,
left+WIDTH/2, top+HEIGHT);
// This is right Bezier cubic path
path.cubicTo(left + 3 * WIDTH / 4, top + 4 * HEIGHT / 5,
left + 4 * WIDTH / 5, top,
left + WIDTH / 2, top + HEIGHT / 4);
paint.setShader(new LinearGradient(0, canvas.getHeight()/4, canvas.getWidth(), canvas.getHeight()/4, new int[]{Color.RED, Color.YELLOW, Color.GREEN}, new float[]{0, 0.6f, 1}, Shader.TileMode.CLAMP));
canvas.drawPath(path, paint);
heart_outline_paint.setColor(getResources().getColor(R.color.heart_outline_color)); // Change the boundary color
heart_outline_paint.setStrokeWidth(4);
heart_outline_paint.setStyle(Paint.Style.STROKE);
canvas.drawPath(path, heart_outline_paint);
}
I am able to draw heart without any issue and I am able to fill color inside the heart using the Fill option in Paint. But I should be able to fill the heart dynamically according to some data and it cannot be filled fully all the time. What I have achieved so far is as follows :
I have made an extensive search and came across a lot of things similar to this. Some of which includes :
Android fill in part of a path?
filling a circle gradually from bottom to top android
I also came across the concept of converting the canvas to bitmap and filling color inside the bitmap using Flood Fill Algorithm which lets users to fill colors inside the bitmap. However, I do not want the bitmap to fill the color while touching inside the heart but to fill while a button click action.
I thought that filling a circle gradually from bottom to top android
would give help me but it makes use of a circle and I am not well-versed in Canvas which makes me very weak in adapting the circle code to such a shape.
If anybody has some ideas or any insights on how to achieve this, it will be really helpful. Cheers. Thanks in advance.
P.S : I also tried some tricks using setShader in Paint but nothing would give me what I want.
EDIT :
I just stumbled upon a idea of drawing a rectangle over the heart with another color same as the background of the canvas so that it will look like its half filled !! I am still working on the idea and not sure how accurate this is gonna be for me. If someone has a better idea, you're most welcome.
I used clipPath function available in Canvas to achieve what I needed. I draw the heart by above method and draw a rectangle over it, and I use the clipPathfunction to clip out the region that is outside the heart.
public static double filled_amount = .90;
path.moveTo(left_x_moveto, left_y_moveto);
path.cubicTo(left_x1, left_y1, left_x2, left_y2, left_x3, left_y3);
path.cubicTo(right_x2, right_y2, right_x1, right_y1, left_x_moveto, left_y_moveto);
path.close();
Rect rect = new Rect((int)(canvas.getWidth()*.10),(int)(canvas.getHeight()*filled_amount),(int) canvas.getWidth(), (int) canvas.getHeight());
canvas.clipPath(path);
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.FILL);
canvas.drawPath(path, paint);
canvas.drawRect(rect, rect_paint);
heart_outline_paint.setColor(getResources().getColor(R.color.heart_outline_color)); // Change the boundary color
heart_outline_paint.setStrokeWidth(15);
heart_outline_paint.setStyle(Paint.Style.STROKE);
canvas.drawPath(path, heart_outline_paint);
This will give me the desired result of filling the heart dynamically. Changing the value of filled_amount dynamically and calling invalidate() will make it look like the heart is being filled dynamically.
#Henry's answer might be a better one but this did the trick for me and I dont look deeply in to the edges so a bit of zig-zags here and there is all right.
You could use Bitmap Masking to get a partially filled Heart. What you ideally do here is use one bitmap to mask the other.
In your case you could have a filled rectangle in the canvas and you have then have the heart shape in a new bitmap to act as the mask. You could then dynamically change the filling of the heart by changing the height of the background rectangle.
Refer this: https://stackoverflow.com/a/33483600/4747587. This contains the implementation of partially filling a Star. The idea is the same.
let's get straight to the point, I was making an android game and I decided to try and use some more android methods like Rect and Path so I can experiment and learn how they work. (in the past I used only bitmaps to draw graphics)
As I was making the game I noticed some weird coloring on my rects, so I tried a lot of things, I made sure my rects are initialized properly and I also tried to simplify my code to make sure the problem was caused there.
For debug purposes my code draws a white square on the top left side of the screen, a black on the top right, and a gray one on the bottom, this is the code:
Paint pGray, pWhite, pBlack;
public myClass()
{
paintGray = new Paint();
paintGray.setARGB(255, 125, 125, 125);
paintWhite = new Paint();
paintWhite.setARGB(255, 255, 255, 255);
paintBlack = new Paint();
paintBlack.setARGB(255, 0, 0, 0);
}
public void draw(Canvas canvas)
{
canvas.drawRect(0, screenHeight/2, screenWidth, screenHeight, paintGray);
canvas.drawRect(0, 0, screenWidth/2, screenHeight/2, paintWhite);
canvas.drawRect(screenWidth/2, 0, screenWidth, screenHeight/2, paintBlack);
}
(I don't know if it matters but it runs on another Thread)
When I run it on my phone and save a screenshot using Android Studio the screenshot looks like this:
which is t he desired result, the problem is that my phone doesn't display the graphics properly and here is a photo:
As you can see the gray square has 2 colors inside it, a darker and a lighter one. It happens on both phones that I have and I have no idea what it is, even weirder is that saving the screenshot doesn't show this problem!!
I also noticed the colorization changes based on the white square, if I make it bigger or smaller the gray square changes its color where the white box ends.
Another thing I noticed is that these lines of "decolorization" (with multiple white boxes, multiple lines appear) on the gray square is vertical on landscape mode, but on portrait it becomes horizontal.
I've been torturing my self for so much time with this, I have commented out my whole application to try and see why it happens, if I'm missing something or anyone knows anything please let me know!
I don't think it's a software bug. My guess would be that that's the way the display is rendering colors.
I've been browsing for some days now, but I can't seem to find a way to do this. I hope that maybe some of you are more experienced then I am with the Android SDK and its abilities :)
Say you draw the path on the canvas with the upper- and left-most control point x=300 and y=500 (the scribble in the image below). I want to be able to set the position of its "rectangle" to the canvas coordinates e.g. x=10 and y=10
So basically, it is the rectangle with the path that I am interested in. The idea is "cutting" this area out and moving it to a given position (but I don't want to include the underlying draws that are already on the canvas).
What I have tried:
Converting the Path into a PathShape and then a ShapeDrawable. I am able to skew the position of the Drawable, but it is too inexact to be used to position it.
ShapeDrawable sd = new ShapeDrawable(new PathShape(path, getWidth(), getHeight());
sd.getPaint().set(p);
sd.setBounds(0, 0, getWidth(), getHeight());
getWidth() and getHeight() are respectively getting the width and height of the canvas.
Can you please help me think of a way to do this by a new idea or by correcting my ShapeDrawable idea? Thank you very much for any help in advance!
Path transform looks like exactly what you need.
I have been trying to work on a simple code for two days now. I have tried all alterations but none seems to be working.
I am trying to draw vertical rectangles with different colors.
In the first one, I am using only one Rect variable and moving the coordinates. Here is the relevant part of the code.
Rect myRect1=new Rect();
Random colorMe=new Random();
for(int j=0;j<5;j++){
myRect1.set(myCanvas.getWidth()/5*j, 0, myCanvas.getWidth()/5*j, myCanvas.getHeight());
paint.setColor(Color.rgb(colorMe.nextInt(255), colorMe.nextInt(255), colorMe.nextInt(255)));
myCanvas.drawRect(myRect1, paint);
}
Other alteration which I tried was through an array.
Here is the code.
Rect[] myRect=new Rect[5];
Random colorMe=new Random();
for(int j=0;j<5;j++){
myRect[j].set(myCanvas.getWidth()/5*j, 0, myCanvas.getWidth()/5*j, myCanvas.getHeight());
paint.setColor(Color.rgb(colorMe.nextInt(255), colorMe.nextInt(255), colorMe.nextInt(255)));
myCanvas.drawRect(myRect[j], paint);
}
Can somebody please help me what is the problem actually there?
The first thing that seems obviously wrong (there might be more):
The minimum x-coordinate of your rectangle is myCanvas.getWidth()/5*j
The maximum x-coordinate of your rectangle is myCanvas.getWidth()/5*j
They are both the same value, so your rectangle is degenerate.
Offtopic, but very relevant: whenever you run into a problem like this, you need to break it down into smaller parts until you get it to do something. This will help you understand what's wrong:
Extract all subexpressions (like the color, and the generated x/y values) into local variables so you can easily inspect them in the debugger
Replace the random color by a predefined color (COLOR.YELLOW), to rule out the random element
Replace the caclulated rectangle by a fixed rectangle (say (10,10) - (20,20)) to rule out the coordinate calculations.
Replace the loop, to rule out the loop.
Your rect has a width of 0px. The parameters of the set() function are, in order, left/top/right/bottom. You use the same value for left and right, so the width is (right-left)=0.
Let's see your coordinates, first:
myRect1.set(myCanvas.getWidth()/5*j, 0, myCanvas.getWidth()/5*j, myCanvas.getHeight());
Top left corner has the same x coordinate as the bottom right corner, so you are drawing a rectangle with 0 width.
Add this line
myRect[j] = new Rect()
before
myRect[j].set(myCanvas.getWidth()/5*j, 0, myCanvas.getWidth()/5*j, myCanvas.getHeight());