Android 万能适配方案和UI屏幕适配 不同分辨率 最全面 最易懂的

屏幕尺寸

屏幕尺寸指屏幕的对角线的长度,单位是英寸,1英寸=2.54厘米(下面有图文介绍)

比如常见的屏幕尺寸有2.4、2.8、3.5、3.7、4.2、5.0、5.5、6.0等

屏幕分辨率

屏幕分辨率是指在横纵向上的像素点数,单位是px,1px=1个像素点。一般以纵向像素*横向像素,如1960*1080。

屏幕像素密度

屏幕像素密度是指每英寸上的像素点数,单位是dpi,即“dot per inch”的缩写。屏幕像素密度与屏幕尺寸和屏幕分辨率有关,在单一变化条件下,屏幕尺寸越小、分辨率越高,像素密度越大,反之越小

  • 当设备的物理尺寸存在差异的时候,dp就显得无能为力了。为4.3寸屏幕准备的UI,运行在5.0寸的屏幕上,很可能在右侧和下侧存在大量的空白。而5.0寸的UI运行到4.3寸的设备上,很可能显示不下。

一句话,总结下,dp能够让同一数值在不同的分辨率展示出大致相同的尺寸大小。但是当设备的尺寸差异较大的时候,就无能为力了。适配的问题还需要我们自己去做,于是我们可能会这么做:
Android   万能适配方案和UI屏幕适配   不同分辨率    最全面  最易懂的 - 阿里云

Android   万能适配方案和UI屏幕适配   不同分辨率    最全面  最易懂的
上述代码片段来自网络,也就是说,我们为了优质的用户体验,依然需要去针对不同的dpi设置,编写多套数值文件。
可以看出,dp并没有能解决适配问题。下面看百分比。

我们再来看看一些适配的tips

  1. 多用match_parent
  2. 多用weight
  3. 自定义view解决

其实上述3点tip,归根结底还是利用百分比,match_parent相当于100%参考父控件;weight即按比例分配;自定义view无非是因为里面多数尺寸是按照百分比计算的;

dp:Density-independent pixel (dp)独立像素密度。标准是160dip.即1dp对应1个pixel,计算公式如:px = dp * (dpi / 160),屏幕密度越大,1dp对应 的像素点越多。 
上面的公式中有个dpi,dpi为DPI是Dots Per Inch(每英寸所打印的点数),也就是当设备的dpi为160的时候1px=1dp;

计算值

ppi的运算方式是:

PPI = √(长度像素数² + 宽度像素数²) / 屏幕对角线英寸数

dp:Density-independent pixels,以160PPI屏幕为标准,则1dp=1px,

dp和px的换算公式 :
dp*ppi/160 = px。比如1dp x 320ppi/160 = 2px。


屏幕尺寸、分辨率、像素密度三者关系(以上三者的关系)

像素密度的公式

一部手机的分辨率是宽x高,屏幕大小是以寸为单位,那么三者的关系是:

Android   万能适配方案和UI屏幕适配   不同分辨率    最全面  最易懂的 - 阿里云
假设一部手机的分辨率是1080×1920(px),屏幕大小是5寸,问密度是多少?

Android   万能适配方案和UI屏幕适配   不同分辨率    最全面  最易懂的 - 阿里云
Android   万能适配方案和UI屏幕适配   不同分辨率    最全面  最易懂的
Android   万能适配方案和UI屏幕适配   不同分辨率    最全面  最易懂的

像素密度计算公式


屏幕多少英寸指的是对角线的长度。像素密度是指(以1920×1080,5英寸为例),1920和1080的平方和开根号(就是直角三角形斜边长的算法),开出来等于2202.9,除以5英寸就得到ppi441左右
例:"HTC One(32GB/单卡/国际版)
4.7英寸屏幕,分辨率1920x1080 求解像素密度?
解:√(1920^2+1080^2)=2202.9071
2202.9/5=468.7021(ppi)≈469ppi
答:此屏幕像素密度约是469ppi.
因为ui设计师给你的设计图是以px为单位的,Android开发则是使用dp作为单位的,那么我们需要进行转换:
                                                                                                                                                                                                       
密度类型 代表的分辨率(px) 屏幕密度(dpi) 换算(px/dp) 比例
低密度(ldpi) 240x320 120(最大) 1dp=0.75px 3
中密度(mdpi) 320x480 160(最大) 1dp=1px 4
高密度(hdpi) 480x800 240(最大) 1dp=1.5px 6
超高密度(xhdpi) 720x1280 320(最大) 1dp=2px 8
超超高密度(xxhdpi) 1080x1920 480(最大) 1dp=3px 12

