I'm trying to programmatically draw an SVG on to the screen. The code below is what I've tried, when I run the program nothing shows up.
public MainView(Context context) {
hexagon = AppCompatResources.getDrawable(context,R.drawable.hex_svg);
}
#Override
protected void onDraw(Canvas canvas) {
hexagon.setBounds(30,30,30,30);
hexagon.draw(canvas);
}
The setBounds(int left, int top, int right, int bottom) method takes the positions of the bounding box of the drawable - you've set them all to 30 so you're setting the drawable's width and height to zero.
If you want the image to be at 30x,30y with a width and height of 30 then call setBounds(30, 30, 60, 60).
Also I'd call this in the onLayout method rather than in onDraw.
Related
So I want to change the position of an image which I implemented as a JComponent after I click the corresponding button, however, it does not do anything when getting clicked.
I think the problem may lay inside my paintComponent method, since I want the image to be drawn in the center of my panel in the beginning.
The panel itself has a GridBagLayout, although I think that anchoring it in the center would not help either, since I want to move the image whenever the button is clicked and only want it to show up in the center of the panel when I open the frame...
For this button in particular I want my JComponent/image to move 50 pixels to the right.
Anyway here's what I did:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int x = (this.getWidth() - img.getWidth(null))/2;
int y = (this.getHeight() - img.getHeight(null))/2;
g.drawImage(img, x, y, null);
}
#Override
public void actionPerformed(ActionEvent e) {
img.repaint(img.getX()+50, img.getY(), img.getHeight(), img.getWidth());
}
Currently, your paintComponent method always uses the same values for x and y, so it should come as no surprise that the image doesn’t move.
x and y are state that needs to be remembered. This is done by defining instance fields:
private int x;
private int y;
You can’t initialize them at construction time, because a component has a width and height of zero when it’s created (usually). Fortunately, there is a method which tells you when a component has been given a width and height; that method is addNotify, which you can and should override:
#Override
public void addNotify() {
super.addNotify();
x = (this.getWidth() - img.getWidth(this)) / 2;
y = (this.getHeight() - img.getHeight(this)) / 2;
}
Notice that you should pass this (your component instance) to any method which expects an ImageObserver argument, rather than null.
Now paintComponent doesn’t need to do any calculation. It just paints the image at whatever x and y happen to be:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(img, x, y, this);
}
And now that your coordinates are instance fields, you can change them directly:
#Override
public void actionPerformed(ActionEvent event) {
x += 50;
repaint();
}
I am making a pixel game for android. I am using 32x32 images. To make the game appear the same regardless of screen-dimensions i dynamically scale up the images. My issue is that when scaling up, parts of the images does not keep their original color:
6 tiles, originally 32x32. As you can see, just before the black edges there is an unwanted shadowy line (presumably the average of the black and the redish color).
This is the code i use for scaling:
public abstract class Drawable {
protected int x;
protected int y;
protected Bitmap image;
Drawable(Bitmap image, int x, int y, float scale) {
this.x = x;
this.y = y;
this.image = Bitmap.createScaledBitmap(image, (int)(image.getWidth()*scale), (int)(image.getHeight()*scale), false);
}
abstract void draw(Canvas canvas);
}
As you can see i am not using the filter. This would make the edge-area more blurry. Are there another filter that in contrast to if i where to use true when scaling up actually perserves the crispness of the image?
Edit:
I now tried this approach instead:
scaledRect = new RectF(x, y, x+image.getWidth()*scale, y+image.getHeight()*scale);
paint = new Paint();
paint.setAntiAlias(false);
paint.setDither(false);
paint.setFilterBitmap(false);
And in the draw call:
canvas.drawBitmap(this.image, null, scaledRect, paint);
With no success...
Android processes bitmap scaling with bilinear interpolation algorithm by default. What you're trying to do is nearest neighbor interpolation.
Make a Paint, turn off dither and anti-alias, don't draw by createScaledBitmap and try this:
paint.setDither(false);
paint.setAntiAlias(false);
canvas.drawBitmap(bitmap, null, new RectF(left, top, width, height), paint);
I'm working on a drawing application and am pretty close to release but I'm having issues with the eraser part of the app. I have 2 main screens (fragments) one is just a blank white canvas that the user can draw on with some options and so on. The other is a note taking fragment. This note taking fragment looks like notebook paper. So for erasing on the drawing fragment, I can simply use the background of the canvas and the user wont know the difference. On the note fragment though I cannot do this beacuse I need to keep the background in tact. I have looked into PorterDuffer modes and have tried the clear version and tried to draw onto a separate bitmap but nothing has worked. If there was a way to control what gets draw ontop of what then that would be useful. I'm open to any suggestions, I can't seem to get anything to work.
Ive also played with enabling a drawing cache before erasing and that doesn't work. In addition I tried hardware enabling and that made my custom view behave oddly. Below is the relavent code. My on draw methods goes through a lot of paths because I am querying them in order to allow for some other functionallity.
#Override
protected void onDraw(Canvas canvas) {
//draw the backgroumd type
if(mDrawBackground) {
//draw the background
//if the bitmap is not null draw it as the background, otherwise we are in a note view
if(mBackgroundBitmap != null) {
canvas.drawBitmap(mBackgroundBitmap, 0, 0, backPaint);
} else {
drawBackgroundType(mBackgroundType, canvas);
}
}
for (int i = 0; i < paths.size(); i++ ) {
//Log.i("DRAW", "On draw: " + i);
//draw each previous path.
mDrawPaint.setStrokeWidth(strokeSizes.get(i));
mDrawPaint.setColor(colors.get(i));
canvas.drawPath(paths.get(i), mDrawPaint);
}
//set paint attributes to the current value
mDrawPaint.setStrokeWidth(strokeSize);
mDrawPaint.setColor(mDrawColor);
canvas.drawPath(mPath, mDrawPaint);
}
and my draw background method
/**
* Method that actually draws the notebook paper background
* #param canvas the {#code Canvas} to draw on.
*/
private void drawNoteBookPaperBackground(Canvas canvas) {
//create bitmap for the background and a temporary canvas.
mBackgroundBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBackgroundBitmap);
//set the color to white.
mBackgroundBitmap.eraseColor(Color.WHITE);
//get the height and width of the view minus padding.
int height = getHeight() - getPaddingTop() - getPaddingBottom();
int width = getWidth() - getPaddingLeft() - getPaddingRight();
//figure out how many lines we can draw given a certain line width.
int lineWidth = 50;
int numOfLines = Math.round(height / lineWidth);
Log.i("DRAWVIEW", "" + numOfLines);
//iterate through the number of lines and draw them.
for(int i = 0; i < numOfLines * lineWidth; i+=lineWidth) {
mCanvas.drawLine(0+getPaddingLeft(), i+getPaddingTop(), width, i+getPaddingTop(), mNoteBookPaperLinePaint);
}
//now we need to draw the vertical lines on the left side of the view.
float startPoint = 30;
//set the color to be red.
mNoteBookPaperLinePaint.setColor(getResources().getColor(R.color.notebook_paper_vertical_line_color));
//draw first line
mCanvas.drawLine(startPoint, 0, startPoint, getHeight(), mNoteBookPaperLinePaint);
//space the second line next to the first one.
startPoint+=20;
//draw the second line
mCanvas.drawLine(startPoint, 0, startPoint, getHeight(), mNoteBookPaperLinePaint);
//reset the paint color.
mNoteBookPaperLinePaint.setColor(getResources().getColor(R.color.notebook_paper_horizontal_line_color));
canvas.drawBitmap(mBackgroundBitmap, 0, 0, backPaint);
}
To all who see this question I thought I would add how I solved the problem. What I'm doing is creating a background bitmap in my custom view and then passing that to my hosting fragment. The fragment then sets that bitmap as its background for the containing view group so that when I use the PorterDuff.CLEAR Xfermode, the drawn paths are cleared but the background in the fragment parent remains untouched.
I am making a live wallpaper with a gif image that is put in the raw directory, how can I put the gif in the center of the screen, no matter what device I am using?? I understand why my code right now puts it in the left, because display.getWidth-display.getWidth =0, and same with height, hence (0,0) is in the top left. But what is center?! I cannot seem to figure it out for the life of me. This class is extending WallpaperService.
#Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
super.onSurfaceChanged(holder, format, width, height);
mScaleX = width / (1.5f*mNyan.width());
mScaleY = height / (1.5f*mNyan.height());
Display display = ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
mWidth = (display.getWidth()-display.getWidth());
mHeight = (display.getHeight()-display.getHeight());
nyan();
}
and this is the end where I draw the canvas...
void nyanNyan(Canvas canvas) {
canvas.save();
canvas.scale(mScaleX, mScaleY);
mNyan.setTime(mWhen);
mNyan.draw(canvas, mWidth,mHeight);
canvas.restore();
}
Can anyone help!?! I'm stuck, and I can't move past this. I also tried, without any luck:
void nyanNyan(Canvas canvas) {
canvas.save();
canvas.scale(mScaleX, mScaleY);
mNyan.setTime(mWhen);
mNyan.draw(canvas, mCenterX - mNyan.width() , mCenterY - mNyan.height());
}
As I do not fully understand your code (e.g. where vars like mCenterX are coming from or how they are defined) I can not gurantee the code to run properly without further adjustments.
Assuming that you have access to nyan's width and height (I'll call it nyan.getWidth()) and the canvas' dimensions, then your last mNyan.draw() call should probably look like this:
mNyan.draw(
canvas,
( canvas.getWidth() - nyan.getWidth() ) / 2,
( canvas.getHeight() - nyan.getHeight() ) / 2
);
I need to customize an ImageView so that several images are displayed next to each other like This:
[IMG][IMG]
My original code looks like this:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(img1, 10, 10, null);
canvas.drawBitmap(img2, fourtyfive.getScaledWidth(canvas)+10, 10, null);
}
What I'm trying to do is place the first image, get it's scaled device-specific width then place the second image at an offset based on the width the first.
Any suggestions?