Android: Draw Rectangle Over Another Rectangle on Canvas - java

I'm trying to draw one rectangle that's light gray over another rectangle that's white on a canvas, but it doesn't seem to do anything. Here's what I've got:
public void onDraw(Canvas c) {
Paint paint = new Paint();
paint.setColor(Color.LTGRAY);
c.drawRect(0, 0, width, height, paint);
paint.setColor(Color.WHITE);
c.drawRect(10, 10, width - 10, height - 10, paint); //This is slightly smaller than the gray rectangle, so it looks kinda like a border.
}
To display this, I use setContentView() in the main activity to set the view to a new class extending SurfaceView. When the surface is created in the custom SurfaceView, it starts a thread that executes onDraw() every 100 milliseconds. I got the Canvas by using holder.lockCanvas(), then onDraw()ing and holder.unlockCanvasAndPost(c).

Where are you initializing your width and height? Are they set to 0?
Try calling canvas.getWidth() or canvas.getHeight().

Related

Libgdx background image not fitting

I am developing a game which has 480x800 VIRTUAL screen sizes. Also I render my map using TiledMapRenderer. My problem is fitting background and HUD elements into the screen which has different ratio than 480/800 (Mostly taller devices). Some devices show blank area at the bottom of screen.
//my viewport (WIDTH = 480, HEIGHT = 800)
viewport = new ScalingViewport(Scaling.fillX,MyGdxGame.WIDTH,MyGdxGame.HEIGHT,camera);
#Override
public void resize(int width, int height) {
viewport.update(width, height, true);
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
barriers.getRenderer().setProjectionMatrix(viewport.getCamera().combined);
shapeRenderer.setProjectionMatrix(viewport.getCamera().combined);
}
My screen should fit the X, but background image should fit X and Y without changing the aspect ratio. In this case ScalingViewport does not solve my problem, and if I change the viewport, I have to code everything from beginning.
#Override
public void render(float delta) {
update(delta);
SpriteBatch sb = game.batch;
Gdx.gl.glClearColor(46f/255,46f/255,46f/255,1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
sb.setProjectionMatrix(camera.combined);
sb.begin();
//this has to change in somehow
sb.draw(AssetManager.backgroundMenu,0,0,MyGdxGame.WIDTH,MyGdxGame.HEIGHT);
sb.end();
}
Should I use multiple viewport? Or is there any way to fit my background into the screen? By the way I do not want to change my camera if there is a way.
Yes, you should use second viewport for your HUD elements.
I would recommend using ExtendViewport
ExtendViewport viewport = new ExtendViewport(MyGdxGame.WIDTH,MyGdxGame.HEIGHT);
It fills all screen (without black bars) and keeps aspect ratio for all resolutions.

LibGDX: How to draw in the area of the black bars of a FitViewport?

I got a FitViewport with a virtual width and virtual height. When the screen got another aspect ratio than my virtual resolution black bars are added. I want to draw something inside these letterboxes.
I tried to do it that way, but only objects "inside" my virtual resolution are drawn, objects "outside" are just not visible:
viewport = new FitViewport(VIRTUAL_WIDTH, VIRTUAL_HEIGHT, cam);
viewport.apply();
batch.setProjectionMatrix(cam.combined);
batch.begin();
batch.draw(texture, viewport.getRightGutterX(), 0);
batch.end();
How to draw inside the letterboxes?
You would need a second viewport, probably ExtendViewport with the same virtual dimensions as your FitViewport.
//create:
fitViewport = new FitViewport(VIRTUAL_WIDTH, VIRTUAL_HEIGHT);
extendViewport = new ExtendViewport(VIRTUAL_WIDTH, VIRTUAL_HEIGHT);
//resize:
fitViewport.update(width, height);
extendViewport.update(width, height);
//render:
fitViewport.apply();
batch.setProjectionMatrix(fitViewport.getCamera().combined);
batch.begin();
//draw game
batch.end();
extendViewport.apply();
batch.setProjectionMatrix(extendViewport.getCamera().combined);
batch.begin();
//draw stuff in border
batch.end();
If you want to be sure the border stuff doesn't overlap your game, you could swap the draw order above.
Or you could just use ExtendViewport to begin with for everything.

Android Canvas drawRect function doesn't show paint shadow

I am trying to use Android's onDraw function to draw rectangles and lines with shadows around them so they can be seen on a white backgrounds. I have my Paint set up to have a shadowlayer but there is no shadow when the lines are drawn.
Here is my code for the Paint:
paint = new Paint();
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.FILL);
paint.setTextSize(m_textSize);
paint.setAntiAlias(true);
Typeface font = Typeface.create("Times New Roman", Typeface.NORMAL);
paint.setTypeface(font);
paint.setShadowLayer(5, 0, 0, Color.BLACK);
this.setLayerType(View.LAYER_TYPE_HARDWARE, paint);
And here is my drawing code:
private void drawMark(Canvas c, float y, float size)
{
float x = (float) (getWidth()-5.0-size);
c.drawRect(x, y, x + size, y + markHeight, paint);
}
Is there something I am missing to make the shadow work for drawRect?
Please note that I am also using the canvas to draw text and the text does get the shadow effect, but shapes and lines do not.
Thanks
The shadows will only appear when you're drawing in software mode:
this.setLayerType(View.LAYER_TYPE_SOFTWARE, paint);

