214

I have an imageview. I want its width to be fill_parent. I want its height to be whatever the width ends up being. For example:

<ImageView
  android:layout_width="fill_parent"
  android:layout_height="whatever the width ends up being" />

Is something like that possible in a layout file without having to create my own view class?

Thanks

user291701
  • 38,411
  • 72
  • 187
  • 285
  • Did you figure out how to do this? I assume you want the aspect ratio to remain the same. Most of these answers assume you want the image to be square. – Adam Feb 08 '13 at 19:29
  • @Joe Blow that is a VERY bad way to do it – Aggressor May 11 '15 at 16:13

14 Answers14

253

Updated July 28 2021 to use AndroidX instead of the support library

First, make sure your project has AndroidX imported, by following the directions here.

Then wrap your image inside a ConstraintLayout, and its fields as such:

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        app:layout_constraintDimensionRatio="1:1" />

</androidx.constraintlayout.widget.ConstraintLayout>

See here

davidchuyaya
  • 3,960
  • 2
  • 16
  • 26
  • 9
    The link this answer has the most elegant solution provided Google. In my case, I wanted image to get displayed in 16:9 ratio no matter what original image aspect ratio is. Works great. Thanks! – Eddie Feb 24 '16 at 14:49
  • Im my case, solutions such as [this one](http://stackoverflow.com/questions/16506275/imageview-be-a-square-with-dynamic-width) did not work, this one did! – Gooey Jul 13 '16 at 20:58
  • 5
    dont forget to add 'compile com.android.support:percent:23.3.0' in your dependencies – Milad Faridnia Oct 16 '16 at 08:34
  • This looks like this approach is having issues with WrappedViewPager which calculates height based on its children contents. Source for WrappedViewPager similar to https://gist.github.com/egslava/589b82a6add9c816a007 – sha Feb 15 '17 at 01:37
  • 1
    The Percent Support module has been deprecated has been deprecated since android support library 26.0.0. Source: https://developer.android.com/topic/libraries/support-library/revisions.html#26-0-0 – MHogge Sep 13 '17 at 14:51
  • Since the percentage-based solution is deprecated, why don't you remove it from the answer? – Minas Mina Apr 30 '18 at 22:12
  • What if I am not using Constraint Layout? – Kakaji Dec 02 '18 at 21:49
  • Works perfect with constraint layout. – ShadeToD Jul 12 '19 at 16:37
  • This didn't work for me because I needed my Imageview to react to the gravity attribute set on the outer LinearLayout. The ConstraintLayout absorbed that effect as it is full width. The answer below worked: https://stackoverflow.com/a/16172762/3795043 – findusl Aug 23 '21 at 18:01
115

Maybe this will answer your question:

<ImageView
    android:id="@+id/cover_image"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:scaleType="fitCenter"
    android:adjustViewBounds="true" />

You can ignore the scaleType attribute for this particular situation.

Hamid Shatu
  • 9,664
  • 4
  • 30
  • 41
Vlad Stefanescu
  • 1,303
  • 1
  • 8
  • 3
31

This can be done using LayoutParams to dynamically set the Views height once your know the Views width at runtime. You need to use a Runnable thread in order to get the Views width at runtime or else you'll be trying to set the Height before you know the View's width because the layout hasn't been drawn yet.

Example of how I solved my problem:

final FrameLayout mFrame = (FrameLayout) findViewById(R.id.frame_id);

    mFrame.post(new Runnable() {

        @Override
        public void run() {
            RelativeLayout.LayoutParams mParams;
            mParams = (RelativeLayout.LayoutParams) mFrame.getLayoutParams();
            mParams.height = mFrame.getWidth();
            mFrame.setLayoutParams(mParams);
            mFrame.postInvalidate();
        }
    });

The LayoutParams must be of the type of the Parent View that your view is in. My FrameLayout is inside of a RelativeLayout in the xml file.

    mFrame.postInvalidate();

is called to force the view to redraw while on a separate thread than the UI thread

dsrees
  • 6,116
  • 2
  • 26
  • 26
  • 4
    awesome answer, especially with the Runnable, thanks! – jesses.co.tt Aug 01 '14 at 17:21
  • 1
    While this works, it is not ideal. Running on post means the view renders once before the layout changes. Could allow a flash of content at the wrong height, before drawing correctly. Better to solve earlier. The earliest possible moment to solve is during a custom `onMeasure`, as shown in [Regis' answer](http://stackoverflow.com/a/16834032/199364). An alternative, but only for views rendered via an adapter, e.g. inside `GridView`, is [Matt's answer](http://stackoverflow.com/a/18927200/199364). – ToolmakerSteve Jan 07 '17 at 22:57
  • 1
    well it worked for me only after calling `requestLayout()` after setting the parameters. why would that be? – Divins Mathew Jun 05 '17 at 08:58
  • mFrame.postInvalidate(); is what did it, without it I was getting the view out of position. – Jacolack Apr 07 '18 at 21:14
20

I couldn't get David Chu's answer to work for a RecyclerView item and figured out I needed to constrain the ImageView to the parent. Set the ImageView width to 0dp and constrain its start and end to the parent. I'm not sure if setting the width to wrap_content or match_parent works in some cases, but I think this is a better way to get the child of a ConstraintLayout to fill its parent.

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintDimensionRatio="1:1"/>

</androidx.constraintlayout.widget.ConstraintLayout>
Maveňツ
  • 1
  • 12
  • 50
  • 89
Shawn Aten
  • 351
  • 4
  • 10
14

If your image view is inside a constraint layout, you can use following constraints to create a square image view make sure to use 1:1 to make square

<ImageView
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:id="@+id/ivImageView"
    app:layout_constraintDimensionRatio="1:1"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"/>
Anatoly
  • 20,799
  • 3
  • 28
  • 42
ChaturaM
  • 1,507
  • 18
  • 32
13

Here I what I did to have an ImageButton which always have a width equals to its height (and avoid stupid empty margins in one direction...which I consider a as a bug of the SDK...):

I defined a SquareImageButton class which extends from ImageButton:

package com.myproject;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageButton;

    public class SquareImageButton extends ImageButton {

        public SquareImageButton(Context context) {
        super(context);


        // TODO Auto-generated constructor stub
    }

    public SquareImageButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub

    }

    public SquareImageButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        // TODO Auto-generated constructor stub

    }

    int squareDim = 1000000000;

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);


        int h = this.getMeasuredHeight();
        int w = this.getMeasuredWidth();
        int curSquareDim = Math.min(w, h);
        // Inside a viewholder or other grid element,
        // with dynamically added content that is not in the XML,
        // height may be 0.
        // In that case, use the other dimension.
        if (curSquareDim == 0)
            curSquareDim = Math.max(w, h);

        if(curSquareDim < squareDim)
        {
            squareDim = curSquareDim;
        }

        Log.d("MyApp", "h "+h+"w "+w+"squareDim "+squareDim);


        setMeasuredDimension(squareDim, squareDim);

    }

}

