Search code examples
androidandroid-layoutimageviewandroid-imageview

ImageView height relative to width


I have this layout:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    style="@style/AppTheme.Widgets.Box"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="2dp"
        android:scaleType="centerCrop"
        android:background="#eee"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="7dp"
        android:gravity="center"/>

</LinearLayout>

So, I am loading remote images into ImageView from web. I know the dimensions of the image so i know width:height ratio. Now I need to somehow apply this ration when I am initializing my layout so it doesnt jump like crazy later in the app.


Solution

  • For such case I've created a custom ImageView that maintains it's height relative to width. It has the custom attribute 'height_ratio' that's multiplied by width to get height:

    DynamicHeightImageView.java:

    /**
     * An {@link android.widget.ImageView} layout that maintains a consistent width to height aspect ratio.
     */
    public class DynamicHeightImageView extends ImageView {
    
        private float mHeightRatio;
    
        public DynamicHeightImageView(Context context, AttributeSet attrs) {
            super(context, attrs);
            TypedArray ta = context.getTheme().obtainStyledAttributes(attrs, R.styleable.DynamicHeightImageView, 0, 0);
            try {
                mHeightRatio = ta.getFloat(R.styleable.DynamicHeightImageView_height_ratio, 0.0f);
            } finally {
                ta.recycle();
            }
        }
    
        public DynamicHeightImageView(Context context) {
            super(context);
        }
    
        public void setHeightRatio(float ratio) {
            if (ratio != mHeightRatio) {
                mHeightRatio = ratio;
                requestLayout();
            }
        }
    
        public double getHeightRatio() {
            return mHeightRatio;
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            if (mHeightRatio > 0.0f) {
                // set the image views size
                int width = MeasureSpec.getSize(widthMeasureSpec);
                int height = (int) (width * mHeightRatio);
                setMeasuredDimension(width, height);
            }
            else {
                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            }
        }
    }
    

    attrs.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="DynamicHeightImageView">
            <attr name="height_ratio" format="float"/>
        </declare-styleable>
    </resources>
    

    Usage:

    <com.melnykov.android.views.DynamicHeightImageView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scaleType="centerCrop"
        custom:height_ratio="0.6"/>