how to get bounds of a scaled view? - android

It seems that setScaleX or setScaleY don't actually change left,top,right,bottom properties. getX and getY remain unchanged too.
So if I scale a view whats the easiest way to get 4 corner coordinates of the newly scaled view?
I tried getHitRect but that doesn't give me the right answer. I am trying to avoid manually calculating the new bounds based on existing transformations (rotation and scale with pivots factored in).

After exploring the view api, it looks like there is no direct API method that does this.
However you can easily get the new points by grabbing the transform matrix of the view and using that to get the new bounds.
Something like this:
Matrix m = view.getMatrix();
Rect bbox = new Rect();
view.getDrawingRect(bbox);
m.mapRect(bbox);
If you want to operate on (x,y) coordiantes directly there is a matrix.mapPoints that will achieve the same result.

I believe if you get the width and height and multiply it by the scales, you'll get the scaled width and height.
int scaledWidth = getWidth() * getScaleX();
int scaledHeight = getHeight() * getScaleY();
int newLeft = getLeft() + (scaledWidth / 2);
int newRight = newLeft + scaledWidth;
int newTop = getTop() + (scaledHeight / 2);
int newBottom = newTop + scaledHeight;
This is assuming that you scaled with a pivot x and y at the center of the view. Things gets far more complicated if you have pivots in strange areas.

Related

Center of the view after rotation or scale

I am trying to find the center of a view. For non-rotated view the value is correct, but for rotated view it's not correct as the centre(0,0) is rotating. In the case of scaling the width and height is keep constant even after zooming
I am using the following formula to calculate the center.
int[] location = new int[2];
childView.getLocationOnScreen(location);
int xLocation = location[0] + childView.getWidth() / 2;
int yLocation = location[1] + childView.getHeight() / 2
from getGlobalVisibleRect i get the rect of visible part only
https://developer.android.com/reference/android/view/View#getHitRect(android.graphics.Rect)
This method will return you Rect(considering rotation and scale) within its parent view

Android Canvas.drawCircle in the center of the screen

