Zdeněk Topič
Zdeněk Topič

Reputation: 780

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.

Upvotes: 2

Views: 2304

Answers (4)

Benjamin Basmaci
Benjamin Basmaci

Reputation: 2557

As an improvement (as I see it) to makovkastar's answer:

I've tried to make the whole thing a little more simple, wrote it in Kotlin and made it so that the height and width aspects are set as integers as to be more precise by using fractions instead of floating point numbers:

/**
 * An [android.widget.ImageView] layout that maintains a consistent width to height aspect ratio.
 */
class DynamicHeightImageView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : ImageView(context, attrs, defStyleAttr) {

private var heightFactor : Int
private var widthFactor : Int

init {
    context.theme.obtainStyledAttributes(attrs, R.styleable.DynamicHeightImageView, 0, 0).apply {
        heightFactor = getInt(R.styleable.DynamicHeightImageView_heightFactor, 1)
        widthFactor = getInt(R.styleable.DynamicHeightImageView_widthFactor, 1)
    }
}

/**
 * Adjusts the [getHeight] relative to the [getWidth], according to [heightFactor] and [widthFactor].
 */
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
    super.onLayout(changed, left, top, right, bottom)
    layoutParams.height = (width.toFloat() * heightFactor / widthFactor).toInt()
}

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

Upvotes: 0

makovkastar
makovkastar

Reputation: 5020

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

Upvotes: 8

WISHY
WISHY

Reputation: 11999

Since you know the dimensions of your image. You can set the image view's dimension programmatically converting pixels into dp

Refer this Convert Pixels to DP

Upvotes: 0

Nantoka
Nantoka

Reputation: 4243

If you use CENTER_INSIDE as scale type, the image will be scaled so that the aspect ratio is preserved and the image fits into the "frame" of the image view that you have defined with layout_width and layout_height. But are you sure that you want your image 2dp high at maximum?

Upvotes: 0

Related Questions