Hi I'm trying to make a square 8x8 grid on a canvas. I've managed to make a grid, but it turns out to be rectangular, but for the game I'm making it needs to be square. How do I change my code to make it a square grid scaled to the phone.
float testWidth = (getWidth() - 16f) / 9f;
float testHeight = (getHeight() - 16f) / 9f;
for (int i = 0; i < 9; i++) {
canvas.drawLine(padding + testWidth* i, padding, padding
+ testWidth * i, testHeight* 8+padding, dark);
canvas.drawLine(padding, padding+testHeight* i, testWidth* 8
+ padding, padding+testHeight* i, dark);
}
EDIT: I can now make a square grid, but I don't know how to center the grid into the middle of the phone
You'll want to take the shortest of the two (Width or Height) and use that to build the grid upon. (So your grid can fit on the screen)
Something like...:
float gridSide = 0;
if (getWidth() > getHeight()) {
gridSide = getHeight();
}
else {
gridSide = getWidth();
}
Simpler logic provided by appsroxcom:
float gridSide = Math.min(testWidth(), testHeight());
Use gridSide as the total length and total width of the grid
Related
On scroll, I want to rotate and translate these list items in a way that they still are around in a circular manner. I have made a custom view and over ride these methods with this rotation and translation as used Here. But rotations are a bit weird and non circular.
This is what I want to achieve
#Override
protected void dispatchDraw(Canvas canvas) {
canvas.save();
int top = getTop();
float rotate = calculateAngle(top, recyclerViewHeight);
Matrix m = canvas.getMatrix();
m.preTranslate(-2 / getWidth(), -2 / getHeight());
m.postRotate(rotate);
m.postTranslate(2 / getWidth(), 2 / getHeight());
canvas.concat(m);
super.dispatchDraw(canvas);
canvas.restore();
}
private float calculateAngle(int top, float height) {
float result = 0f;
float fullAngleFactor= 60f;
if (top < height / 2f) {
result = (top - (height / 2f)) / (height / 2f) * fullAngleFactor;
} else if (top > height / 2f) {
result = (top - (height / 2f)) / (height / 2f) * fullAngleFactor;
}
return result;
}
I used this library to achieve same behavior. No need to create any custom view and override onDraw() or onDispatchDraw(). I used this layout manager configuration:
layoutManager = new CircleLayoutManager.Builder(this)
.setRadius(900)
.setAngleInterval(30)
.setDistanceToBottom(-350)
.setGravity(CircleLayoutManager.LEFT)
.build();
I'm new to work with Canvas in Android. I have the following code:
textGreetingsPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textGreetingsPaint.setARGB(255, 0, 0, 0);
textGreetingsPaint.setTextAlign(Paint.Align.CENTER);
textGreetingsPaint.setTypeface(Typeface.DEFAULT_BOLD);
textSubGreetingsPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textSubGreetingsPaint.setARGB(255, 0, 0, 0);
textSubGreetingsPaint.setTextAlign(Paint.Align.CENTER);
textSubGreetingsPaint.setTypeface(Typeface.DEFAULT_BOLD);
final float startText = (canvas.getWidth() / 2);
final float endText = ((canvas.getHeight() / 2) - ((textGreetingsPaint.descent() + textGreetingsPaint.ascent()) / 2));
final float endSubText = endText + 150;
textGreetingsPaint.setTextSize(determineMaxTextSize("Good night,", (float) (getWidth() / 1.2)));
textSubGreetingsPaint.setTextSize(determineMaxTextSize("how was your day?", (float) (getWidth() / 1.2)));
canvas.drawText("Good night,", startText, endText, textGreetingsPaint);
canvas.drawText("how was your day?", startText, endSubText, textSubGreetingsPaint);
private int determineMaxTextSize(String str, float maxWidth) {
int size = 0;
Paint paint = new Paint();
do {
paint.setTextSize(++size);
} while (paint.measureText(str) < maxWidth);
return size;
}
It basically insets two texts in the center of the canvas:
Good night,
how was your day?
I have the following issue - currently I set the endSubText to be endText + 150, meaning I will have the Good night message in the center of the screen and the how was your day? message under it, meaning I will have something like (note the empty rows):
>
>
> Good night,
>
> how was your day?
>
I want both of the messages to be in the center of the canvas, something like:
>
> Good night,
>
> how was your day?
>
Also, I set endSubText to be endText + 150 with const 150 but it could be different in each screen. How to keep a valid margin between those two texts?
To sum up the questions:
How to set the texts in the center of the canvas?
How to keep valid margin between texts?
I have a rectangle with known size and position. (flag)
I have to fill this rectangle with 4 other rectangles. (stripes)
Each stripe must have 1/4 of the total width of the flag and his position is near the previous.
I have to draw this stripes with a random angle that goes from 0° to 90°.
0° = Vertical stripes (stripe width = flag width / 4)
90° = Horizontal stripes (stripe width = flag height / 4)
How can I calculate the width of each stripe for other angles?
int stripes = 4;
RectF rect = new RectF(0, 0, 100f, 75f);
float angle = new Random.nextInt(90);
float stripeSize;
if (angle == 0) {
stripeSize = rect.width() / stripes;
} else if (angle == 90) {
stripeSize = rect.height() / stripes;
} else {
stripeSize = ?
}
canvas.save();
canvas.rotate(angle, rect.centerX(), rect.centerY());
float offset = 0;
for (int i = 0; i < stripes; i++) {
if (angle == 0) {
reusableRect.set(offset, rect.top, offset + stripeSize, rect.bottom);
} else if (angle == 90) {
reusableRect.set(rect.left, offset, rect.right, offset + stripeSize);
} else {
reusableRect.set(?, ?, ?, ?);
}
canvas.drawRect(reusableRect, paint);
offset += stripeSize;
}
canvas.restore();
Let's pretend you have one stripe. Depending on the angle, the stripe width is going to be a value between the shorter dimension (the height in your case) and the longer dimension (the width in your case). The formula for the stripe width calculation should look something like this:
height + ((width - height) * ?)
where ? varies between 0 and 1 based on the angle of rotation. To me that sounds like the sine function might be a good candidate: sine(0) = 0 and sine(90) = 1. You can use Math.sin(), but be aware that the argument it takes is in radians, not degrees, so you need to use Math.toRadians() on your angle first. Then just divide by the number of stripes:
double radians = Math.toRadians(angle);
float stripeTotal = height + ((width - height) * Math.sin(radians));
float stripeWidth = stripeTotal / 4; // or however many stripes you have
If it's not perfect, you can adjust the formula. One last point, since these values only need to be calculated once, I would do that separately every time the angle changes (if it ever changes), not inside of onDraw().
I'm creating a grid for my game, but I want the size of the grid to vary, depending on the phone's dimensions. When I run the code (note: I removed a lot from ondraw, only concerned about lines atm), it seems like the size of the grid is the same on both my HTC Desire and Wildfire - Which makes the grid look perfect on the wildfire, but there is a massive space below the grid on the desire- prob cos the desire screen is bigger? What I'm asking is...
How do i make the grid scale to the phones dimensions - I want the grid to take up the majority of the phone's screen, but have a margin.Thanks
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
padding = 8;
for (int i = 0; i < 9; i++) {
canvas.drawLine(padding + testWidth* i, padding, padding
+ testWidth * i, testWidth* 8+padding, dark);
canvas.drawLine(padding, padding+testWidth* i, testWidth* 8
+ padding, padding+testWidth* i, dark);
}
}
}
public void onSizeChanged(int w, int h, int oldw, int oldh) {
testWidth= w / 9f;
testHeight = h / 9f;
border = w;
getRect(selX, selY, selRect);
super.onSizeChanged(w, h, oldw, oldh);
}
EDIT: I can now make a grid that scales to the phone's dimensions, however it is a rectangular grid. It looks kind of silly, I need a square one. Maybe I should make padding bigger if the screen is bigger?
This answer is supplementing Nicolas Brown's answer, but you might identify your problem a little better by introducing some more local variables. For example, your original loop could be replaced by:
padding = 8;
for (int i = 0; i < 9; i++) {
int xposition = padding + testWidth * i;
int yposition = padding + testHeight * i;
// Horizontal line
canvas.drawLine(padding, yposition, padding + testWidth * 8, yposition, dark);
// Vertical line
canvas.drawLine(xposition, padding, xposition, padding + testHeight * 8, dark);
}
Also, as Nicolas suggested, you are not accounting for the 8 pixel padding. So, in your onSizeChanged you want:
testWidth = (w - 16f) / 9f;
testHeight = (h - 16f) / 9f;
The problem is a typing error. Seems like you've copied and pasted testWidth and forgot to change it to. Try this:
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
padding = 8;
for (int i = 0; i < 9; i++) {
canvas.drawLine(padding + testWidth* i, padding, padding
+ testWidth * i, testWidth* 8+padding, dark);
canvas.drawLine(padding, padding+testHeight* i, testHeight* 8
+ padding, padding+testHeight* i, dark);
}
}
RelativeLayout container = (RelativeLayout) findViewById(R.id.sc);
I've then added my canvas class to this container, but my grid is in the top left corner, i.e there is big space below the grid and I would like to know how to center the grid. This is my code to draw the grid.
float testWidth = (getWidth() - 16f) / 9f;
float testHeight = (getHeight() - 16f) / 9f;
for (int i = 0; i < 9; i++) {
canvas.drawLine(testWidth* i, 0 , testWidth * i, testWidth* 8, dark);
canvas.drawLine(0, testWidth* i, testWidth* 8, testWidth* i, dark);
}
Do I use gravity/margin in the xml file?
Check if it works for you.
float testWidth = (getWidth() - 16f) / 9f;
float testHeight = (getHeight() - 16f) / 9f;
float size = Math.min(testWidth, testHeight);
float offsetW = (getWidth() - size*8) / 2;
float offsetH = (getHeight() - size*8) /2;
for (int i = 0; i < 9; i++) {
canvas.drawLine(offsetW + size*i,
offsetH,
offsetW + size*i,
offsetH + size*8,
dark);
canvas.drawLine(offsetW,
offsetH + size* i,
offsetW + size* 8,
offsetH + size* i,
dark);
}
The code is not tested. The idea is to provide horizontal and vertical offset to the grid.
Use gravity = "center" in the XML file of the PARENT view. In that case, all children of the view will be centered.