Correct the ImageView's adjustViewBounds behaviour on API Level 17 and below

In your application, you have a requirement like “I want to scale up an ImageView proportionally to fit its parent. How can I do that?“

android<em>imageview</em>adjustviewbound

In this case, I was use ImageView and set its width attribute is match_parent and set its adjustViewBounds is true, like code below.

<ImageView android:layout_width="match_parent"  
  android:layout_height="wrap_content"
  android:adjustViewBounds="true"
  android:src="@mipmap/ic_launcher" />

Here is the result:

android<em>imageview</em>adjustviewbound_result

Everything looks fine?
Actually not. When I run application in Android device version API 17 or below, I don’t have expect result.

android<em>imageview</em>adjustviewbound_result2

This issue noted in the office document.

Note: If the application targets API level 17 or lower, adjustViewBounds will allow the drawable to shrink the view bounds, but not grow to fill available measured space in all cases. This is for compatibility with legacy MeasureSpec and RelativeLayout behavior.

It mean: In targets level 17 or lower, ImageView‘s max with and max height defined in android:src. Then the result that we received is not expect.

If your application support for targets level 17 or lower, you must resolve this. Now, in this article I will show you how to make a custom ImageView that can use adjustViewBounds attribute in targets 17 or below.

package net.awpspace.adjustviewbounddemo;  
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; /** * Created by Administrator on 22-Aug-15. */  
public class AdjustableImageView extends ImageView {  
 boolean mAdjustViewBounds;
 public AdjustableImageView(Context context) {
  super(context);
 }
 public AdjustableImageView(Context context, AttributeSet attrs) {
  super(context, attrs);
 }
 public AdjustableImageView(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
 }
 @Override public void setAdjustViewBounds(boolean adjustViewBounds) {
  mAdjustViewBounds = adjustViewBounds;
  super.setAdjustViewBounds(adjustViewBounds);
 }
 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  Drawable mDrawable = getDrawable();
  if (mDrawable == null) {
   super.onMeasure(widthMeasureSpec, heightMeasureSpec);
   return;
  }
  if (mAdjustViewBounds) {
   int mDrawableWidth = mDrawable.getIntrinsicWidth();
   int mDrawableHeight = mDrawable.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) {
    // Fixed Height & Adjustable Width 
    int height = heightSize;
    int width = height * mDrawableWidth / mDrawableHeight;
    if (isInScrollingContainer()) setMeasuredDimension(width, height);
    else setMeasuredDimension(Math.min(width, widthSize), Math.min(height, heightSize));
   } else if (widthMode == MeasureSpec.EXACTLY && heightMode != MeasureSpec.EXACTLY) {
    // Fixed Width & Adjustable Height
    int width = widthSize;
    int height = width * mDrawableHeight / mDrawableWidth;
    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 p = getParent();
  while (p != null && p instanceof ViewGroup) {
   if (((ViewGroup) p).shouldDelayChildPressedState()) {
    return true;
   }
   p = p.getParent();
  }
  return false;
 }
}

The issue resolved when I use AdjustableImageView, here is the result:

android<em>imageview</em>adjustviewbound_result2