Android 屏幕适配(上)

屏幕适配的重要性

作为一名 Android 开发者,有一个逾越不过的问题,就是屏幕适配。谈屏幕适配其实是一件非常让人蛋疼的事情,究其原因就是Android 的开放性。由于Google 这种搞一个东西就开放源代码的“习惯”造成了Android 系统的开放性,以至于随随便便一个厂商就可以随心所欲定制自家系统,任意修改成他们想要的样子。

这使整个Android 的碎片化非常严重。
严重到什么程度呢?下面给出几张图,大家感受一下。

如下图所示:
这里写图片描述

上图一个颜色块代表了一个手机品牌。
再来看手机屏幕尺寸的分布以及所占的比例

这里写图片描述

上图蓝色的线代表屏幕尺寸,颜色越深占比越大。

截止写这篇文章之前,由于我没有找到最新最官方的资料,所以调查数据只找到2015年。如下:

2012年,支持Android的设备共有3997种。
2013年,支持Android的设备共有11868种。
2014年,支持Android的设备共有18796种。

而到15年时Android 设备厂商又增加了很多很多,两年来Android 的碎片化已经从13年的11868翻倍。

如今,Android 版本依然非常混乱,而且有愈演愈烈的趋势。

针对这么多的手机,我们不可能做到面面俱到,当今市场上最流行哪些呢?根据我在 screensiz.es 上看到的数据(截止到2016年10月7日),当前全球手机屏幕尺寸、操作系统、品牌以及市场占有率的调查数据如下:

这里写图片描述

这是愿意接受调查并提供数据的一些厂商的数据,作为一名国内 Android开发者,我们抛开 IOS 不看,只看Android和国内的情况,2016年8月友盟统计的国内 Android 设备分辨率数据如下:

这里写图片描述

现在应该很清楚为什么我们要对 Android 的屏幕进行适配了吧?这么多的屏幕尺寸,怎么能保证我们自己开发的程序能美观的显示到不同尺寸、不同分辨率的设备上呢?显而易见,这肯定需要我们自己去处理,而如何处理这些问题,这就涉及到屏幕适配,也就是今天要讲的。

从上图可以看出,主流的分辨率是前六种:1280×720、1920×1080、854×480、960×540、800×480、1184×720。而真实开发中,我们要做的事就是适配当前市场上绝大多数的 Android 屏幕就可以了。

知道了屏幕适配的重要性之后,接下来开始进入正题。

必须了解的概念

先抛出几个概念:

  屏幕尺寸、屏幕分辨率、屏幕像素密度
  dp、dip、dpi、sp、px
  mdpi、hdpi、xhdpi、xxhdpi、xxxhdpi

屏幕尺寸、屏幕分辨率、屏幕像素密度

屏幕尺寸

    屏幕对角线长度,单位是英寸,我们常说的多少多少寸,比如4.7存手机、5.7存手机,指的就是这个。


    是指在手机屏幕的像素点的个数,单位是px,1px=1像素点,一般是纵向像素横向像素,如1920×1080,意味着高有1920个像素点,宽有1080个像素点。

屏幕像素密度

    是指每英寸上的像素点数,单位是dpi(dotper inch)。像素密度和屏幕尺寸和屏幕分辨率有关,它是由对角线的像素点数除以屏幕的大小得到的,关系如下:

这里写图片描述

单一变化条件下,屏幕尺寸越小、分辨率越高,像素密度越大,反之越小。

dp、dip、dpi、sp、px

  dp:是Android 特有的,意为密度无关像素,Google 发布的 BASELINE(基准线)为 160,以此为基准。
  dip:Density Independent Pixels,同dp。
  dpi:即为屏幕像素密度的单位
  sp:Scale-IndependentPixels的缩写,可以根据文字大小首选项自动进行缩放。Google推荐我们使用12sp以上的大小,通常可以使用12sp,14sp,18sp,22sp,为避免精度损失,建议最好不要使用奇数和小数。
  px:就是我们常说的像素

mdpi、hdpi、xhdpi、xxhdpi、xxxhdpi

文档中介绍他们之间的关系,告知他们的比例为2:3:4:6:8,其实就是160、240、320、480、640的比例。
配以图说明如下:
这里写图片描述

了解了以上这些“纸上谈兵”的概念之后,接下来进入真实解决问题的环节。但请记住,只有了解了这些概念,你才能去解决这些问题,所以不要轻视这些概念性的东西。

解决方案

一般都是采用以下几种适配的方案:

 1.布局适配
 2.权重适配
 3.代码动态设置
 4.图片适配
 5.dp 适配
 6.百分比适配
