美文网首页Android自定义ViewAndroid开发Android自定义控件
Android打造可按宽高比例缩放的ImageView

Android打造可按宽高比例缩放的ImageView

作者: Sky_Blue | 来源:发表于2018-06-09 10:40 被阅读76次
    一、概述

    图片多的页面,经常会听见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

    相关文章

      网友评论

      • 有点健忘:最新的constraintlayout里边的控件就支持设置宽高比的,比较省事,可以看下

      本文标题:Android打造可按宽高比例缩放的ImageView

      本文链接:https://www.haomeiwen.com/subject/qwxteftx.html