近期要做一款手机APP,要自己PS设计界面。在学习Android的UI设计过程中,在网上看了很多资料,记得自己以前在界面编程中也经常在这方面混淆,就顺便整理了一下。若有错误,欢迎在下面评论中指正。首先,需要了解几个概念:
1.屏幕尺寸/大小Screen size
显示屏幕的实际大小,指的是屏幕对角线的物理尺寸,以英寸(inch)为单位。比如某某手机为“5寸大屏手机”,就是指对角线的尺寸,5寸×2.54厘米/寸=12.7厘米。
为简单起见,Android把所有的屏幕大小分为四种尺寸:小,普通,大,超大(分别对应:small, normal, large, and extra large)。应用程序可以为这四种尺寸分别提供不同的自定义屏幕布局-平台将根据屏幕实际尺寸选择对应布局进行渲染,这种选择对于程序侧是透明的,不需要程序员用代码来干预的。
2.屏幕长宽比Aspect ratio
屏幕的物理长度与物理宽度的比例。程序可以为制定长宽比的屏幕提供制定的素材,只需要用系统提供的资源分类符long和notlong。
3.屏幕分辨率Resolution
屏幕的像素点数,一般描述成屏幕的“宽×高”,Android手机屏幕常见的分辨率有480×800、720×1280、1080×1920等。720×1280表示此屏幕在宽度方向有720个像素,在高度方向有1280个像素。
需要注意的是:尽管分辨率通常用宽x高表示,但分辨率并不意味着具体的屏幕长宽比。在Andorid系统中,应用程序不直接使用分辨率。
4.密度Density(dpi,dots per inch;或PPI,pixels per inch)
从英文顾名思义,就是每英寸的像素点数,数值越高当然显示越细腻。假如我们知道一部手机的分辨率是1080×1920,屏幕大小是5英寸,能否算出此屏幕的密度呢?通过宽1080和高1920,根据勾股定理,我们得出对角线的像素数大约是2203,那么用2203除以5就是此屏幕的密度了,计算结果是440。440dpi的屏幕已经相当细腻了。
根据像素分辨率,在屏幕指定物理宽高范围内能显示的像素数量。在同样的宽高区域,低密度的显示屏能显示的像素较少,而高密度的显示屏则能显示更多的像素。屏幕密度非常重要,因为其它条件不变的情况下,一共宽高固定的UI组件(比如一个按钮)在低密度的显示屏上显得很大,而在高密度显示屏上看起来就很小。
为简单起见,Android把所有的屏幕分辨率也分为四种尺寸:小,普通,大,超大(分别对应:small, normal, large, and extra large)。应用程序可以为这四种尺寸分别提供不同的资源-平台将透明的对资源进行缩放以适配指定的屏幕分辨率,这种选择对于程序侧是透明的,不需要程序员用代码来干预的。。
PS.实际密度与系统密度
“实际密度”就是我们自己算出来的密度,这个密度代表了屏幕真实的细腻程度,如上述例子中的440dpi就是实际密度,说明这块屏幕每寸有440个像素。5英寸1080×1920的屏幕密度是440,而相同分辨率的4.5英寸屏幕密度是490。如此看来,屏幕密度将会出现很多数值,呈现严重的碎片化。而密度又是Android屏幕将界面进行缩放显示的依据,那么Android是如何适配这么多屏幕的呢?
其实,每部Android手机屏幕都有一个初始的固定密度,这些数值是120、160、240、320、480,我们权且称为“系统密度”。大家发现规律没有?相隔数值之间是2倍的关系。一般情况下,240×320的屏幕是低密度120dpi,即ldpi;320×480的屏幕是中密度160dpi,即mdpi;480×800的屏幕是高密度240dpi,即hdpi;720×1280的屏幕是超高密度320dpi,即xhdpi;1080×1920的屏幕是超超高密度480dpi,即xxhdpi。
Android对界面元素进行缩放的比例依据正是系统密度,而不是实际密度。
5.设备独立像素Density-independent pixel (dp/dip)
指一个抽象意义上的像素,程序用它来定义界面元素。它作为一个与实际密度无关的单位,帮助程序员构建一个布局方案(界面元素的宽度,高度,位置)。
你可以想象dp更类似一个物理尺寸,比如一张宽和高均为100dp的图片在320×480和480×800的手机上“看起来”一样大。而实际上,它们的像素值并不一样。dp正是这样一个尺寸,不管这个屏幕的密度是多少,屏幕上相同dp大小的元素看起来始终差不多大。
另外,文字尺寸使用sp,即scale-independentpixel的缩写,这样,当你在系统设置里调节字号大小时,应用中的文字也会随之变大变小。
PS.dp与px的转换
在Android中,系统密度为160dpi的中密度手机屏幕为基准屏幕,即320×480的手机屏幕。在这个屏幕中,1dp=1px。
100dp在320×480(mdpi,160dpi)中是100px。那么100dp在480×800(hdpi,240dpi)的手机上是多少px呢?我们知道100dp在两个手机上看起来差不多大,根据160与240的比例关系,我们可以知道,在480×800中,100dp实际覆盖了150px。因此,如果你为mdpi手机提供了一张100px的图片,这张图片在hdpi手机上就会拉伸至150px,但是他们都是100dp。
dp与px的换算要以系统密度为准,720×1280的系统密度为320,320×480的系统密度为160,320/160=2,那么在 720×1280中,1dp=2px。同理,在1080×1920中,1dp=3px。
大家可以记住下面这个比例,dp与px的换算就十分easy啦!
ldpi:mdpi:hdpi:xhdpi:xxhdpi=3:4:6:8:12,我们发现,相隔数字之间还是2倍的关系。计算的时候,以mdpi为基准。比如在720×1280(xhdpi)中,1dp等于多少px呢?mdpi是4,xhdpi是8,2倍的关系,即1dp=2px。反着计算更重要,比如你用PhotoShop在720×1280的画布中制作了界面效果图,两个元素的间距是20px,那要标注多少dp呢?2倍的关系,那就是10dp!
当Android系统字号设为“普通”时,sp与px的尺寸换算和dp与px是一样的。比如某个文字大小在720×1280的PS画布中是24px,那么告诉工程师,这个文字大小是12sp。
PS. Android上获取屏幕分辨率信息的方法
Android上有两种获取屏幕分辨率信息的方法,分别是通过DisplayMetrics类和WindowManager类来实现。
DisplayMetrics metrics = newDisplayMetrics();
Display display =activity.getWindowManager().getDefaultDisplay();
display.getMetrics(metrics);
//这里得到的像素值是设备独立像素dp
//DisplayMetricsmetrics=activity.getResources().getDisplayMetrics(); 这样获得的参数信息不正确,不要使用这种方式。
不能使用android.content.res.Resources.getSystem().getDisplayMetrics()。这个得到的宽和高是空的。
private void initResolutionStr(Context context) {
if (ApiConfig.getResolutionStr()== null || ApiConfig.getResolutionStr().equals("")) {
WindowManager winMgr =(WindowManager)context.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
Display display =winMgr.getDefaultDisplay();
int height =display.getHeight();
int width =display.getWidth();
String resolution = height> width ? height + "x" + width : width + "x" + height;
ApiConfig.setResolutionStr(resolution);
// densityDpi = 120dpi isldpi, densityDpi = 160dpi is mdpi,
// densityDpi = 240dpi ishdpi, densityDpi = 320dpi is xhdpi
DisplayMetrics dm = newDisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int densityDpi =dm.densityDpi;
ApiConfig.setDensityDpi(densityDpi);
}
}
关于屏幕适配,以前只考虑到界面编程,忽视了前期的UI设计,往往是适配出现问题了,在界面编程无法解决再去找设计师改图。如今要自己设计UI,原来这方面也是有考究的。这部分主要注意到两方面:
1.UI设计-建议在xdhpi中作图
最好在xhdpi中作图。如今Android手机有很多屏幕,作图时并没有必要为不同密度的手机都提供一套素材,大部分情况下,一套就够了。现在手机比较高的分辨率是1080×1920,你可以选择这个尺寸作图,但是图片素材将会增大应用安装包的大小。并且尺寸越大的图片占用的内存也就越高。如果不是设计ROM,而是做一款应用,建议用PS在720×1280的画布中作图。这个尺寸兼顾了美观性、经济性和计算的简单。美观性是指,以这个尺寸做出来的应用,在720×1280中显示完美,在1080×1920中看起来也比较清晰;经济性是指,这个分辨率下导出的图片尺寸适中,内存消耗不会过高,并且图片文件大小适中,安装包也不会过大;计算的简单,就是1dp=2px。最后记得做出来的图片,放进drawable-xhdpi的资源文件夹中。
2.界面编程-解决屏幕宽高差异
在720×1280中作图,要考虑向下兼容不同的屏幕。通过计算我们可以知道,320×480和480×800的屏幕宽度都是320dp,而720×1280和1080×1920的屏幕宽度都是360dp。它们之间有40dp的差距,这40dp在设计中影响还是很大的。如下图蝴蝶图片距离屏幕的左右边距在320dp宽的屏幕和360dp宽的屏幕中就不一样。
不仅宽度上有差异,高度上的差异更加明显。对于天气等工具类应用,由于界面一般是独占式的,更要考虑屏幕之间的比例差异。
如果想消除这些比例差异,可以通过添加布局文件来实现。一般情况下,布局文件放在layout文件夹中,如果要单独对360dp的屏幕进行调整,你可以单做做一个布局文件放在layout-w360dp中;不过,最好是默认针对360dp的屏幕布局(较为主流),然后对320dp的屏幕单独布局,将布局文件放到layout-w320dp中;如果你想对某个特殊的分辨率进行调整,那么你可以将布局文件放在标有分辨率的文件夹中,如layout-854×480。
介绍到layout文件夹,相对的,drawable文件夹也要相应要求。
在720×1280中做了图片,要让开发人员放到drawable-xhdpi的资源文件夹中,这样才可以显示正确。个人认为仅提供一套素材就可以了,可以测试一下应用在低端手机上运行是否流畅,如果比较卡顿,可以根据需要提供部分mdpi的图片素材,因为xhdpi中的图片运行在mdpi的手机上会比较占内存。
以应用图标为例,xhdpi中的图标大小是96px,如果要单独给mdpi提供图标,那么这个图标大小是48px,放到drawable-mdpi的资源文件夹中。各个资源文件夹中的图片尺寸同样符合ldpi:mdpi:hdpi:xhdpi:xxhdpi=3:4:6:8:12的规律。
如果你把一个高2px的分割线素材做成了9.png图片,你想让细线在不同密度中都是2px,而不被Android根据密度进行缩放,怎么办?你可以把这个分割线素材放到drawable-nodpi中,这个资源文件夹中的图片,将按照实际像素大小进行显示,而不会被Android根据密度进行缩放。即在mdpi中细线是 2px(2dp),在xhdpi中细线是2px(1dp)。
如果需要为Android定制资源文件,则res目录下的目录可能为:
drawable: | | values: |
drawable-ldpi | | values-ldpi |
drawable-mdpi | | values-mdpi |
drawable-hdpi | | values-hdpi |
drawable-xhdpi | | values-xhdpi |
drawable-nodpi | | values-nodpi |
drawable-nodpi-1024×600 | | values-nodpi-1024×600 |
drawable-nodpi-1280×800 | | values-nodpi-1280×800 |
drawable-nodpi-800×480 | | values-nodpi-800×480 |
PS.屏幕适配的注意事项
1、基本设置
1.1 AndroidManifest.xml设置
在Manifest中添加子元素android:anyDensity="true"时,应用程序安装在不同密度的终端上时,程序会分别加载xxhdpi、xhdpi、hdpi、mdpi、ldpi文件夹中的资源(默认就是?)。相反,如果设为false,即使在文件夹下拥有相同资源,应用不会自动地去相应文件夹下寻找资源:如果drawable-hdpi、drawable-mdpi、drawable-ldpi三个文件夹中有同一张图片资源的不同密度表示,那么系统会去加载drawable_mdpi文件夹中的资源;如果drawable-hpdi中有高密度图片,其它两个文件夹中没有对应图片资源,那么系统会去加载drawable-hdpi中的资源,其他同理;如果drawable-hdpi和drawable-mdpi中有图片资源,drawable-ldpi中没有,系统会加载drawable-mdpi中的资源,其他同理,使用最接近的密度级别。
1.2 横屏竖屏目录区分
drawable:drawable-hdpi该图片即适用于横屏,也适用于竖屏;drawable-land-hdpi当屏幕为横屏,且为高密度时,加载此文件夹的资源;drawable-port-hdpi当屏幕为竖屏,且为高密度时,加载此文件夹中的资源。其他同理。
layout:在res目录下建立layout-port和layout-land两个目录,里面分别放置竖屏和横屏两种布局文件,以适应对横屏竖屏自动切换。
2、多屏幕适配的黄金原则
1) 在layout文件中设置控件尺寸时应采用fill_parent、wrap_content、match_parent、dp、sp。
2) 在程序的代码中不要出现具体的像素值,在dimens.xml中定义。为了使代码简单,android内部使用pix为单位表示控件的尺寸,但这是基于当前屏幕基础上的。为了适应多种屏幕,android建议开发者不要使用具体的像素来表示控件尺寸。
3) 不使用AbsoluteLayout(android1.5已废弃) ,可使用RelativeLayout替代。
4) 对不同的屏幕提供合适大小的图片。不同大小屏幕用不同大小的图片,low:medium:high:extra-high图片大小的比例为3:4:6:8;举例来说,对于中等密度(medium)的屏幕你的图片像素大小为48×48,那么低密度(low)屏幕的图片大小应为36×36,高(high)的为72×72,extra- high为96×96。
5) 使用9-patch PNG图片。使用图片资源时,如果出现拉伸,因为图片处理的原因,会变形,导致界面走形。9-patch PNG图片也是一种标准的PGN图片,在原生PNG图片四周空出一个像素间隔,用来标识PNG图片中哪些部分可以拉伸、哪些不可以拉伸、背景上的边框位置等。“上、左”定义可拉伸区域;“右、下”定义显示区域,如果用到完整填充的背景图,建议不要通过android:padding来设置边距,而是通过9-patch方式来定义。Android SDK中提供了编辑9-Patch图片的工具,在tools目录下draw9patch.bat,能够立刻看到编辑后的拉伸效果,也可以直接用其他图片编辑工具编辑,但是看不到效果。
6) 对某些特殊的分辨率提供不同的layout。