布局适配
   这种适配方案基本上不怎么使用了,因为实在是太耗费资源,试想一下。多写一套布局,而大部分的代码都是相同的,纯粹是为了适配而做的这些事情,无疑增加了开发者的负担以及使程序变得更冗余和庞大,我个人认为,实在是得不偿失。
权重适配
   这是 LinearLayout 的特有属性:weight,意味权重,我们可以让界面布局按照我们设定的比例来显示。比如,现在有个需求,要求界面上有两个控件,一个占屏幕宽的1/3,另一个占屏幕宽的2/3。

可以这样编写代码,如下:

这里写图片描述

文本1的weight=1,宽度为0dp
文本2的weight=2,宽度为0dp

而显示效果就是文本1的宽度占了1/(1+2),文本2的宽度占了1/(1+2),如上图所示,这样就很好的完成了需求。
但我希望你能明白权重的计算规则,权重的意思是控件的大小等于自身大小加上占剩余空间的比例。注意是剩余空间的比例,什么意思呢?

先看另外一种效果。

这里写图片描述

与之前相比,我只改了一个属性,就是把文本1和文本2这两个TextView的宽度改成了match_parent。
然而结果却变了个样,本该显示1/3的文本1却占了2/3,而文本2却变成了1/3。

再来看一下刚才那句话,什么叫剩余空间呢?

当前的LinearLayout的orientatioin为横向,两个TextView的weight分别是1和2。
先分析第一种情况,就是当宽度为0dp的时候。
假设说屏幕的宽度为L,现在该屏幕下有两个控件,两个控件的宽度为0,那剩余空间就等于L-(0+0)=L。
文本1的weight=1,那么它的宽度:
自身宽度 + 所占剩余空间的比例 = 真正的宽度
0 + L * 1/(1+2) = 1/3 L

同理,文本2的宽度为:
自身宽度 + 所占剩余空间的比例 = 真正的宽度
0 + L * 2/(1+2) = 2/3 L

因此当宽度设置为0dp的时候,显示效果就是1:2的关系。

再来讨论当宽度设置为match_parent的时候的情况,就是当控件的宽度为 L 的时候。
现在屏幕的宽度为L,现在这两个控件的宽度都为L,那剩余空间就等于L-(L+L) = -L。
文本1的weight=1,那么它的宽度:
自身宽度 + 所占剩余空间的比例 = 真正的宽度
L + -L * 1/(1+2) = 2/3 L

同理,文本2的宽度为:
自身宽度 + 所占剩余空间的比例 = 真正的宽度
L + -L * 2/(1+2) = 1/3 L

因此当宽度设置为0dp的时候,显示效果就是2:1的关系。
这就是权重的计算规则,很多人面试都遇到过。
这是横向的只测试了宽的权重,其实高也是一样,这里不做讲解,贴两张图,改动的地方我会标记出来,大家自己查看,有疑问请在评论区提问。

0dp的情况

这里写图片描述

match_parent的情况

这里写图片描述

注意:

 权重只有LinearLayout才有,RelativeLayout没有这个属性,虽然 Google 推荐使用RelativeLayout而不是LinearLayout。

这里多提一句为什么Google推荐使用RelativeLayout而不是LinearLayout。

在 Android 中,系统对View进行测量、布局和绘制时,都是通过对 View树的遍历来进行操作的。如果一个View 树的高度太高,就会严重影响测量、布局和绘制的速度,因此我们如果不想被影响的话,第一个方法就是要降低View树的高度,Google也在其API文档中建议View树的高度不宜超过10层。
真实项目中,大部分的根布局几乎都是RelativeLayout,因为要实现相对位置的控制,所以比较方便一些。
而最初的时候创建一个 xml 布局,Google是用 LinearLayout作为默认根布局的,而现在已经使用 RelativeLayout 作为 xml 文件默认的根布局了,原因就是希望通过扁平的 RelativeLayout来降低通过 LinearLayout 嵌套所产生布局树的高度,从而提高 UI 渲染的效率。

代码适配

有一些情况下,我们需要去动态的设置控件的大小或者是控件的位置,比如dialog或者popupwindow的偏移量或者是显示的位置等等,这个时候在xml布局里就显得有点乏力,我们可以根据当前屏幕的大小属性来设置合适的数值。
比如

//获取屏幕高宽
DisplayMetricsmetric = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metric);
windowsHeight= metric.heightPixels;
windowsWight= metric.widthPixels;
//动态改变布局
LinearLayoutproduction_factory = (LinearLayout)findViewById(R.id.production_factory);
LayoutParamsparams = production_factory.getLayoutParams();
params.height= windowsHeight / 2;
production_factory.setLayoutParams(params);

下篇详细介绍更为广泛用途的方式:Android 屏幕适配(下)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值