A requirement that almost every single application has is "I want to scale up an ImageView proportio

A requirement that almost every single application has is "I want to scale up an ImageView proportionally to fit its parent. How can I do that?" Like this:

adjustviewbounds

Actually ImageView has already come with this capability. You can just simply setandroid:adjustViewBounds to true and that's all.

1
2
3
4
5
< ImageView
     android:layout_width = "match_parent"
     android:layout_height = "wrap_content"
     android:adjustViewBounds = "true"
     android:src = "@mipmap/ic_launcher" />

Here is the result.

22_1

Everything looks fine? Actually not. If you switch your preview version to API Level 17 or below, you will see that ImageView doesn't scale up anymore.

17_1

It is not a bug but a correct behaviour that is officially noted in the documentation.

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  MeasureSpecand  RelativeLayout behavior.

It means that in API Level 17 and below, the maximum width and maximum height are bounded to the size of image defined in android:src. As a result, it happens like picture above.

Have a small look at Market Share of Android Platform Versions. It appears that Android phone running API Level 17 and below takes almost 50% share.

platformversions

It is not a good solution to set minSdkVersion to 18 just to avoid this problem.

It is far better to modify some ImageView's source code to give it an API Level 18+'s behavior and use it instead of a normal ImageView. Here it comes, a Custom ImageView that does the job !

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
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 nuuneoi on 2/17/15 AD.
  */
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 way these codes work is straightforward. It would calculate the height proportionally in case the width is fixed and vice versa inside onMeasure. In case this AdjustableImageView object is placed inside non-scrollable container, width and height would be limited to the space left in parent. Otherwise, it would be scaled up without any restriction.

To use it, simply change ImageView tocom.inthecheesefactory.thecheeselibrary.widget.AdjustableImageView in the layout xml.

1
2
3
4
5
< com.inthecheesefactory.thecheeselibrary.widget.AdjustableImageView
     android:layout_width = "match_parent"
     android:layout_height = "wrap_content"
     android:adjustViewBounds = "true"
     android:src = "@mipmap/ic_launcher" />

And it is now done !

Make it easy with AdjustableImageView Library

We know that it is such a boring task creating a file, copy the code, paste it, reformat, check if everything is right, blah blah blah.

Your life is now 10 times easier with the library dependency we prepared for you. It is now live on jcenter. Once you add the dependency to your project, AdjustableImageView and AdjustableImageButton will be ready to make your day. Source codes of this library are hosted on GitHub. Please feel free to have a look.

Here is the gradle dependency. Just simply add this line to yourbuild.gradle

1
2
3
dependencies {
     compile 'com.inthecheesefactory.thecheeselibrary:adjustable-imageview:1.0.0'
}

AdjustableImageView and AdjustableImageButton are now ready to use inside com.inthecheesefactory.thecheeselibrary.widget.* package.

Simply replace ImageView and ImageButton with those classes provided by the library.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
< LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android"
     xmlns:tools = "http://schemas.android.com/tools" android:layout_width = "match_parent"
     android:layout_height = "match_parent"
     android:orientation = "vertical"
     tools:context = ".MainActivity" >
 
     < ScrollView
         android:layout_width = "match_parent"
         android:layout_height = "match_parent"
         android:fillViewport = "true" >
 
         < LinearLayout android:layout_width = "match_parent"
             android:layout_height = "match_parent"
             android:orientation = "vertical" >
 
             < com.inthecheesefactory.thecheeselibrary.widget.AdjustableImageView
                 android:layout_width = "match_parent"
                 android:layout_height = "wrap_content"
                 android:adjustViewBounds = "true"
                 android:src = "@mipmap/ic_launcher" />
 
             < com.inthecheesefactory.thecheeselibrary.widget.AdjustableImageView
                 android:layout_width = "match_parent"
                 android:layout_height = "wrap_content"
                 android:adjustViewBounds = "true"
                 android:src = "@mipmap/ic_launcher" />
         </ LinearLayout >
 
     </ ScrollView >
 
</ LinearLayout >

As a result, ImageView is now scaled up perfectly no matter which Android version the application is running on.

final

This is a good example why we should install multiple SDK Platforms in the machine and not just the latest one. Since if you want to let Android Studio preview your layout with specific Android version, you need to install SDK Platform for that version or it wouldn't be listed as a choice in preview pane. Per my suggestion, you should install every single SDK Platform from API Level 14 on. Loss some disk space but what that you get back is worthy.

Author: nuuneoi (Android GDE, CTO & CEO at The Cheese Factory)
A full-stack developer with more than 6 years experience on Android Application Development and more than 12 years in Mobile Application Development industry. Also has skill in Infrastucture, Service Side, Design, UI&UX, Hardware, Optimization, Cooking, Photographing, Blogging, Training, Public Speaking and do love to share things to people in the world!
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值