Android关于不同分辨率下图片被拉伸、压缩而失真的解决方案

说个关于图片适配的方法,关于图片适配相信网上大把资料,在2.1之前,没有适配的概念,随着手机尺寸和分辨率越来越多,适配的问题就不得不被提出来,在2.1之后,存放图片资源的文件夹由原来的drawable变成了drawable-hdpi、drawable-mdpi和drawable-ldpi,这是为了支持不同终端设备的不同分辨率。

大概的可以描述为: 

(1)drawable-hdpi里面存放高分辨率的图片,如WVGA(480x800),FWVGA(480x854)
(2) drawable-mdpi里面存放中等分辨率的图片,如(320x480)
(3) drawable-ldpi里面存放低分辨率的图片,如QVGA(240x320)

如果想要实现适配,即在几个文件夹各放一套图片,程序执行时,系统会自动加载对应文件夹下的资源,这种方式是最常见的。

有种情况是,当图片是从网上获取,并且需要布局在屏幕上,而且通常是一组图片,这时候,为了尽量减少资源的占用和效率的提高,往往会采用别的方式。

最近做项目遇到这个问题,就写出来大家分享下:服务器固定宽高比的图片,获取下来之后布局到不同分辨率的手机,分辨率大的的手机图片显示太小,分辨率小的图片显示过大,想过固定ImageView的宽,高,后来觉得不是太完美,就想着是不是可以用一个容器,将ImageVIew放进去,只要将容器的宽高比设置成图片的宽高比,这样图片不会失真,不会出现被拉伸,压缩的情况。

于是动手写代码:

首先继承FrameLayout ,因为在几个常用的Layout中,FrameLayout算是最纯净的:

public class MyRatioLayout extends FrameLayout {
private float mPicRatio; // 图片的宽高比,如果设置为零,则不会影响图片原始显示
public static final intKNOWN_WIDTH = 0;// 给定宽度,根据图片宽高比,可以计算出容器高度
public static final intKNOWN_HEIGHT= 1;// 给定高度,根据图片宽高比,可以计算出容器宽度


private in relative = KNOWN_HEIGHT;


public void setPicRatio(float picRatio) {
mPicRatio = picRatio;
}


public void setRelative(int relative) {
this.relative = relative;
}


public RatioLayout(Context context) {
// super(context);
this(context, null);
}


public RatioLayout(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RatioLayout);
// 将mPicRatio设置为属性值,在xml中可以动态设置
mPicRatio = typedArray.getFloat(R.styleable.RatioLayout_picRatio, 0);
relative = typedArray.getInt(R.styleable.RatioLayout_relative, 0);
typedArray.recycle();


}


// onmeasure


@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int parentWidthMode = MeasureSpec.getMode(widthMeasureSpec);
int parentHeightMode = MeasureSpec.getMode(heightMeasureSpec);// match_prent 100dp


// AT_MOST
// EXACTLY 100dp 20dp match_parent
// UNSPECIFIED wrap_content

//当宽度固定的时候,可以动态计算高度,保证维持图片原来的比例不失真
if (parentWidthMode == MeasureSpec.EXACTLY && mPicRatio != 0 && relative ==KNOWN_WITH) {// 宽度固定
// 得到控件的宽度
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
// 计算控件的高度
// 图片宽高比 = parentWidth/parentHeight
int parentHeight = (int) (parentWidth / mPicRatio + .5f);


// 得到图片控件宽度
int childWidth = parentWidth - getPaddingLeft() - getPaddingRight();
int childHeight = parentHeight - getPaddingTop() - getPaddingBottom();


// 测绘孩子
int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY);
int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY);
measureChildren(childWidthMeasureSpec, childHeightMeasureSpec);


// 设置自身测绘的结果
setMeasuredDimension(parentWidth, parentHeight);
} else if (parentHeightMode == MeasureSpec.EXACTLY && mPicRatio != 0 && relative ==KNOWN_HEIGHT) {

//当高度固定的时候,可以动态计算宽度,保证维持图片原来的比例不失真
// 得到控件的高度
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
// 动态计算控件宽度
// 图片的宽高比 = parentWidth/parentHeight
int parentWidth = (int) (mPicRatio * parentHeight + .5f);


// 计算孩子的宽度和高度
// 得到图片控件宽度
int childWidth = parentWidth - getPaddingLeft() - getPaddingRight();
int childHeight = parentHeight - getPaddingTop() - getPaddingBottom();


// 让孩子测绘
int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY);
int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY);
measureChildren(childWidthMeasureSpec, childHeightMeasureSpec);


// 设置自身测绘的结果
setMeasuredDimension(parentWidth, parentHeight);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}


}

关于属性的xml代码,这里就不贴了,很简单,有一个问题,在使用自定义控件的时候一定要注意命名空间的问题。这样重写之后,不仅可以将ImageView放进去,还可以将Button,TextView等等,应用场景需要都可以直接放进去使用,下面第一幅是定义图片宽高比ratio=2,并且可以获得屏幕宽度

值,动态计算高度,第二幅ratio=3;同样也可以设置高度固定,宽度动态改变,只需要在使用时,获取设置高度,然后将relative设置成KNOWN_HEIGHT,即可;



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值