Android屏幕适配主要包含三个方面
- 屏幕像素密度(ldpi,mdpi,hdpi,xhdpi,xxhdpi,xxxhdpi)
- 屏幕尺寸(分辨率,最小屏幕宽度,最小宽度,最小高度)
- 屏幕方向(竖屏,横屏)
屏幕像素密度
adb命令:
adb shell wm density
例子:三星G9500
Physical density: 480
Override density: 420
Physical density:屏幕物理像素密度
Override density:屏幕覆写像素密度(通过软件修改)
屏幕分辨率
adb命令:
adb shell wm size
例子:三星G9500
Physical size: 1440*2960
Override size: 1080*2220
Physical size:屏幕物理分辨率
Override size:屏幕覆写分辨率(通过软件修改)
图片分辨率
图片分辨率小于ImageView尺寸
ImageView的scaleType属性设置为fitXY,当图片分辨率小于ImageView尺寸时,会对图片进行拉伸,使图片尺寸等于ImageView尺寸。
图片分辨率大于ImageView尺寸
ImageView的scaleType属性设置为fitXY,当图片分辨率大于ImageView尺寸时,会对图片进行压缩,使图片尺寸等于ImageView尺寸。
当图片分辨率大于ImageView尺寸时,需要先计算图片的采样率,尽可能压缩图片,这样才能减少解码图片资源以获取Bitmap对象时的内存占用。
图片的采样率计算方法如下:
//从资源文件中获取相应的图片
public Bitmap decodeSampleBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {
BitmapFactory.Options options = new BitmapFactory.Options();
//设置只加载宽高标志位
options.inJustDecodeBounds = true;
//加载原始图片宽高到Options中
BitmapFactory.decodeResource(res, resId, options);
//通过所需图片宽高和原始图片宽高计算采样率
options.inSampleSize = calculateSampleSize(reqWidth, reqHeight, options);
//还原并再次加载图片
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
//从文件描述符中获取相应的图片
public Bitmap decodeSampleBitmapFromFileDescriptor(FileDescriptor fd, int reqWidth, int reqHeight) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFileDescriptor(fd, null, options);
options.inSampleSize = calculateSampleSize(reqWidth, reqHeight, options);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFileDescriptor(fd, null, options);
}
//计算采样率
public static int calculateSampleSize(int reqWidth, int reqHeight, BitmapFactory.Options options) {
//如果传入0参数,则将采样率设成1,即不压缩
if (reqWidth == 0 || reqHeight == 0) {
return 1;
}
int inSampleSize = 1;
int width = options.outWidth;
int height = options.outHeight;
//当所需宽高比实际宽高小时才进行压缩
if(reqWidth < width && reqHeight < height) {
int halfWidth = width / 2;
int halfHeight = height / 2;
//保证压缩后的宽高不能小于所需宽高
while(reqWidth <= halfWidth && reqHeight <= halfHeight) {
inSampleSize *= 2;
halfWidth /= 2;
halfHeight /= 2;
}
}
return inSampleSize;
}
资源文件夹
资源文件夹下各目录的含义
1.与屏幕像素密度相关
ldpi,mdpi,hdpi,xhdpi,xxhdpi,xxxhdpi对应的屏幕像素密度:
注意:默认目录与mdpi目录对应的屏幕像素密度相同。
运行设备为三星G9500,屏幕像素密度为420,目录选择方法如下:
420对应的dpi范围为320~480,因此对应的目录为xxhdpi,如果该目录下有相应的资源文件则直接使用,否则按照以下顺序继续查找:
xxhdpi -> xxxhdpi -> xhdpi -> nodpi -> hdpi -> mdpi -> 默认 -> ldpi
运行设备为三星C7100,屏幕像素密度为420,目录选择方法如下:
420对应的dpi范围为320~480,因此对应的目录为xxhdpi,如果该目录下有相应的资源文件则直接使用,否则按照以下顺序继续查找:
xxhdpi -> xxxhdpi -> xhdpi -> hdpi -> nodpi -> mdpi -> 默认 -> ldpi
2.与屏幕尺寸相关
- sw<N>dp,如layout-sw400dp
sw是smallestwidth的缩写,当屏幕的最小宽度大于等于400dp时,就会到带sw400dp后缀的目录找相关资源,这里的最小宽度是指屏幕宽跟高的较小值,每个屏幕都是固定的,不会随着屏幕横向纵向的改变而改变。 - w<N>dp,如layout-w400dp
当屏幕宽度大于等于400dp时,就会到带w400dp后缀的目录找相关资源文件,它和sw400dp不同的是,当屏幕横向纵向切换时,屏幕的宽度是变化的,以变化后的宽度来与400dp相比,看是否使用此目录下的资源。 - h<N>dp,如layout-h400dp(很少使用)
当屏幕高度大于等于400dp时,就会到带h400dp后缀的目录找相关资源文件,它和sw400dp不同的是,当屏幕横向纵向切换时,屏幕的高度是变化的,以变化后的高度来与400dp相比,看是否使用此目录下的资源。 - height*width,如layout-2094x1080
当屏幕分辨率的高大于等于2094、宽大于等于1080时,就会到带2094x1080后缀的目录找相关资源文件,每个屏幕都是固定的,不会随着屏幕横向纵向的改变而改变。
3.与屏幕方向相关
- layout-sw400dp
竖屏时使用的目录 - layout-sw400dp-land
横屏时使用的目录
4.与运行设备Android API level相关
- layout-v28,运行设备Android API level大于等于28时使用的目录
资源文件夹下的图片加载到内存时分辨率如何计算
例子:
图片原始分辨率为860*318,放在drawable-xxxhdpi目录,运行设备屏幕像素密度420dpi。
分析:
drawable-xxxhdpi目录对应的屏幕像素密度为640dpi,即在该屏幕像素密度的运行设备中,每英寸有640个像素,那么图片宽860个像素在该运行设备中有860/640英寸,图片高318个像素在该运行设备中有318/640英寸,将该图片加载到屏幕像素密度为420dpi的运行设备中,对应的宽有860/640 * 420=564个像素,对应的高有318/640 * 420=209个像素。
资源文件夹下的图片加载为Bitmap时内存如何计算
例子:
图片原始分辨率为860*318,放在drawable-xxxhdpi目录,运行设备屏幕像素密度420dpi。
分析:
由以上分析可知,图片加载到内存时分辨率为564 * 209,而BitmapFactory加载图片时默认的色彩模式为ARGB_8888,即一个像素占4个字节,那么Bitmap占用的内存为564 * 209 * 4=471504字节。
drawable目录跟mipmap目录的区别
在应用内部使用的图片,并不会因为图片是放在mipmap目录还是drawable目录而产生差异,系统都会优先加载跟当前运行设备的像素密度相对应的目录下的图片,只是两个目录下引用图片的路径有所不同:R.drawable.xxx、R.mipmap.xxx。
而在Launcher中使用的应用图标,则必须放在mipmap目录,Launcher会优先加载更加合适的像素密度(有可能跟当前运行设备的像素密度不同)相对应的目录下的图片。
网友评论