为了保证用户获得一致的用户体验效果:使得某一元素在Android不同尺寸、不同分辨率的手机上具备相同的显示效果
在进行开发的时候,我们需要把合适大小的图片放在合适的文件夹里面。下面以图标设计为例进行介绍。

Android   万能适配方案和UI屏幕适配   不同分辨率    最全面  最易懂的


下图为图标的各个屏幕密度的对应尺寸:

Android   万能适配方案和UI屏幕适配   不同分辨率    最全面  最易懂的

Android   万能适配方案和UI屏幕适配   不同分辨率    最全面  最易懂的


1).使用自动拉伸位图
.9图片
2).请务必使用 sp 指定文字大小:

3).使用布局别名

最小宽度限定符仅适用于 Android 3.2 及更高版本。因此,如果我们仍需使用与较低版本兼容的概括尺寸范围(小、正常、大和特大)。例如,如果要将用户界面设计成在手机上显示单面板,但在 7 英寸平板电脑、电视和其他较大的设备上显示多面板,那么我们就需要提供以下文件:

  • res/layout/main.xml: 单面板布局

  • res/layout-large: 多面板布局

  • res/layout-sw600dp: 多面板布局

后两个文件是相同的,因为其中一个用于和 Android 3.2 设备匹配,而另一个则是为使用较低版本 Android 的平板电脑和电视准备的。

要避免平板电脑和电视的文件出现重复(以及由此带来的维护问题),您可以使用别名文件。例如,您可以定义以下布局:

  • res/layout/main.xml,单面板布局

  • res/layout/main_twopanes.xml,双面板布局

然后添加这两个文件:

res/values-large/layout.xml:

Android   万能适配方案和UI屏幕适配   不同分辨率    最全面  最易懂的 - 阿里云

res/values-sw600dp/layout.xml:

Android   万能适配方案和UI屏幕适配   不同分辨率    最全面  最易懂的 - 阿里云

后两个文件的内容相同,但它们并未实际定义布局。它们只是将 main 设置成了 main_twopanes 的别名。由于这些文件包含 large 和 sw600dp 选择器,因此无论 Android 版本如何,

系统都会将这些文件应用到平板电脑和电视上(版本低于 3.2 的平板电脑和电视会匹配 large,版本高于 3.2 的平板电脑和电视则会匹配 sw600dp)。


图片的适配方案:
什么叫最适合的图片?比如我的手机屏幕密度是xxhdpi,那么drawable-xxhdpi文件夹下的图片就是最适合的图片。

缩放原理:
例如,一个启动图标的尺寸为48x48 dp,这表示在 MDPI 的屏幕上其实际尺寸应为 48x48 px,在 HDPI 的屏幕上其实际大小是 MDPI 的 1.5 倍 (72x72 px),

在 XDPI 的屏幕上其实际大小是 MDPI 的 2 倍 (96x96 px),依此类推。

虽然 Android 也支持低像素密度 (LDPI) 的屏幕,但无需为此费神,系统会自动将 HDPI 尺寸的图标缩小到 1/2 进行匹配。

放大系数的关系:和屏幕像素密度有关

mdpi密度的最高dpi值是160,而xxhdpi密度的最高dpi值是480,因此是一个3倍的关系。放大系数和文件夹的密度有关系!

xxxhdpi密度的最高dpi值是640,480是它的0.75倍

正常Xhdpi的图片,如果放在了xxhdpi里面,图片会缩小,放在hdpi的里面图片会放大!

一张原图片被缩小了之后显示其实并没有什么副作用,但是一张原图片被放大了之后显示就意味着要占用更多的内存了。
但是一张原图片被放大了之后显示就意味着要占用更多的内存了。因为图片被放大了,像素点也就变多了,而每个像素点都是要占用内存的。 

我们仍然可以通过例子来直观地体会一下,首先将android_logo.png图片移动到drawable-xxhdpi目录下,运行程序后我们通过Android Monitor来观察程序内存使用情况: 

Android   万能适配方案和UI屏幕适配   不同分辨率    最全面  最易懂的


可以看到,程序所占用的内存大概稳定在19.45M左右。然后将android_logo.png图片移动到drawable-mdpi目录下,重新运行程序,结果如下图所示: 
Android   万能适配方案和UI屏幕适配   不同分辨率    最全面  最易懂的



