ImageView be a square with dynamic width?

54,507

Solution 1

The best option is to subclass ImageView yourself, overriding the measure pass:

public class SquareImageView  extends ImageView {

  ...

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

    int width = getMeasuredWidth();
    setMeasuredDimension(width, width);
  }

  ...

}

Solution 2

The other answer works fine. This is just an extension of bertucci's solution to make an ImageView with square width and height with respect to xml inflated layout.

Create a class, say a SquareImageView extending ImageView like this,

public class SquareImageView extends ImageView {

    public SquareImageView(Context context) {
        super(context);
    }

    public SquareImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public SquareImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

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

        int width = getMeasuredWidth();
        setMeasuredDimension(width, width);
    }

}

Now, in your xml do this,

        <com.packagepath.tothis.SquareImageView
            android:id="@+id/Imageview"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent" />

If you need an ImageView not to be dynamically created in program, instead, to be fixed in xml, then this implementation will be helpful.

Solution 3

Even more simple:

public class SquareImageView extends ImageView {
    ...
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, widthMeasureSpec);
    }    
}

Solution 4

Several of the previous answers are perfectly sufficient. I'm just adding a small optimization to both @Andro Selva and @a.bertucci's solutions here:

It's a tiny optimization, but checking that the width and the height are different could prevent another measurement pass.

public class SquareImageView extends ImageView {

    public SquareImageView(Context context) {
        super(context);
    }

    public SquareImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public SquareImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

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

        int width = getMeasuredWidth();
        int height = getMeasuredHeight();

        // Optimization so we don't measure twice unless we need to
        if (width != height) {
            setMeasuredDimension(width, width);
        }
    }

}

Solution 5

For those looking for a Kotlin solution:

class SquareImageView @JvmOverloads constructor(
        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0
) : ImageView(context, attrs, defStyleAttr, defStyleRes){
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) = super.onMeasure(widthMeasureSpec, widthMeasureSpec)
}
Share:
54,507
Andrea
Author by

Andrea

Don't forget to take a look at my personal website

Updated on July 05, 2022

Comments

  • Andrea
    Andrea almost 2 years

    I have a GridView with ImageViews inside. I have 3 of them for each row. I can set correctly the width with WRAP_CONTENT and scaleType = CENTER_CROP, but I don't know how to set the ImageView's size to be a square. Here's what I did until now, it seems to be ok except the height, that is "static":

    imageView = new ImageView(context);     
    imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
    imageView.setLayoutParams(new GridView.LayoutParams(GridView.LayoutParams.WRAP_CONTENT, 300));
    

    I'm doing it inside an adapter.

  • Andrea
    Andrea about 11 years
    Awesome! Thank you very much, I didn't think about this possibility
  • Waza_Be
    Waza_Be almost 11 years
    If I set padding // margin, I get a white border.. Any idea how to fix that?
  • Taliadon
    Taliadon over 10 years
    Awesome, thank you Andro. This is precisely what I was looking for. Again, thanks for taking the time to provide a complete answer.
  • Kaloyan Roussev
    Kaloyan Roussev over 10 years
    android:adjustViewBounds="true" android:scaleType="centerCrop" @Waza_Be
  • Jarrod Robins
    Jarrod Robins almost 10 years
    This should be marked as the correct, full solution.
  • Mehdiway
    Mehdiway about 9 years
    That's the most beautiful fix I've ever seen. Thank you ! :)
  • android developer
    android developer about 9 years
    Shouldn't it be set as the min(width,height) instead?
  • Chantell Osejo
    Chantell Osejo almost 9 years
    It's a tiny optimization, but checking that the width and the height are different could prevent another measurement pass. @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = getMeasuredWidth(); int height = getMeasuredHeight(); // Optimization so we don't measure twice unless we need to if (width != height) { setMeasuredDimension(width, width); } }
  • Jan Rabe
    Jan Rabe over 8 years
    don't forget for sdk >= 21 @TargetApi(Build.VERSION_CODES.LOLLIPOP) public SquareImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); }
  • Pullat Junaid
    Pullat Junaid almost 6 years
    Answer is explained in this page codesofjunaid.blogspot.com/2017/04/…
  • Richard Le Mesurier
    Richard Le Mesurier over 5 years
    The use of AppCompatImageView in this answer is an important point.
  • Mr-IDE
    Mr-IDE over 2 years
    See also a good tutorial that uses this technique: raywenderlich.com/…