I have an action bar, text view and an imageview in my layout. Imageview has widht and height match_parent. Imageview takes the rest of the space left in the view. I want to set a bitmap to the view but that is too huge. So I first want to get the width and height of the imageview and use them to scale down the bitmap and then set it the imageview. I have tried getting width and height of the imageview in OnCreate, but that is coming as 0,0 probably because imageview has not been created yet.
Please suggest how to do it ?
Thanks.
you need to use the ViewTreeObserver onPreDrawListener, this gets called after everything is measured and right before it is drawn
ImageView iv = (ImageView)findViewBYId(R.id.imageview);
ViewTreeObserver observer = iv.getViewTreeObserver()
observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw(){
observer.removeOnPreDrawListener(this);
//do your stuff here
}
}
If you're only interested in layout changes of the particular ImageView, then a layout listener on it might be the way to go:
imageView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
// do stuff
}
});
Have you tried this link?
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html#load-bitmap
There is basically such a method especially used for preventing memory problems because of large bitmaps. Your first read the dimensions and then laod the scaled sample.
Related
Let's say we have a main_activity.xml layout that defines all dimensions in a relative manner -- constraints, percentages, and guidelines (that are percentages)... no "static" dp.
But in MainActivity.java, we programatically create some subviews, and we want to define their height/width dimensions as relative to existing views.
We do not know the dimensions or density of the device so, so nor do we know the (actual integer) dimensions of any view before run-time...
But we can say something like:
int heightDimensionForNewView = (int) (someAlreadyInflatedView.getHeight() / 7f)
But what if, under certain circumstances, these "new" views need to be displayed immediately at app start-time?
So, the question:
In the Android Activity life-cycle, when is the earliest point at which you can (somehow) safely query (something) for actual/finalized/guaranteed layout dimensions? And what is that something and somehow?
I haven't been able to find an override method such as "onContentViewInflated()" and there is no onCreateView() method like there is in Fragments.
I've also tried Logging from inside onStart() and onResume() but the dimension results are always "0," presumably because they haven't been inflated yet.
I know that any given View can get its own dimensions in onMeasure(), but then you would have make a static variable in MainActivity in order to assign it and use it from there... or some way of sending that information from the View back to the Activity.
What am I missing? I just want to be able to get the number somehow from inside MainActivity itself.
My suggestions are:
view.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
#Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
int oldWidth = oldRight - oldLeft; // right exclusive, left inclusive
if( v.getWidth() != oldWidth ) {
// width has changed
}
}
});
and
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// View has laid out
// Remove the layout observer if you don't need it anymore
view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});
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;
}
}
I've implemented a gallery using the recyclerview and I've added an onLayoutChangeListener to the viewholder so that once the layout is calculated, the height of the imageview is changed to match the image's aspect ratio. It works fine when first opening the activity, rotating the device or unlocking the screen, but when coming back from another activity it doesn't work. The method is executed, but the imageview does not change. Any idea of what could be causing this?
image.addOnLayoutChangeListener(new View.OnLayoutChangeListener(){
#Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
ImageView img = (ImageView) v;
Bitmap bm = ((BitmapDrawable) img.getDrawable()).getBitmap();
img.getLayoutParams().height = Utils.scaledHeight(bm.getWidth(), bm.getHeight(), img.getWidth());
img.removeOnLayoutChangeListener(this);
}
});
The debugger shows the correct height being set, but the displayed imageview is not what it should be.
Correct Image
Incorrect Image
It looks as though you're just trying to get the proper aspect ratio on an ImageView.
ImageView has a property called adjustViewBounds. If you have a specific layout_width like match_parent or a dp value, you can specify wrap_content for the layout_height and set android:adjustViewBounds="true". This will cause the ImageView to automatically respect the aspect ratio of the image when measuring for the height.
I have an ImageView which has layout_width of fill_parent. I want to get the width of this ImageView in order to calculate the size of the thumbnail. The problem is that imageView.getWidth() and imageView.getHeight() both return 0 because the layout hasn't been sat yet.
My question is, does the ImageView has some kind of SizeChanged event or something of the kind? How do I react as soon as the ImageView width has been established?
Update:
I solved my problem this way. As I actually only needed the width of the ImageView which is set to fill_parent, what I actually needed was the device window size:
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int targetW = metrics.widthPixels;
You can hook into a number of View tree events using a ViewTreeObserver. Specifically, either an OnGlobalLayoutListener or an OnPreDrawListener should work for you depending on what you are doing with the size.
Here's an example of using a ViewTreeObserverto get a View's width once everything has been laid out:
final ImageView myImageView = (ImageView) findViewById(R.id.image);
final ViewTreeObserver observer = myImageView.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int height = myImageView.getHeight();
// Do something with the height
// Remove the layout listener so we don't waste time on future passes
observer.removeOnGlobalLayoutListener(this);
}
});
According to this post's answer:
ImageView.getWidth() returns 0
You will need to call it from the following function:
public void onWindowFocusChanged(boolean hasFocus)
This is because the window has not yet been attached and as you have noticed your imageview will have no dimensions yet.
I want to have an ImageView with width=fill_parent, and the height should be whatever the width is. I'm not sure if there's a way to specify that in xml, is the only option to create my own ImageView-derived class?:
public class MyImageView extends ImageView {
// Just return whatever the current width is?
private int measureHeight(int measureSpec) {
return getWidth();
}
}
Is this the way to go, any other options? (I'm not sure if the above is even correct, not sure if the width measurement even takes place before the height measurement for example)
Thanks
You can get the width with the method
imageView.getMeasuredWidth();
So, you can set it's height
imageView.setLayoutParams(new LayoutParams(imageView.getMeasuredWidth(), imageView.getMeasuredWidth()));
Make layout height equal to the width:
The problem with digulino's answer (in my case at least) is that if you want to change the dimensions in the start, getMeasuredWidth() will return 0 because the views haven't been drawn yet.
You can still do it by using a Runnable() thread like this:
FrameLayout frame = (FrameLayout)findViewById(R.id.myFrame);
frame.post(new Runnable() {
#Override
public void run() {
RelativeLayout.LayoutParams lparams;
lparams = (RelativeLayout.LayoutParams) frame.getLayoutParams();
lparams.height = frame.getWidth();
frame.setLayoutParams(lparams);
frame.postInvalidate();
}
});
Important Note:
This example assumes your view is a FrameLayout inside a RelativeLayout. Change it accordingly for other layouts.