本章节讲述Android屏幕的基础知识
1.基本概念讲解
1.1.屏幕尺寸
含义:手机对角线的物理尺寸。
单位:英寸(inch),1英寸=2.54cm。
1.2.屏幕分辨率
含义:手机在横向、纵向上的像素点数总和。
一般描述成屏幕的"宽x高”=AxB:屏幕在横向方向(宽度)上有A个像素点,在纵向方向(高)有B个像素点。
例子:1080x1920,即宽度方向上有1080个像素点,在高度方向上有1920个像素点。
UI设计师的设计图会以px作为统一的计量单位。
Android手机常见的分辨率:320x480、480x800、720x1280、1080x1920。
附 目前手机主流分辨率列表:
链接2:https://material.io/tools/devices/
1.3.屏幕像素密度
含义:每英寸的像素点数。
单位:dpi(dots per ich)有的也说PPI(PX PER INCH)。
其中:
dpi: 像素密度,在系统软件上指定的单位尺寸的像素数,可认为调整,dpi没有认为调整时==ppi。
ppi:像素密度,每英寸所包含的像素数,屏幕物理参数,不可调整,ppi==dpi没有认为调整时。
1.4.密度无关像素
含义:density-independent pixel,叫dp或dip,与终端上的实际物理像素点无关。
单位:dp,可以保证在不同屏幕像素密度的设备上显示相同的效果。
1.5.独立比例像素
含义:scale-independent pixel,叫sp或sip。
单位:sp。
1.6.屏幕尺寸、分辨率、像素密度三者关系
1.7.dp与px的转换
因为ui设计师给你的设计图是以px为单位的,Android开发则是使用dp作为单位的,那么我们需要进行转换:
| 密度类型 | 代表的分辨率(px) | 屏幕密度(dpi)|换算(px/dp)
| 低密度(ldpi) | 240x320 | 120 |1dp=0.75px (过时)
| 中密度(mdpi) | 320x480 | 160 |1dp=1px 2
| 高密度(hdpi) | 480x800 | 240|1dp=1.5px 3
| 超高密度(xhdpi) | 720x1280 | 320|1dp=2px 4
| 超超高密度(xxhdpi) | 1080x1920 | 480 |1dp=3px 6
| 超超超高密度(xxXhdpi) | 1440x3120 | 640 |1dp=4px 8
Google官方指定按照下列标准进行区分
在Android中,规定以160dpi(即屏幕分辨率为320x480)为基准:1dp=1px
在设计图标时,对于五种主流的像素密度(MDPI、HDPI、XHDPI、XXHDPI 和 XXXHDPI)应按照 2:3:4:6:8 的比例进行缩放。例如,一个启动图标的尺寸为48x48 dp,这表示在 MDPI 的屏幕上其实际尺寸应为 48x48 px,在 HDPI 的屏幕上其实际大小是 MDPI 的 1.5 倍 (72x72 px),在 XDPI 的屏幕上其实际大小是 MDPI 的 2 倍 (96x96 px),依此类推。
虽然 Android 也支持低像素密度 (LDPI) 的屏幕,但无需为此费神,系统会自动将 HDPI 尺寸的图标缩小到 1/2 进行匹配。
下图为图标的各个屏幕密度的对应尺寸
2.屏幕适配问题的本质
使得“布局”、“布局组件”、“图片资源”、“用户界面流程”匹配不同的屏幕尺寸。
使得“图片资源”匹配不同的屏幕密度。
2.1.布局匹配
使得布局元素自适应屏幕尺寸。即根据需求使用相应的布局。
开发中,我们使用的布局一般有:
线性布局(Linearlayout)
相对布局(RelativeLayout)
帧布局(FrameLayout)
动画布局(ConstraintLayout)详情:Android ConstraintLayout相关属性详解
绝对布局(AbsoluteLayout)(停止使用)
2.2.尺寸(size)限定符
2.3.最小宽度(Smallest-width)限定符
2.4.使用布局别名
2.5.使用屏幕方向限定符
2.6.图片资源匹配
2.6.1.使用.9图片。
关于高清设计图尺寸Google官方给出的高清设计图尺寸有两种方案。
一种是以mdpi设计,然后对应放大得到更高分辨率的图片。
另外一种则是以高分辨率作为设计大小,然后按照倍数对应缩小到小分辨率的图片。
根据经验,我更推荐第二种方法,因为小分辨率在生成高分辨率图片的时候,会出现像素丢失,我不知道是不是有方法可以阻止这种情况发生。
而分辨率可以以1280*720或者是1960*1080作为主要分辨率进行设计。
2.6.2.ImageView的ScaleType属性
设置不同的ScaleType会得到不同的显示效果,一般情况下,设置为centerCrop能获得较好的适配效果。
附:ImageView的ScaleType 属性
1.CENTER /center :按图片的原来size居中显示,当图片长/宽超过View的长/宽,则截取图片的居中部分显示。
2.CENTER_CROP / centerCrop :按比例扩大图片的size居中显示,使得图片长(宽)等于或大于View的长(宽)。
3.CENTER_INSIDE / centerInside :将图片的内容完整居中显示,通过按比例缩小或原来的size使得图片长/宽等于或小于View的长/宽。
4.FIT_CENTER / fitCenter :把图片按比例扩大/缩小到View的宽度,居中显示。
5.FIT_END / fitEnd:把图片按比例扩大/缩小到View的宽度,显示在View的下部分位置。
6.FIT_START / fitStart:把图片按比例扩大/缩小到View的宽度,显示在View的上部分位置。
7.FIT_XY / fitXY:把图片不按比例扩大/缩小到View的大小显示。
8.MATRIX / matrix:用矩阵来绘制,动态缩小放大图片来显示。
2.7.动态设置
有一些情况下,我们需要动态的设置控件大小或者是位置,比如说popwindow的显示位置和偏移量等,这个时候我们可以动态的获取当前的屏幕属性,然后设置合适的数值。再比如说banner图设计宽度为屏幕的宽度,高度为屏幕高度的1/3.
3.Android系统适配原则
Android为了更好地优化应用在不同屏幕密度下的用户体验,在项目的res目录下可以创建drawab目录,开发者在进行APP开发时,针对不同的屏幕密度,将图片放置于对应的drawable目录,Android系统会依据特定的原则来查找各drawable目录下的图片。查找流程为:
3.1. 先查找和屏幕密度最匹配的文件夹。如当前设备屏幕密度dpi为160,则会优先查找drawable-mdpi目录;如果设备屏幕密度dpi为420,则会优先查找drawable-xxhdpi目录。
3.2. 如果在最匹配的目录没有找到对应图片,就会向更高密度的目录查找,直到没有更高密度的目录。例如,在最匹配的目录drawable-mdpi中没有查找到,就会查找drawable-hdpi目录,如果还没有查找到,就会查找drawable-xhdpi目录,直到没有更高密度的drawable目录。
3.3. 如果一直往高密度目录均没有查找,Android就会查找drawable目录。drawable目录中的资源适用于所有密度的设备,不管当前屏幕的密度如何,系统都不会缩放此目录中的资源。因此,对于永远不希望系统缩放的资源,最简单的方法就是放在此目录中;同时,放在该目录中的资源最好不要再放到其他drawable目录下了,避免得到非预期的效果。
3.4. 如果在drawable目录也没有查找到,系统就会向比最匹配目录密度低的目录依次查找,直到没有更低密度的目录。例如,最匹配目录是xxhdpi,更高密度的目录和drawable目录查找不到后,就会依次查找drawable-xhdp、drawable-hdpi、drawable-mdpi、drawable-ldpi。
举个例子,假如当前设备的dpi是320,系统会优先去drawable-xhdpi目录查找,如果找不到,会依次查找xxhdpi → xxxhdpi → hdpi → mdpi → ldpi。对于不存在的drawable目录直接跳过,中间任一目录查找到资源,则停止本次查找。
总结一下图片查找过程:优先匹配最适合的图片→查找密度高的目录(升序)→查找密度低的目录(降序)。
按上面的原理
只需选择唯一一套分辨率规格的图片资源
(
每个分辨率下都生成一套图片 是常见的一种方案,这固然是一种解决办法。
但缺点在于:
每套分辨率出一套图,为美工或者设计增加了许多工作量 对Android工程文件的apk包变的很大
)
那么应该提供哪种分辨率规格呢
如果只提供ldpi规格的图片,对于大分辨率(xdpi、xxdpi)的手机如果把图片放大就会不清晰。
所以需要提供一套你需要支持的最大dpi分辨率规格的图片资源,这样即使用户的手机分辨率很小,这样图片缩小依然很清晰。那么这一套最大dpi分辨率规格应该是哪种呢?是现在市面手机分辨率最大可达到1080X1920的分辨率(dpi=xxdpi=480)
xhdpi应该是首选
原因如下:
xhdpi分辨率以内的手机需求量最旺盛
目前市面上最普遍的高端机的分辨率还多集中在720X1080范围内(xhdpi),所以目前来看xhpdi规格的图片资源成为了首选。
节省设计资源&工作量
在现在的App开发中(iOS和Android版本),有些设计师为了保持App不同版本的体验交互一致,可能会以iPhone手机为基础进行设计,包括后期的切图之类的。
设计师们一般都会用最新的iPhone6和iPhone5s(5s和5的尺寸以及分辨率都一样)来做原型设计,所有参数请看下图
|机型| 分辨率(px) | 屏幕尺寸(inch) | 系统密度(dpi)|
| ------------- |:-------------:| -------------:|
|iPhone 5s| 640X1164 | 4 | 332 |
|iPhone 6| 1334x750 | 4.7 | 326 |
| iPhone 6 Plus | 1080x1920 |5| 400 |
iPhone主流的屏幕dpi约等于320, 刚好属于xhdpi,所以选择xhdpi作为唯一一套dpi图片资源,可以让设计师不用专门为Android端切图,直接把iPhone的那一套切好的图片资源放入drawable-xhdpi文件夹里就好,这样大大减少的设计师的工作量。
4.px+dp+sp相互转换
工具类
public class DisplayUtil {
/**
* 获取屏幕宽度 单位px
*/
public static int getScreenWidth(Context context) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
int width = wm.getDefaultDisplay().getWidth();
return width;
}
/**
* 获取屏幕高度 单位px
*/
public static int getScreenHeight(Context context) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
int height = wm.getDefaultDisplay().getHeight();
return height;
}
/**
* 根据手机分辨率从DP转成PX
*/
public static int dip2px(Context context, float dpValue) {
float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
* 根据手机的分辨率PX(像素)转成DP
*/
public static int px2dip(Context context, float pxValue) {
float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
/**
* 将sp值转换为px值,保证文字大小不变
*/
public static int sp2px(Context context, float spValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (spValue * fontScale + 0.5f);
}
/**
* 将px值转换为sp值,保证文字大小不变
* 由于density和scaledDensity取值一样 所以 px转dp和px转 sp一样
*/
public static int px2sp(Context context, float pxValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (pxValue / fontScale + 0.5f);
}
/**
* 获取屏幕密度 0.75 1.0 1.5 2.0
*/
public static float getScreenDensity(Context context) {
DisplayMetrics dm = context.getResources().getDisplayMetrics();
float density = dm.density;
return density;
}
}