5

I have an RelativeLayout that contains a custom ImageView, the scaleType="centerInside", I load in a bitmap (usually smaller than the imageView). How can I get the top/left position of where the bitmap was drawn? I need to be able addView's on top a positions relative to the bitmap.

   RelativeLayout view = (RelativeLayout) inflater.inflate(R.layout.scroll_scaled, container, false);
ContentImageView image = (ContentImageView) view.findViewById(R.id.base_page);
Bitmap bm = mInterfaceActivity.getPageImage(mPageNumber);
image.setImageBitmap(bm);`

The layout file scrolled_scaled

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
    android:scaleType="centerInside"
    android:id="@+id/base_page"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ff00ff00"
    android:contentDescription="@string/product_page"
    android:src="@android:drawable/ic_menu_report_image" >
</ImageView>
</RelativeLayout>
user1603721
  • 188
  • 3
  • 12

4 Answers4

3

You'll need to do the math yourself using the bounds of the Drawable.

ImageView test = (ImageView) findViewById(R.id.base_page);
Rect bounds = test.getDrawable().getBounds();
int x = (test.getWidth() - bounds.right) / 2;
int y = (test.getHeight() - bounds.bottom) / 2;

First we calculate the space in the View that is not being used by the image. Then since it is centered the extra space is evenly distributed before and after the image so it is draw half of that length into the View.

These numbers are relative to the location of the View but you can add the views X and Y if you need you.

Fr33dan
  • 4,227
  • 3
  • 35
  • 62
  • its not working man :( I have got null pointer exception on test.getdrable().getBounds() – Ahmad Arslan Sep 30 '14 at 10:36
  • @ArslanAhmad It seems likely to me that you are encountering an error that is outside the scope of this question. I suggest you start a new question to determine why that was null. Before doing so I'd recommend you actually determine which part of that command is null (does `test == null`, or `test.getDrawable() == null`) – Fr33dan Sep 30 '14 at 13:10
3

This method returns the bounds of image inside imageView.

/**
 * Helper method to get the bounds of image inside the imageView.
 *
 * @param imageView the imageView.
 * @return bounding rectangle of the image.
 */
public static RectF getImageBounds(ImageView imageView) {
    RectF bounds = new RectF();
    Drawable drawable = imageView.getDrawable();
    if (drawable != null) {
        imageView.getImageMatrix().mapRect(bounds, new RectF(drawable.getBounds()));
    }
    return bounds;
}
Nabin Bhandari
  • 15,949
  • 6
  • 45
  • 59
1

UPDATE 2: getX and getY will return 0 if you're using unspecified width and height (e.g. wrap_content). Instead of iv.getX() and iv.getY() replace that with the answer to this question: Getting View's coordinates relative to the root layout then add the bounds of the image to those values.

You can do this by adding the ImageView's position to the top left bound of the drawable inside. Something like this:

ImageView iv = (ImageView)findViewById(R.id.image_view);
Drawable d = iv.getDrawable();
Rect bounds = d.getBounds();
int top = iv.getY() + bounds.top;
int left = iv.getX() + bounds.left;

UPDATE: For images that are scaled, you'll have to multiply the top and left coords by the image scale to get more accurate positioning. You can do that like this:

Matrix m = iv.getImageMatrix();
float[] values = new float[9];
m.getValues(values);
float scaleX = values[Matrix.MSCALE_X];
float scaleY = values[Matrix.MSCALE_Y];

Then you'd have to multiply top by scaleY and the left by scaleX.

Community
  • 1
  • 1
Michael Celey
  • 12,645
  • 6
  • 57
  • 62
  • Did not work. I'm thinking my ViewGroup hasn't completed inflating at this point so the values for "top" and "left" are both zero. – user1603721 Sep 11 '12 at 15:31
  • See updated answer for better method of getting the view's top and left coords. – Michael Celey Sep 11 '12 at 15:44
  • Your answer assumes the bounds will have the top and left value to match where they are drawn relative to the `View`. This is not the case. They are always 0. – Fr33dan Sep 11 '12 at 15:47
  • They're not always 0 for all cases. I use the top and left bounds of an image in an ImageView for limiting image translation in pinch to zoom. The code for that, which works, can be found here: http://stackoverflow.com/questions/4227451/android-imageview-setting-drag-and-pinch-zoom-parameters/11615173#11615173 It's possible in this case that onLayout hasn't been called yet so the bounds are 0. If that's the case then delay getting the position until after onLayout has been called. – Michael Celey Sep 11 '12 at 15:51
  • Interesting, because I tested that for this question from a button so it onLayout had been performed. I wonder why the difference. – Fr33dan Sep 11 '12 at 15:57
  • Fr33dan is correct, the top/left are still zero. I'm loading the 'base_page' and wanting to put its overlay on top. MCeley I could wait till the onLayout has been called, but how would I know when this happened? – user1603721 Sep 11 '12 at 16:57
  • The easiest way would be to override the control and just catch the event by overriding onLayout. A less elegant solution would be to create a handler and post a Runnable to handle the overlay with a delay of half a second. That's usually enough time for the layout to set itself up but, like I said, it's not very elegant and could fail on slower devices. I get my bounds to work by loading the image in an AsyncTask, setting the image in onPostExecute, and allowing pinch to zoom starting after that. The task takes less than a second to complete and I fade the image in to hide it. – Michael Celey Sep 11 '12 at 17:06
0

Ended up with a two part solution, based on the feedback and a bit of retry.

I created the subviews an added them to the RelativeLayout in "approximate" position, but as View.INVISIBLE.

I super-classed the RelativeLayout ViewGroup and in the onLayout I walked the list of child views and put them in the "proper" place as I now had the RelativeLayout self-aware of its expanded size.

Seems clunky, but it works.

Thanks to all for the suggestions, my solution was taking pieces of everyones advice.

user1603721
  • 188
  • 3
  • 12