Android自定义ViewAndroid开发Android自定义控件

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>
八、测试效果,就是开始就给出的
效果图.jpg
上一篇下一篇

猜你喜欢

热点阅读