现在涨到23.40M了,占用内存明显增加了。如果你将图片移动到drawable-ldpi目录下,你会发现占用内存会更高。通过这个例子同时也验证了一个问题,我相信有不少比较有经验的Android程序员可能都遇到过这个情况,就是当你的项目变得越来越大,有的时候加载一张drawable-hdpi下的图片,程序就直接OOM崩掉了,但如果将这张图放到drawable-xhdpi或drawable-xxhdpi下就不会崩掉,其实就是这个道理。那么经过上面一系列的分析,答案自然也就出来了,图片资源应该尽量放在高密度文件夹下,这样可以节省图片的内存开支,而UI在设计图片的时候也应该尽量面向高密度屏幕的设备来进行设计。就目前来讲,最佳放置图片资源的文件夹就是drawable-xxhdpi。那么有的朋友可能会问了,不是还有更高密度的drawable-xxxhdpi吗?干吗不放在这里?这是因为,市面上480dpi到640dpi的设备实在是太少了,如果针对这种级别的屏幕密度来设计图片,图片在不缩放的情况下本身就已经很大了,

因为分辨率不一样,所以不能用px;因为屏幕宽度不一样,所以要小心的用dp,那么我们可不可以用另外一种方法来统一单位,不管分辨率是多大,屏幕宽度用一个固定的值的单位来统计呢?

百分比适配方法,对于控件的宽和高!

<TextView android:layout_width="@dimen/x360" android:layout_height="@dimen/x360" android:background="@color/colorAccent" android:gravity="center" android:text="360x360"/><TextView android:layout_width="@dimen/x180" android:layout_height="@dimen/x180" android:background="@color/colorPrimaryDark" android:gravity="center" android:text="180x180"/>
<dimen name="x356">356px</dimen><dimen name="x357">357px</dimen><dimen name="x358">358px</dimen><dimen name="x359">359px</dimen><dimen name="x360">360px</dimen><dimen name="x358">537px</dimen><dimen name="x359">538.5px</dimen><dimen name="x360">540px</dimen><dimen name="x361">541.5px</dimen><dimen name="x362">543px</dimen><dimen name="x363">544.5px</dimen>
Android   万能适配方案和UI屏幕适配   不同分辨率    最全面  最易懂的

Android   万能适配方案和UI屏幕适配   不同分辨率    最全面  最易懂的
总结: 不同分辨率的文件夹有不同x360的px值,是通过程序计算自动生成的!
适配缺点:
所以说,这个方案虽然是一劳永逸,但是由于实际上还是使用的px作为长度的度量单位,所以多少和google的要求有所背离,不好说以后会不会出现什么不可预测的问题。其次,如果要使用这个方案,你必须尽可能多的包含所有的分辨率,因为这个是使用这个方案的基础,如果有分辨率缺少,会造成显示效果很差,甚至出错的风险,而这又势必会增加软件包的大小和维护的难度,所以大家自己斟酌,择优使用。

  • 对于没有考虑到屏幕尺寸,可能会出现意外的情况;
  • apk的大小会增加;

注意的问题:要有一个通用的布局,不然有些手机会报错!


虚拟按键的问题

设计高度 = 屏幕高度 - 状态栏高度
布局高度 = 屏幕高度 - 状态栏高度 - 虚拟按键高度

要解决这个问题,其实很简单,我说过,这不是一个技术问题,因此不必使用 fitsSystemWindows 属性,也避免了副作用。

只需要在布局时,正确理解设计师的意图,比如,如果一个按钮在最底部,你应该用 layout_gravity="bottom" 而不是用 marginTop 或者其他方式来把它撑到底部。



我开始以为他们是导航栏上的虚拟按键,因为确实我将按键隐藏后可以成功适配,然后我就在网上通过如下代码来获取他们的真实分辨率 

/** * @param context * @return 获取屏幕原始尺寸高度,包括虚拟功能键高度 */public static int getTotalHeight(Context context) { int dpi = 0; WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); Display display = windowManager.getDefaultDisplay(); DisplayMetrics displayMetrics = new DisplayMetrics(); @SuppressWarnings("rawtypes") Class c; try { c = Class.forName("android.view.Display"); @SuppressWarnings("unchecked") Method method = c.getMethod("getRealMetrics", DisplayMetrics.class); method.invoke(display, displayMetrics); dpi = displayMetrics.heightPixels; } catch (Exception e) { e.printStackTrace(); } return dpi;}/** * @param context * @return 获取屏幕内容高度不包括虚拟按键 */public static int getScreenHeight(Context context) { WindowManager wm = (WindowManager) context .getSystemService(Context.WINDOW_SERVICE); DisplayMetrics outMetrics = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics(outMetrics); return outMetrics.heightPixels;}

