Scott Johansen
Scott Johansen

Reputation: 545

imageview height as the wrap_content of the shown image

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

Answers (4)

Hareshkumar Chhelana
Hareshkumar Chhelana

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

Simon Mayrshofer
Simon Mayrshofer

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:

API 17+

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

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.

Using a library

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"/>

Using a custom View

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

Kit
Kit

Reputation: 2380

You have to set adjustViewBounds to true.

imageView.setAdjustViewBounds(true);

Upvotes: 99

Scott Johansen
Scott Johansen

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

Related Questions