Reputation: 545
I want the width of an ImageView to be set by the parent and the height should be aspect proportional. The reasons for this is that next is shown a TextView that I want to place just under the ImageView.
I can get image to show correctly using
android:layout_width="fill_parent"
android:layout_height="fill_parent"
however the ImageView height become the parent height which is much larger than that of the shown stretched image. One idea was to make parent smaller vertically, but.. there I don't yet know the stretched image size.
The following doesn't work because a small image is not filled up horizontally.
android:layout_width="fill_parent"
android:layout_height="wrap_content"
Messing around with
android:layout_height="wrap_content"
for the RelativeLayout surrounding it all does not help. Also tried FrameLayout and LinearLayout and failed.
Any ideas?
Upvotes: 41
Views: 28834
Reputation: 24848
There is two case if your actual image size is equal or grater than your ImageView width and heigh then you can use adjustViewBounds property and if your actual image size is less than ImageView width and height than use scaleType property to shown image in ImageView based on your requirement.
1.Actual image size is equal or grater than ImageView required width and height.
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="@drawable/ic_launcher"/>
2.Actual image size is less than ImageView required width and height.
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:src="@drawable/ic_launcher"/>
Upvotes: 41
Reputation: 1344
So I have had the same issue more than once and looking through the existing stackoverflow answers have realised that no answer gives a perfect explanation for the real confusion regarding a solution to this problem. So here you go:
imageView.setAdjustViewBounds(true);
OR (in XML)
android:adjustViewBounds="true"
solves the issue, it works no matter the actual size of the image resource, i.e. it will scale your image up or down to the desired size you have in your layout.
Below API 17 android:adjustViewBounds="true"
will only work for shrinking an image, not growing, i.e. if the actual height of the image source is smaller than the dimensions you are trying to achieve in your layout, wrap_content
will use that smaller height and not scale 'up' (enlarge) the image as you desire.
And so for API 17 and lower, you have no choice but to use a custom ImageView to achieve this behaviour. You could either write a custom ImageView yourself or use a library, that has already done that job.
There is probably more than one library that fixes this issue, one of them is:
compile 'com.inthecheesefactory.thecheeselibrary:adjustable-imageview:1.0.0'
which is used like this:
<com.inthecheesefactory.thecheeselibrary.widget.AdjustableImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="@drawable/your_drawable"/>
alternatively to using an existing library, you could write a custom view yourself, e.g.:
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.ImageView;
public class ScalableImageView extends ImageView {
boolean adjustViewBounds;
public ScalableImageView(Context context) {
super(context);
}
public ScalableImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ScalableImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public void setAdjustViewBounds(boolean adjustViewBounds) {
this.adjustViewBounds = adjustViewBounds;
super.setAdjustViewBounds(adjustViewBounds);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Drawable drawable = getDrawable();
if (drawable == null) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
if (adjustViewBounds) {
int drawableWidth = drawable.getIntrinsicWidth();
int drawableHeight = drawable.getIntrinsicHeight();
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
if (heightMode == MeasureSpec.EXACTLY && widthMode != MeasureSpec.EXACTLY) {
int height = heightSize;
int width = height * drawableWidth / drawableHeight;
if (isInScrollingContainer())
setMeasuredDimension(width, height);
else
setMeasuredDimension(Math.min(width, widthSize), Math.min(height, heightSize));
} else if (widthMode == MeasureSpec.EXACTLY && heightMode != MeasureSpec.EXACTLY) {
int width = widthSize;
int height = width * drawableHeight / drawableWidth;
if (isInScrollingContainer())
setMeasuredDimension(width, height);
else
setMeasuredDimension(Math.min(width, widthSize), Math.min(height, heightSize));
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
private boolean isInScrollingContainer() {
ViewParent parent = getParent();
while (parent != null && parent instanceof ViewGroup) {
if (((ViewGroup) parent).shouldDelayChildPressedState()) {
return true;
}
parent = parent.getParent();
}
return false;
}
}
... which you would use as follows (XML):
<com.YOUR_PACKE_NAME.ScalableImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="@drawable/your_drawable" />
Upvotes: 9
Reputation: 2380
You have to set adjustViewBounds to true.
imageView.setAdjustViewBounds(true);
Upvotes: 99
Reputation: 545
This was the only way I could get it working, to have the second ImageView in the center and smaller than the first ImageView, and the TextView under the second ImageView.
Unfortunately, it uses fixed "200dp" image size on the second ImageView, so it does not look the same on different sized devices.
It also destroys my ViewFlipper, since any Layout I tried around the second ImageView and the TextView makes them move or resize.
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ImageView
android:id="@+id/imageview1"
android:contentDescription="@string/desc"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:src="@drawable/background" />
<ImageView
android:id="@+id/imageview2"
android:layout_centerInParent="true"
android:contentDescription="@string/desc"
android:layout_height="200dp"
android:layout_width="200dp"
android:adjustViewBounds="true"
android:src="@drawable/image2" />
<TextView
android:id="@+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_below="@id/imageview2"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:gravity="center"
android:textSize="26sp"
android:textColor="#333"
android:background="#fff"
android:text="this is the text under the image right here"
/>
</RelativeLayout>
Upvotes: 0