Add text with grey background to pictures like Snapchat does? Android/Java

Bitmap newBm = ...
Canvas canvas = new Canvas(newBm);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.WHITE);
paint.setTextSize((int) (44 * scale));
Rect bounds = new Rect();
paint.getTextBounds(gText, 0, gText.length(), bounds);
canvas.drawText(gText, x, y, paint);
I drew text on the Bitmap like so. How could I get a grey background that is the same height as the text but covers the whole screen??
You could use a Rect. Before drawing the text draw the Rect to the screen:
int screenWidth = getApplicationContext().getResources().getDisplayMetrics().widthPixels;
Rect greyBack = new Rect(0,top,screenWidth,bottom);
Paint paint = new Paint();
paint.setARGB(128, 100, 100, 100); //added alpha because Snapchat has translucent //grey background
canvas.drawRect(greyBack, paint);
top and bottom need to be coordinates above and below the text. You could use y's value and take away a bit for top and add a bit for bottom. How much you add/subtract is up to you and changes the height of the greyBack background.
The best way to see and learn how these sort of things are done with well written code is to look at the android source code itself. For example here is the onDraw method for a TextView it includes additional stuff you won't probably need like compoundPadding, but you can follow it through and get the basic concept of how it's done.

PorterDuffXfermode DST_IN not working as expected

So I'm trying to speed up some drawing we're doing (drawing a portion of an arc with alpha transparency) and was attempting to cache the entire arc into a separate bitmap, and show it selectively with an alpha mask.
From the research I've done (the Xfermodes API demo for Android, this example, and this tool), if I have for example the following two graphics:
and draw using the following:
Xfermode DST_IN = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
canvas.drawBitmap(circle, 0, 0, paint);
paint.setXfermode(DST_IN);
canvas.drawBitmap(arc, 0, 0, paint);
paint.setXfermode(null);
I should get this result:
Where the destination image (the circle) is clipped to the area where the source image (the arc) is drawn. Instead, I get the full circle. If I just draw the arc, it appears in the correct location, and if I use DST_OUT instead, I get the inverse of the expected result (the other three quadrants of the circle).
I've also made sure to disable hardware rendering for this view, in case there was an issue with this Xfermode, but it doesn't make a difference.
I broke it out into a separate project at the simplest level trying to get it to work, and using the following code, I still have the same problem:
public class ClippedView extends View {
private Xfermode DST_IN, DST_OUT;
private Paint paint;
public ClippedView(Context context) {
super(context);
init();
}
private void init() {
setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
this.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
DST_IN = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
DST_OUT = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setColor(Color.GREEN);
canvas.drawRect(0, 0, getWidth() / 2, getHeight() / 2, paint);
paint.setColor(Color.BLACK);
paint.setXfermode(DST_IN);
canvas.drawCircle(getWidth() / 2, getHeight() / 2, getWidth() / 2, paint);
paint.setXfermode(null);
}
}
Am I using it wrong? Am I just missing something? Have I found a bug? :)
There's a much cheaper and easier way to achieve this: use clipping. Canvas.clipRect() is enough. Your solution is burning a lot of fillrate. You can get the effect you want by using SRC_IN instead of DST_IN. Be careful though: it will work only in a transparent Bitmap or in layer. When you draw directly on screen, the destination is already filled by the window background.

Categories