加载的过程中图片变形了? --教你自定义自动适配图片宽高比的RatioLayout

时间:2023-03-09 17:18:45
加载的过程中图片变形了? --教你自定义自动适配图片宽高比的RatioLayout

  很多同行在开发中可能会遇到这样的问题,就是在加载图片的时候会出现图片变形的问题.其实这很可能就是你的图片宽高比和图片所在容器的宽高比不匹配造成的.比如说图片的宽为200,高为100.宽高比就是2,那么这时候把它放在宽高比为1或者3的控件上就会分别出现变窄和变宽的问题.只有在容器宽高比为2的时候图片才会和原始显示效果一样.怎样解决这个问题呢?这个时候就可以创建一个能够自适应图片宽高比的父容器来包裹ImageView就可以了.在使用RatioLayout的时候要注意以下几点:

1)ImageView的宽高属性都要改成match_parent

2)要指定RatioLayout以宽还是高来进行适配

3)在attrs.xml中添加控件的两个属性:一个是宽高比,一个是适配标准.前者为float,后者为enum类型,分别制定width=0和height=1

4)创建一个类RatioLayout继承FrameLayout,重写两个构造方法以及onMeasure方法

具体代码如下:

I.RatioLayout.java

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.FrameLayout; import com.yangtao.googleplay.R;
/**
* Created by 杨涛 on 2016/11/18.
* 版权所有 翻版必究
* 自定义的容器控件
* 可以实现的功能如下:
* 1.可以根据指定的宽高比和模式来让子控件动态适应屏幕
*/
public class RatioLayout extends FrameLayout { private float mRatio; private static final int RATIOMODE_WIDTH = 0; private static final int RATIOMODE_HEIGHT = 1; private int ratioMode = RATIOMODE_WIDTH; public RatioLayout(Context context) { this(context, null); } public RatioLayout(Context context, AttributeSet attrs) { super(context, attrs); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RatioLayout); mRatio = typedArray.getFloat(R.styleable.RatioLayout_ratio, 1); ratioMode = typedArray.getInt(R.styleable.RatioLayout_ratioMode, RATIOMODE_WIDTH); typedArray.recycle(); } public void setRatio(float ratio) { mRatio = ratio; } public void setRatioMode(int ratioMode) { this.ratioMode = ratioMode; } /* 根据固定的宽计算高 宽是已经确定的 高需要根据ratio来确定 */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); if (widthMode == MeasureSpec.EXACTLY && ratioMode == RATIOMODE_WIDTH) { int width = MeasureSpec.getSize(widthMeasureSpec); //拿到了控件的宽 int height = (int) ((width / mRatio) + .5f); setMeasuredDimension(width, height); setAndMeasureChilds(width, height); } else if (heightMode == MeasureSpec.EXACTLY && ratioMode == RATIOMODE_HEIGHT) { //如果高度已经确定的话 int height = MeasureSpec.getSize(heightMeasureSpec); //拿到了控件的宽 int width = (int) ((height * mRatio) + .5f); setMeasuredDimension(width, height); setAndMeasureChilds(width, height); } else { super.setMeasuredDimension(widthMeasureSpec, heightMeasureSpec); } } /** * 得到子控件应有的宽和高,然后调用方法测量子控件的宽和高 * @param width * @param height */ private void setAndMeasureChilds(int width, int height) { int childWidth = width - getPaddingLeft() - getPaddingRight(); int childHeight = height - getPaddingTop() - getPaddingBottom(); int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY); int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY); measureChildren(childWidthMeasureSpec, childHeightMeasureSpec); } }

II.attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="RatioLayout">
<attr name="ratio" format="float"></attr>
<attr name="ratioMode" format="enum">
<enum name="width" value="0"></enum>
<enum name="height" value="1"></enum>
</attr>
</declare-styleable>
</resources>