I am using Canvas.drawCircle to draw a circle in Android laout.
Method gets 3 parameters - first two are position - x and y.
Is it possible to skip hardcoded position of the circle and draw it centered ?
Following code can be used to get the width and height of the screen.
int width = this.getWidth();
int height = this.getHeight();
To draw circle in the middle of screen you can call :
Canvas.drawCircle(width/2, height/2)
You can paint a circle centered to the screen like this:
Display disp = ((WindowManager)this.getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
canvas.drawCircle(disp.getWidth()/2, disp.getHeight()/2, radius, paint);
Assuming you are extending the View class:
int CentreX = (this.getWidth() / 2);
int CentreY = (this.getHeight() / 2);

How to get the X Y coordinates and pixel size of a TextView?

Given a TextView, is it possible to know at runtime the X and Y coordinates of where it is drawn?
Is it also possible to know the size (width/length) in pixels?
There are getLeft(), getTop(), getWidth(), getHeight() methods for a view, it works for textView too. for more information , see the following link...
getLeft() and getTop() will return you the starting x,y co-ordinates.
http://developer.android.com/reference/android/view/View.html
Coordinates relative to parent
int x = textView.getLeft();
int y = textView.getTop();
Absolute coordinates
int[] location = new int[2];
textView.getLocationOnScreen(location);
int x = location[0];
int y = location[1];
See this answer for more.
Pixel size
int width = textView.getWidth();
int height = textView.getHeight();
Notes
If you are getting (0,0) it could be because you are getting the relative coordinates related to the parent layout (and it is sitting in the top left corner of the parent). It could also be because you are trying to get the coordinates before the view has been laid out (for example, in onCreate()).

Scrollable ImageView Android Problem (overscrolling)

I got my image to at least SCROLL, but I don't want it to scroll past the image itself. I have variables called maxLeft, maxRight, etc that I have that I currently just set to
ImageView img = (ImageView)findViewById(R.id.mapimg);
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int maxX = (int)????;
int maxY = (int)????;
// set scroll limits
final int maxLeft = (maxX * -1);
final int maxRight = maxX;
final int maxTop = (maxY * -1);
final int maxBottom = maxY;
I've been messing around with what I could in place of the question marks I put there, but I seem to be stuck, especially when I try on different emulators. Any help would really be appreciated! Thanks
If I understand your question correctly, you want to extend ImageView to add scrolling. If that's the case, you don't want to use getWindowmanager() as that returns the dimensions of the entire screen (including the title bar). Rather, you want to extend ImageView and get the view's dimensions from onMeasure. You can check out my answer here where I added zoom functionality and panning to ImageView.
I used setImageMatrix and postTranslate to set a matrix equal to the image and move it. To track the image's location, I used the following:
float f[] = new float[9];
matrix.getValues(m); //see matrix documentation. inserts matrix values into f.
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
Float x and y will track the top left corner of the image. Make sure if the next event will cause the image to scroll out of bounds, you adjust postTranslate to equal the border of the image. The answer i linked above should give you a good place to start, and if you also want zoom functionality, then you're in luck, because you don't have to do any additional work.

Android Canvas Coordinate System

I'm trying to find information on how to change the coordinate system for the canvas. I have some vector data I'd like to draw to a canvas using things like circles and lines, but the data's coordinate system doesn't match the canvas coordinate system.
Is there a way to map the units I'm using to the screen's units?
I'm drawing to an ImageView which isn't taking up the entire display.
If I have to do my own calculations prior to each drawing call, how to I find the width and height of my ImageView?
The getWidth() and getHeight() calls I tried seem to be returning the entire canvas size and not the size of the ImageView which isn't helpful.
I see some matrix stuff, is that something that will work for me?
I tried to use the "public void scale(float sx, float sy)", but that works more like a pixel level zoom rather than a vector scale function by expanding each pixel. This means if the dimensions are increased to fit the screen, the line thickness is also increased.
Update:
After some research I'm starting to think there's no way to change coordinate systems to something else. I'll need to map all my coordinates to the screen's pixel coordinates and do so by modifying each vector. The getWidth() and getHeight() seem to be working better for me now. I can say what was wrong, but I suspect I can't use these methods inside the constructor.
Thanks for the reply. I have pretty much given up on getting this to work in the way I think it should. Of course how I think things should happen isn't how they do happen. :)
Here's basically how it works, but it seems to be off by a pixel in some cases and the circles seem to be missing sections when things land on some boundary conditions I have yet to figure out. Personally I think this is unacceptable to be inside application code and should be in the Android libraries... wink wink, nudge nudge if you work for Google. :)
private class LinearMapCanvas
{
private final Canvas canvas_; // hold a wrapper to the actual canvas.
// scaling and translating values:
private double scale_;
private int translateX_;
private int translateY_;
// linear mapping from my coordinate system to the display's:
private double mapX(final double x)
{
final double result = translateX_ + scale_*x;
return result;
}
private double mapY(final double y)
{
final double result = translateY_ - scale_*y;
return result;
}
public LinearMapCanvas(final Canvas canvas)
{
canvas_ = canvas;
// Find the extents of your drawing coordinates:
final double minX = extentArray_[0];
final double minY = extentArray_[1];
final double maxX = extentArray_[2];
final double maxY = extentArray_[3];
// deltas:
final double dx = maxX - minX;
final double dy = maxY - minY;
// The display's available pixels, accounting for margins and pen stroke width:
final int width = width_ - strokeWidth_ - 2*margin_;
final int height = height_ - strokeWidth_ - 2*margin_;
final double scaleX = width / dx;
final double scaleY = height / dy;
scale_ = Math.min(scaleX , scaleY); // Pick the worst case, so the drawing fits
// Translate so the image is centered:
translateX_ = (int)((width_ - (int)(scale_*dx))/2.0 - scale_*minX);
translateY_ = (int)((height_ - (int)(scale_*dy))/2.0 + scale_*maxY);
}
// wrappers around the canvas functions you use. These are only two of many that would need to be wrapped. Annoying and error prone, but beats any alternative I can find.
public void drawCircle(final float cx, final float cy, final float radius, final Paint paint)
{
canvas_.drawCircle((float)mapX(cx), (float)mapY(cy), (float)(scale_*radius), paint);
}
public void drawLine(final float startX, final float startY, final float stopX, final float stopY, final Paint paint)
{
canvas_.drawLine((float)mapX(startX), (float)mapY(startY), (float)mapX(stopX), (float)mapY(stopY), paint);
}
...
}
You can scale the canvas co-ordinates to your own units using the preScale() method of the canvas' matrix. Be aware though that this also scales the Paint's stroke width, which may not be what you want.
The only way I know of to do custom vector graphics on the fly in Android is to draw everything into an image file and then put that into an ImageView. I'm not sure I understand exactly what you are asking, but if the only issue is scaling, the ImageView will scale whatever image it is given to its own size using android:scaleType="center" as a property of the ImageView.
As far as changing the coordinate system, I doubt that is possible (although I haven't researched it). It might be fairly trivial to write a function that would map your data's system to the standard Android coordinate system, though.

Categories

Resources