您的位置:首页 > 移动开发 > Android开发

Android自定View——可以设置宽高比例的ImageView

2016-11-30 15:52 246 查看
如果对android自定义view还不太属性,可以查看我之前写的文章《Android自定义View——基础知识篇

在App中展示最多的除了文字外,应该就是图片了。为了适配屏幕,有些情况下在布局时图片大小是不固定的,如下图:



中间是三张图片(ImageView),图片左右两边的间距都已经确定,但图片大小不确定。可以看出三张图片占用剩下的空间,这里可以用LinearLayout布局,设置中间三个ImageView的layout_weight=1。但这里还有一个需求,图片不能被变形,必须按比例缩放。因为不确定ImageView的大小,所以无法事先根据比例设置宽高。

我们可以自定义一个ImageView,根据图片的比例自动确定ImageView的大小,或者指定宽高的比例。效果图如下:





我们可以看出,ImageView根据屏幕的大小不同自动适配。下面是关键代码:

[java] view
plain copy

 





public class RatioImageView extends ImageView {  

  

    /* 优先级从大到小: 

     mIsWidthFitDrawableSizeRatio mIsHeightFitDrawableSizeRatio 

     mWidthRatio mHeightRatio 

     即如果设置了mIsWidthFitDrawableSizeRatio为true,则优先级较低的三个值不生效 */  

  

    private float mDrawableSizeRatio = -1f; // src图片(前景图)的宽高比例  

    // 根据前景图宽高比例测量View,防止图片缩放变形  

    private boolean mIsWidthFitDrawableSizeRatio; // 宽度是否根据src图片(前景图)的比例来测量(高度已知)  

    private boolean mIsHeightFitDrawableSizeRatio; // 高度是否根据src图片(前景图)的比例来测量(宽度已知)  

    // 宽高比例  

    private float mWidthRatio = -1; // 宽度 = 高度*mWidthRatio  

    private float mHeightRatio = -1; // 高度 = 宽度*mHeightRatio  

  

    public RatioImageView(Context context) {  

        this(context, null);  

    }  

  

    public RatioImageView(Context context, AttributeSet attrs) {  

        this(context, attrs, 0);  

    }  

  

    public RatioImageView(Context context, AttributeSet attrs, int defStyleAttr) {  

        super(context, attrs, defStyleAttr); // 虽然此处会调用setImageDrawable,但此时成员变量还未被正确初始化  

        init(attrs);  

        // 一定要有此代码  

        if (getDrawable() != null) {  

            mDrawableSizeRatio = 1f * getDrawable().getIntrinsicWidth()  

                    / getDrawable().getIntrinsicHeight();  

        }  

    }  

  

    /** 

     * 初始化变量 

     */  

    private void init(AttributeSet attrs) {  

  

        TypedArray a = getContext().obtainStyledAttributes(attrs,  

                R.styleable.RatioImageView);  

        mIsWidthFitDrawableSizeRatio = a.getBoolean(R.styleable.RatioImageView_is_width_fix_drawable_size_ratio,  

                mIsWidthFitDrawableSizeRatio);  

        mIsHeightFitDrawableSizeRatio = a.getBoolean(R.styleable.RatioImageView_is_height_fix_drawable_size_ratio,  

                mIsHeightFitDrawableSizeRatio);  

        mHeightRatio = a.getFloat(  

                R.styleable.RatioImageView_height_to_width_ratio, mHeightRatio);  

        mWidthRatio = a.getFloat(  

                R.styleable.RatioImageView_width_to_height_ratio, mWidthRatio);  

        a.recycle();  

    }  

  

    @Override  

    public void setImageResource(int resId) {  

        super.setImageResource(resId);  

        if (getDrawable() != null) {  

            mDrawableSizeRatio = 1f * getDrawable().getIntrinsicWidth()  

                    / getDrawable().getIntrinsicHeight();  

            if (mDrawableSizeRatio > 0  

                    && (mIsWidthFitDrawableSizeRatio || mIsHeightFitDrawableSizeRatio)) {  

                requestLayout();  

            }  

        }  

    }  

  

    @Override  

    public void setImageDrawable(Drawable drawable) {  

        super.setImageDrawable(drawable);  

        if (getDrawable() != null) {  

            mDrawableSizeRatio = 1f * getDrawable().getIntrinsicWidth()  

                    / getDrawable().getIntrinsicHeight();  

            if (mDrawableSizeRatio > 0  

                    && (mIsWidthFitDrawableSizeRatio || mIsHeightFitDrawableSizeRatio)) {  

                requestLayout();  

            }  

        }  

    }  

  

    @Override  

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  

        // 优先级从大到小:  

        // mIsWidthFitDrawableSizeRatio mIsHeightFitDrawableSizeRatio  

        // mWidthRatio mHeightRatio  

        if (mDrawableSizeRatio > 0) {  

            // 根据前景图宽高比例来测量view的大小  

            if (mIsWidthFitDrawableSizeRatio) {  

                mWidthRatio = mDrawableSizeRatio;  

            } else if (mIsHeightFitDrawableSizeRatio) {  

                mHeightRatio = 1 / mDrawableSizeRatio;  

            }  

        }  

  

        if (mHeightRatio > 0 && mWidthRatio > 0) {  

            throw new RuntimeException("高度和宽度不能同时设置百分比!!");  

        }  

  

        if (mWidthRatio > 0) { // 高度已知,根据比例,设置宽度  

            int height = MeasureSpec.getSize(heightMeasureSpec);  

            super.onMeasure(MeasureSpec.makeMeasureSpec(  

                            (int) (height * mWidthRatio), MeasureSpec.EXACTLY),  

                    MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));  

        } else if (mHeightRatio > 0) { // 宽度已知,根据比例,设置高度  

            int width = MeasureSpec.getSize(widthMeasureSpec);  

            super.onMeasure(MeasureSpec.makeMeasureSpec(width,  

                    MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(  

                    (int) (width * mHeightRatio), MeasureSpec.EXACTLY));  

        } else { // 系统默认测量  

            super.onMeasure(widthMeasureSpec, heightMeasureSpec);  

        }  

    }  

  

}  

res/values/attrs.xml

[html] view
plain copy

 





<?xml version="1.0" encoding="utf-8"?>  

<resources>  

    <declare-styleable name="RatioImageView">  

  

        <!--宽度是否根据src图片的比例来测量(高度已知)-->  

        <attr name="is_width_fix_drawable_size_ratio" format="boolean"/>  

        <!--高度是否根据src图片的比例来测量(宽度已知)-->  

        <attr name="is_height_fix_drawable_size_ratio" format="boolean"/>  

  

        <!-- 高度设置,参考宽度,如0.5 , 表示 高度=宽度×0.5 -->  

        <attr name="height_to_width_ratio" format="float"/>  

        <!-- 宽度设置,参考高度,如0.5 , 表示 宽度=高度×0.5 -->  

        <attr name="width_to_height_ratio" format="float"/>  

  

    </declare-styleable>  

</resources>  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