这里我用了三部华为手机通过上面的方法获取分辨率 
华为荣耀8 1080 1920 得到1080 1812 
华为畅享5 720 1280 得到720 1184 
华为畅玩5x 108 1920 得到 1080 1776

通过这两个方法我们可以得到手机的分辨率高度和手机去除虚拟按键的高度,两者相减就是手机的虚拟按键的高度
调用后得到的结果是总高度 : 2560 内容高度 : 2408 虚拟按键 : 152
如果想要适配该机型,其实也很简单,只需要把原来的values-2560x1440文件夹复制一份重新名为values-2408x1440即可,

http://blog.csdn.net/c15522627353/article/details/52452490
Google的 百分比布局库(percent-support-lib)
PercentRelativeLayout、PercentFrameLayout,不过貌似没有LinearLayout,有人会说LinearLayout有weight属性呀。但是,weight属性只能支持一个方向呀~~哈,没事,刚好给我们一个机会去自定义一个PercentLinearLayout

<android.support.percent.PercentRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"> <Viewandroid:id="@+id/top_left"android:layout_width="0dp"android:layout_height="0dp"android:layout_alignParentTop="true"android:background="#ff44aacc"app:layout_heightPercent="20%"app:layout_widthPercent="70%" /> <Viewandroid:id="@+id/top_right"android:layout_width="0dp"android:layout_height="0dp"android:layout_alignParentTop="true"android:layout_toRightOf="@+id/top_left"android:background="#ffe40000"app:layout_heightPercent="20%"app:layout_widthPercent="30%" /> <Viewandroid:id="@+id/bottom"android:layout_width="match_parent"android:layout_height="0dp"android:layout_below="@+id/top_left"android:background="#ff00ff22"app:layout_heightPercent="80%" /></android.support.percent.PercentRelativeLayout>


Android UI适配小结:
1.一般情况下,输出几套,各为多少分辨率不同的质量的切图?
2.一般情况下,输出几套分辨率不同的标注图(如常说的主流四套分辨率,1080*1920,720*1280,480*800.240*320), 标注单位为px还是自己计算的dp(这个单位您一般是自己计算还是交给程序,如果自己计算的话比较好的方法),创建画布时第一版从多少分辨率的画布开始设计。
3.是否考虑带有虚拟按键的适配不同方法?
4.遇到与主流分辨率相近长宽比不同的分辨率时的适配方式。
5.字号的适配方式,字号单位
6.与程序适配沟通时需要注意的要点
7.其它我未提及或者没考虑到的但您觉得非常重要的问题


1.一般只输出主流尺寸的切图,如480*800 1280*720
2.开发写标准尺寸是按照320P来的,得按照你自己的设计稿来标注,不过得算好比例:比如你出了480*800的设计稿,你所有的标注的所有尺寸都得除以1.5;要是出了720*1280的设计稿,你所有的标注的所有尺寸都得除以2,以此类推
3.无需考虑,系统自适应
4.只要宽度分辨率一样,适配一样
5.字号跟第2点一样道理
6.程序员对UI实现都不严谨(因为他们觉得UI不重要),要时时刻刻盯着
主流APP:  对于平板来说:都是要单独一套App的
而分辨率可以以1280*720或者是1960*1080作为主要分辨率进行设计。

1280:720    的屏占比     16:91960*1280的屏占比      49:32
效果图一套(720p),切图也是 720p (有时候要求1080p,看公司要求高不高)。

UI切图都是以1280*720 开发写标准尺寸是按照320P来的

假若还是不适配的话也可以根据不适配的机型来设定特别的值。


为什么Web页面设计人员从来没有说过,尼玛适配好麻烦?

其实就是一个原因,网页提供了百分比计算大小。
自定义控件以PX为单位计算的,那么怎么适配呢!

SVG
适配参考http://blog.csdn.net/zhaoyw2008/article/details/46008513

虚拟按键的适配http://blog.csdn.net/guozhaohui628/article/details/71870530
http://blog.csdn.net/github_2011/article/details/72636851
   demo:不知道为什么上传不上去。