安卓(Android)奇葩机型UI适配方案

发表于2017-03-30
评论0 7k浏览

问题发现

最近在帮忙视觉走查还原,发现在N6手机上,整个UI给人的感觉会偏小,无论是控件的宽高,还是字体,和其他手机相比都会缩一圈的样子。最典型的的界面是账号登出界面,按钮占屏幕宽的比例明显不对劲。

如下图,左边是根据设计稿,还原出来的在普通手机上的效果,而右边的按钮部分,是适配前在N6手机上这一页面的效果。可以明显看出,整体都较左图偏小

例如按钮宽度这一参数,为330dp,而dp这个单位,本身就是安卓UI适配方案的一部分:

密度无关像素 (dp)
在定义 UI 布局时应使用的虚拟像素单位,用于以密度无关方式表示布局维度 或位置。
密度无关像素等于 160 dpi 屏幕上的一个物理像素,这是 系统为“中”密度屏幕假设的基线密度。在运行时,系统 根据使用中屏幕的实际密度按需要以透明方式处理 dp 单位的任何缩放 。dp 单位转换为屏幕像素很简单: px = dp * (dpi / 160)。 例如,在 240 dpi 屏幕上,1 dp 等于 1.5 物理像素。在定义应用的 UI 时应始终使用 dp 单位 ,以确保在不同密度的屏幕上正常显示 UI。

无论屏幕的密度是多少,设置控件的参数单位为dp时应该总能适配才对。

问题原因

造成这一问题的原因其实很简单,设计同学的视觉稿,都是按照360dp乘640dp的标准来绘制的。而一般的手机,屏幕的宽高按像素/屏幕密度换算下来也就是这一值。但是诸如N6这款奇葩手机,屏幕密度为3.5,分辨率为1440 X 2560,换算成dp,宽高分别约为411dp和731dp。这样一来,就造成了不适配的情况了。

适配方案

针对这种情况,网上也有很多适配方案,例如:
Android 屏幕适配方案

Android 百分比布局库(percent-support-lib) 解析与扩展

我们的项目里目前使用的是官方推荐的:
Google官方屏幕尺寸支持方案

尺寸换算

这一方案的思路其实还是百分比的一种体现,例如一个36dp宽的按钮,在360dp宽的屏幕上,占比10%,那么如果在411dp宽的N6上要呈现一样效果的按钮,它的宽度应该为411dp*10%=41.1dp。

建立映射

在res目录下,建立两个文件夹,一是标准屏的文件夹,按照360dp为基础,即:values-sw360dp 下面的dimen.xml 是 1 - 500 一直是相等的:

sw360dpdimen.xml

1
2
3
4
5
6
7
8
9
<resources>
    <dimen name="dp_1">1.00dpdimen>
    <dimen name="sp_1">1.00spdimen>
    <dimen name="dp_2">2.00dpdimen>
    <dimen name="sp_2">2.00spdimen>
    ...
    <dimen name="dp_500">500.00dpdimen>
    <dimen name="sp_500">500.00spdimen>
resources>


然后针对N6手机,建立一个411dp的文件夹,即values-sw411dp,数值按照比例来换算:411/360=1.14
sw411dpdimen.xml

1
2
3
4
5
6
7
8
9
<resources>
    <dimen name="dp_1">1.14dpdimen>
    <dimen name="sp_1">1.14spdimen>
    <dimen name="dp_2">2.28dpdimen>
    <dimen name="sp_2">2.28spdimen>
    ...
    <dimen name="dp_500">570.83dpdimen>
    <dimen name="sp_500">570.83spdimen>
resources>


使用映射代替数值

建立好上述映射后,在布局中不再使用xxdp这样的数值,而是统一用@dimen/dp_xxx这样的形式:例如

1
<button android:id="@+id/account_logout" android:layout_width="@dimen/dp_330" android:layout_height="@dimen/login_btn_height" android:layout_gravity="center" android:layout_marginleft="@dimen/dp_15" android:layout_marginright="@dimen/dp_15" android:layout_margintop="@dimen/dp_37" android:background="@drawable/qq_logout_bg_selector" android:text="@string/account_logout" android:textcolor="@color/colorPrimaryDark" android:textsize="@dimen/game_item_title_size">button>


这样,在普通的360dp宽的设备上,dp_15对应的仍然是15dp,而在411dp宽的N6上,它的值就会映射为17.12dp,字体也是同一个道理,这样呈现出来的UI就和视觉稿一致了。


自动生成工具

奇葩的机型这么多,数值这么多,一个个手动加不太现实,网上也给出了自动化的工具:
DimenFilesBuilder

运行后,会自动生成文件夹和dimen.xml文件,放在项目里res目录下就好

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引