Here is my xml:

<com.myproject.SquareImageButton
            android:id="@+id/speakButton"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:scaleType="centerInside"
            android:src="@drawable/icon_rounded_no_shadow_144px"
            android:background="#00ff00"
            android:layout_alignTop="@+id/searchEditText"
            android:layout_alignBottom="@+id/searchEditText"
            android:layout_alignParentLeft="true"
           />

Works like a charm !

ToolmakerSteve
  • 18,547
  • 14
  • 94
  • 196
toto_tata
  • 14,526
  • 27
  • 108
  • 198
6

In Android 26.0.0 PercentRelativeLayout has been deprecated.

The best way to solve it is now with ConstraintLayout like this:

<android.support.constraint.ConstraintLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content">

    <ImageView android:layout_width="match_parent"
               android:layout_height="0dp"
               android:scaleType="centerCrop"
               android:src="@drawable/you_image"                       
               app:layout_constraintDimensionRatio="1:1"/>


</android.support.constraint.ConstraintLayout>


Here is a tutorial on how to add ConstraintLayout to your project.

Sebastian Schneider
  • 4,896
  • 3
  • 20
  • 47
6

You can't do it with the layout alone, I've tried. I ended up writing a very simple class to handle it, you can check it out on github. SquareImage.java Its part of a larger project but nothing a little copy and paste can't fix (licensed under Apache 2.0)

Essentially you just need to set the height/width equal to the other dimension (depending on which way you want to scale it)

Note: You can make it square without a custom class using the scaleType attribute but the view's bounds extend beyond the visible image, which makes it an issue if you are placing other views near it.

smith324
  • 13,020
  • 9
  • 37
  • 58
5

To set your ImageView equal to half the screen, you need to add the following to your XML for the ImageView:

<ImageView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_centerInParent="true"
    android:scaleType="fitXY"
    android:adjustViewBounds="true"/>

To then set the height equal to this width, you need to do it in code. In the getView method of your GridView adapter, set the ImageView height equal to its measured width:

mImageView.getLayoutParams().height = mImageView.getMeasuredWidth();
Matt Logan
  • 5,886
  • 5
  • 31
  • 48
4

For people passing by now, in 2017, the new best way to achieve what you want is by using ConstraintLayout like this:

<ImageView
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:scaleType="centerCrop"
    app:layout_constraintDimensionRatio="1:1" />

And don't forget to add constraints to all of the four directions as needed by your layout.

Build a Responsive UI with ConstraintLayout

Furthermore, by now, PercentRelativeLayout has been deprecated (see Android documentation).

CristinaTheDev
  • 1,952
  • 2
  • 17
  • 25
1

Here's how I solved that problem:

int pHeight =  picture.getHeight();
int pWidth = picture.getWidth();
int vWidth = preview.getWidth();
preview.getLayoutParams().height = (int)(vWidth*((double)pHeight/pWidth));

preview - imageView with width setted to "match_parent" and scaleType to "cropCenter"

picture - Bitmap object to set in imageView src.

That's works pretty well for me.

udenfox
  • 1,594
  • 1
  • 15
  • 25
  • You have not explained *where* this code must be put. You also have not explained why you do `= vw*ph/pw` instead of the simpler `= vw`. (I think you do this to preserve aspect ratio of source image, rather than force a square preview.) – ToolmakerSteve Jan 07 '17 at 22:53
0

The ImageView "scaleType" function may help you here.

This code will keep the aspect ratio and position the image at the top:

android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="fitStart"

Here is a great post showing the possibilities and appearances from using scaleType.

ImageView scaleType samples

ac_banks
  • 9
  • 1
  • "scaleType" doesn't help here. The goal is to have the ImageView itself always be square, not just the image inside it. With scaleType, the ImageView may be larger than the image. – ToolmakerSteve Jan 07 '17 at 22:40
0

i did like this -

layout.setMinimumHeight(layout.getWidth());
HarshitG
  • 2,677
  • 3
  • 16
  • 13
0

I don't think there's any way you can do it in XML layout file, and I don't think android:scaleType attribute will work like you want it to be.
The only way would be to do it programmatically. You can set the width to fill_parent and can either take screen width as the height of the View or can use View.getWidth() method.

0xC0DED00D
  • 19,522
  • 20
  • 117
  • 184