I want to get the position of my ImageView programmatically. By position, I mean the distance in pixel from top of the screen to that ImageView. I have tried every other solution posted in stackoverflow but it's not working for me. My minimum API level is 8.
These are the codes I have tried-
ImageView image = (ImageView) findViewById(R.id.imageView1);
1) image.getTop();
2) private int getRelativeTop(View myView) {
if (myView.getParent() == myView.getRootView())
return myView.getTop();
else
return myView.getTop() + getRelativeTop((View) myView.getParent());
}
3) image.getLocationOnScreen(int[] locaiton);
You need to wait for the callback when the layout has been placed with children views. This is the listener you need to add to your root view in order to calculate the coordinates for your image. Otherwise it will return 0.
getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
public void onGlobalLayout() {
getViewTreeObserver().removeGlobalOnLayoutListener(this);
int[] locations = new int[2];
image.getLocationOnScreen(locations);
int x = locations[0];
int y = locations[1];
}
});
Use View.getLocationOnScreen() or getLocationInWindow() BUT ONLY after the view has been layout. getTop(), getLeft(), getBottom() and getRight() return the position relative to its parent.
Glide.with(this)
.asBitmap()
.apply(requestOptions)
.load(url)
.placeholder(R.mipmap.img_place_holder)
.apply(new RequestOptions().override(myImage.getMeasuredWidth(), myImage.getMeasuredHeight()))
.into(new SimpleTarget<Bitmap>() {
#Override
public void onResourceReady(Bitmap bitmap,
Transition<? super Bitmap> transition) {
// TouchImageView myImage1 = findViewById(R.id.image_zoom_poll_card);
img_zoomIn.setVisibility(View.VISIBLE);
myImage.setImageBitmap(bitmap);
getBitmapPositionInsideImageView(myImage, img_zoomIn);
}
});
Related
I'm using Glide to load images on Scale ImageView - it is a custom view with pan and zoom gestures. I should pass Bitmap object to this custom view in order to set picture.
So I can use Glide's .asBitmap() with SimpleTarget:
private SimpleTarget target = new SimpleTarget<Bitmap>() {
#Override
public void onResourceReady(Bitmap bitmap, GlideAnimation glideAnimation) {
scaleImageView.setImage(ImageSource.bitmap(bitmap));
}
};
private void loadImageSimpleTarget() {
Glide
.with(context)
.load(url)
.asBitmap()
.into(target);
}
This code snippet works well, but I will get fullsize Bitmap, which can lead to OutOfMemoryErrors. Also I could specify desired Bitmap size on constructor like this: ...new SimpleTarget<Bitmap>(250, 250)..., but I would have to manually calculate dimensions.
Is there a possibility to pass view (instance of CustomView) to Glide's request, so dimensions will calculated automatically and receive Bitmap object as a result?
Continuing the discussion from the comments, you get 0 for width and height when calling it from onCreateView. However, you can set a listener to be notified when the bounds of the view are actually calculated and then you can get the real width and height by calling getWidth or getHeight:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// ...
// your other stuff
// ...
// set listener
customView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
Log.d("debug", "width after = " + customView.getHeight());
// pass the width and height now that it is available
target = new SimpleTarget<Bitmap>(customView.getWidth(), customView.getHeight()) {
#Override
public void onResourceReady(Bitmap bitmap, GlideAnimation glideAnimation) {
scaleImageView.setImage(ImageSource.bitmap(bitmap));
}
};
// remove listener, we don't need to be notified again.
customView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
}
I have a question regarding the process of resizing an ImageView Have on orientation changes.
I have to place a bitmap on the top of an image view. (Basically a marker placed by the user when touching it). On orientation change, I store the relatives position of the marker and intent to restaure it when the image is re-displayed.
for now I do it this way :
on restauration I call this :
handler.post(setCollectedAnswersRunnable);
refering to this :
Runnable setCollectedAnswersRunnable = new Runnable() {
#Override
public void run() {
if (iv.getMeasuredHeight() != 0) {
int x = Math.round(coordinateCollectedAnswer.x * iv.getMeasuredWidth() / (float) question.getImage().getWidth());
int y = Math.round(coordinateCollectedAnswer.y * iv.getMeasuredHeight() / (float) question.getImage().getHeight());
selectedX = x;
selectedY = y;
addPointerImageView(x, y);
} else {
handler.postDelayed(this, 330);
}
}
};
The important thing to note is this works very well when I go from a larger ImageView to a smaller one ie when passing from landscape to portrait.
But in the other way, it doesn't. The ImageView seems to be restaured first with the same size and then scaling up witch mess my marker up. So I certainely could check if it's the same size as in portrait in addition to the !=0 condition in my runnable. but first I'm not very proud of that way to do it, I'd rather be notified when the ImageView get it's final sizing. And I would prefer not passing the viewsize in my state bundle.
Is there a simpler way to achieve this ?
By the way I load the ImageView this way :
Picasso.with(iv.getContext())
.load(AppConstants.SERVER_URL + "/api/" + question.getImage().getUrl())
.config(Bitmap.Config.RGB_565)
.into(new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
iv.setImageBitmap(bitmap);
iv.setAdjustViewBounds(true);
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
});
I´ve got a SurfaceView that keeps to be square. i´ve notice thatn when android runtime is doing all the stuff for layout will measure the component again and again and you never can tell when is the last time and the number of executions does not seem to be related to the amount of components on the screen, it is not random but maybe has something to do with the layout constraints of all the stuff around.
here´s my class overriding the measure ion order to keep square:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int w = MeasureSpec.getSize(widthMeasureSpec);
int h = MeasureSpec.getSize(heightMeasureSpec);
int size = w;
if (w < h) {
setMeasuredDimension(widthMeasureSpec, widthMeasureSpec);
} else {
size = h;
setMeasuredDimension(heightMeasureSpec, heightMeasureSpec);
}
if (h > 0 && squareSurfaceViewListener != null) {
squareSurfaceViewListener.onChangeSize(size);
}
}
So I´d inherit the imageview, detect the change and reload the image.
Using picasso it´ll cache the stuff but, maybe, you could forget about that and call for a new load each time the component is measured or add some kind of observer in the middle.
Im trying to find a way to measure an ImageView after an image has been loaded into it using Glide or Picasso (or anything really). Basically, im trying to layout other views on top of the image in certain positions, but need the final ImageViews dimensions to do so accurately.
Im not sure what the best layout to use to try and do this would be, but im currently using this:
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/viewingImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</FrameLayout>
and loading the image into viewingImageView. These are both inside a root FrameLayout as well but I dont think that matters.
This is my latest attempt, but as commented, using .getWidth() and .getHeight() on the ImageView return 0. The width/height of the resource returns the size of the original image.
Glide
.with(this)
.load(entry.getImageUrl())
.asBitmap()
.into(new SimpleTarget<Bitmap>() {
#Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
mImageView.setImageBitmap(resource);
int width = mImageView.getMaxWidth(); //prints 0
int height = mImageView.getMaxHeight(); //prints 0
int resw = resource.getWidth(); //returns original image width
}
});
So how can I get the image loaded and then measure the ImageView (or its wrapping FrameLayout) after the image has been loaded? Or if possible, measuring the dimensions of the finally laid out image would be better, as I know the image doesnt always fill the entire ImageView depending on scale types. I'm open to any solutions, the above is only what ive tried so far.
You should wait for the view to be drawn, you can use OnGlobalLayoutListener like this
ViewTreeObserver vto = mImageView.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
this.mImageView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
// Get the width and height
int width = mImageView.getMeasuredWidth();
int height = mImageView.getMeasuredHeight();
}
});
Create a custom class with image view.
Use this onMeasure in the image view we can get the height and width
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mNeedsInitialScale) { // Set by setImage when a new image is set
// The measured width and height were set by super.onMeasure above
setInitialScale(getMeasuredWidth(), getMeasuredHeight());
mNeedsInitialScale = false;
}
}
m using RecyclerView with StaggeredGrid (spanCount is variable). Each GridItem (a CardView) contains an a square ImageView. What i want is to load an Image from my backend with desired width and height to exactly fit an ImageView inside a CardView. Any suggestions i can achieve this? Code example is below:
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
Picasso.with(context)
.load(String.format("http://mybackend.com/image/w_%d,h_%d/%s",
holder.image.getMeasuredWidth(), // This returns 0, but i want here a real width
holder.image.getMeasuredWidth(),
myCollection.get(position).getImagePid()))
.tag(context)
.placeholder(R.drawable.placeholder_logo)
.into(holder.image);
In 2 words: somehow i need to get imageView dimensions (width) before my ViewHolder is bound.
Have you looked into using .fit() ? I believe that will resize the image to exactly fit an ImageView.
You can use ViewTreeObserver:
final int width = holder.image.getMeasuredWidth();
if (width > 0) {
Picasso.with(context)
.load(String.format("http://mybackend.com/image/w_%d,h_%d/%s",
holder.image.getMeasuredWidth(), // This returns 0, but i want here a real width
holder.image.getMeasuredWidth(),
myCollection.get(position).getImagePid()))
.tag(context)
.placeholder(R.drawable.placeholder_logo)
.into(holder.image);
} else {
holder.image.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
holder.image.getViewTreeObserver().removeGlobalOnLayoutListener(this);
Picasso.with(context)
.load(String.format("http://mybackend.com/image/w_%d,h_%d/%s",
holder.image.getMeasuredWidth(), // This returns 0, but i want here a real width
holder.image.getMeasuredWidth(),
myCollection.get(position).getImagePid()))
.tag(context)
.placeholder(R.drawable.placeholder_logo)
.into(holder.image);
}
});
}
So I have an imageView inside a listview (loaded by a Loader) and the width is set to match_parent. When I want to set the imageview bitmap I use the height and the width of the imageView to load the best size bitmap. The issue is the imageView size is sometime not known in the Loader bindView (not measured yet?). How could I get the width of bitmap every time in this case ?
#Override
public void bindView(View view, final Context context, Cursor cursor) {
ImageView iv = (ImageView) (ImageView) view.findViewById(R.id.image);
....
bitmap = BitmapHelper.decodeSampledBitmapFromFile( new File(file), iv.getWidth(), iv.getHeight());
imageView.setImageBitmap(bitmap);
}
You have to wait until the view is initialised, then get the dimensions. Try using a ViewObserver like so:
ViewTreeObserver viewTreeObserver = YOURLAYOUT.getViewTreeObserver();
if (viewTreeObserver.isAlive()) {
viewTreeObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
public void onGlobalLayout() {
YOURLAYOUT.getViewTreeObserver().removeGlobalOnLayoutListener(this);
//do some things
//YOURLAYOUT.getWidth() should give a correct answer
}
});
}
Hope that helps :)