Android打造可按宽高比例缩放的ImageView
2018-06-09 本文已影响76人
Sky_Blue
一、概述
图片多的页面,经常会听见UI说,你写的UI变形了。图片拉伸、变形也是开发有时会遇到的问题。
二、先看一下缩放的效果图
效果图.jpg测试图片的宽高尺寸:840 * 420,也就是 2:1,宽是高的2倍。
三、缩放的需求分析
1. 按宽或者高来缩放
2. 缩放的倍数或者说比例
四、自定义属性
<declare-styleable name="ScaleImageView">
<!--缩放的类型:按宽还是高-->
<attr name="viewScaleType" format="enum">
<enum name="width" value="1" />
<enum name="height" value="2" />
</attr>
<!--缩放的倍数-->
<!--比如:宽120 高60 (按宽来缩放:比例就是 2; 按高度来缩放,比例:0.5f)-->
<attr name="viewScaleRadio" format="float" />
</declare-styleable>
五、控件的宽高是在onMeasure指定的,先分析一下有多少种情况
1. 明确的指定了宽高
2. 按宽度来缩放
3. 按高度缩放
/**
* 测量控件的代码
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 不设置任何属性
if (mScaleType == 0 || mScaleRadio == 0) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
// 如果子类设置了精确的宽高
if (widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY
&& (widthSize != 0 && heightSize != 0)) {
setMeasuredDimension(widthSize, heightSize);
return;
}
// 如果是按宽度来缩放
if (mScaleType == WIDTH && widthMode == MeasureSpec.EXACTLY && widthSize != 0) {
heightSize = (int) (widthSize / mScaleRadio);
setMeasuredDimension(widthSize, heightSize);
return;
}
// 如果是按高度来缩放
if (mScaleType == HEIGHT && heightMode == MeasureSpec.EXACTLY && heightSize != 0) {
widthSize = (int) (heightSize / mScaleRadio);
setMeasuredDimension(widthSize, heightSize);
return;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
代码没什么难度,看注释就好
六、自定义缩放ImageView完整的代码
/**
* 缩放的ImageView
*/
public class ScaleImageView extends android.support.v7.widget.AppCompatImageView {
/**
* 类型宽
*/
private static final int WIDTH = 1;
/**
* 类型高
*/
private static final int HEIGHT = 2;
/**
* 缩放的类型
*/
private int mScaleType = 0;
/**
* 缩放的倍数
*/
private float mScaleRadio;
public enum ImageScaleType {
WIDTH, HEIGHT
}
public ScaleImageView(Context context) {
this(context, null);
}
public ScaleImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ScaleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ScaleImageView);
mScaleRadio = array.getFloat(R.styleable.ScaleImageView_viewScaleRadio, 0);
mScaleType = array.getInt(R.styleable.ScaleImageView_viewScaleType, 0);
array.recycle();
}
/**
* 测量控件的代码
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 不设置任何属性
if (mScaleType == 0 || mScaleRadio == 0) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
// 如果子类设置了精确的宽高
if (widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY
&& (widthSize != 0 && heightSize != 0)) {
setMeasuredDimension(widthSize, heightSize);
return;
}
// 如果是按宽度来缩放
if (mScaleType == WIDTH && widthMode == MeasureSpec.EXACTLY && widthSize != 0) {
heightSize = (int) (widthSize / mScaleRadio);
setMeasuredDimension(widthSize, heightSize);
return;
}
// 如果是按高度来缩放
if (mScaleType == HEIGHT && heightMode == MeasureSpec.EXACTLY && heightSize != 0) {
widthSize = (int) (heightSize / mScaleRadio);
setMeasuredDimension(widthSize, heightSize);
return;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
/**
* 设置缩放类型
*/
public void setScaleType(ImageScaleType scaleType) {
switch (scaleType) {
case WIDTH:
mScaleType = WIDTH;
break;
case HEIGHT:
mScaleType = HEIGHT;
break;
}
invalidate();
}
/**
* 设置缩放倍数
*/
public void setScaleRadio(float radio) {
this.mScaleRadio = radio;
invalidate();
}
}
七、测试布局代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.wen.routerdemo.view.ScaleImageView
android:layout_width="120dp"
android:layout_height="0dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="5dp"
android:scaleType="fitXY"
android:src="@mipmap/ic_scale_image"
app:viewScaleRadio="2"
app:viewScaleType="width" />
<com.wen.routerdemo.view.ScaleImageView
android:layout_width="240dp"
android:layout_height="0dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="5dp"
android:scaleType="fitXY"
android:src="@mipmap/ic_scale_image"
app:viewScaleRadio="2"
app:viewScaleType="width" />
<com.wen.routerdemo.view.ScaleImageView
android:layout_width="300dp"
android:layout_height="0dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="8dp"
android:scaleType="fitXY"
android:src="@mipmap/ic_scale_image"
app:viewScaleRadio="2"
app:viewScaleType="width" />
<com.wen.routerdemo.view.ScaleImageView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="5dp"
android:scaleType="fitXY"
android:src="@mipmap/ic_scale_image"
app:viewScaleRadio="2"
app:viewScaleType="width" />
</LinearLayout>