说个关于图片适配的方法,关于图片适配相信网上大把资料,在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,即可;