android ppi 对应资源,Android适配原则及资源加载规则

2023-10-09 09:50

本文主要是介绍android ppi 对应资源,Android适配原则及资源加载规则,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一. 名词解释

o 像素(Pixel, PX)

表示屏幕上一个物理的像素点。

o 屏幕尺寸

屏幕的物理尺寸,一般用屏幕对角线长度来表示,单位英寸(inch)。1in

=2.54cm。通常我们说手机5寸屏,指的就是手机屏幕的对角线长度是5寸。

o 屏幕分辨率(Screen Resolution)

屏幕垂直方向像素数目px *

屏幕水平方向像素数目px,如1280×800,表示屏幕横向有800个像素点,纵向有1280个像素点。相同尺寸屏幕下屏幕分辨率越高显示效果越精细细腻。

o 像素密度(PPI, Pixels Per Inch)

表示每inch上可以显示的像素点数目,单位px。 与屏幕尺寸、分辨率的关系如下:

a4c26d1e5885305701be709a3d33442f.png

o 屏幕密度(DPI,Dots Per Inch)

表示每Inch上可以显示的(打印)点数,单位dpi。如160dpi。在打印机设备上常用。PPI和DPI的详细区别请看https://99designs.com/blog/tips/ppi-vs-dpi-whats-the-difference/。Android提供了DisplayMetrics类和Configuration类获取当前屏幕密度:

context.getResources().getDisplayMetrics().densityDpi

context.getResources().getConfiguration().smallestScreenWidthDp

o 密度无关像素(DP/DIP,Density Independent Pixels)

Android特有的长度单位,可以理解为与具体设备无关的虚拟像素。在特定设备上显示时系统会自动根据屏幕密度确定最终对应的物理长度(px单位)。所以用dp定义的UI可以自适应各种屏幕。Android规定在屏幕密度160dpi的设备上1dp

= 1px。所以虚拟像素dp和物理像素px的换算关系是:

a4c26d1e5885305701be709a3d33442f.png

具体函数实现如下,其中density=DPI/160。

public static intdp2px(Context context, floatdpValue){

floatscale=context.getResources().getDisplayMetrics().density;return(int)(dpValue * scale + 0.5f);}

public static intpx2dp(Context context, floatpxValue){

floatscale=context.getResources().getDisplayMetrics().density;return(int)(pxValue / scale + 0.5f);}

o 比例无关像素(SP, Scale Independent Pixels)

Android特有的字体大小单位,可以理解为与具体字体缩放比例无关的虚拟字体大小。在特定设备上显示时系统会自动根据字体缩放比例确定最终字体大小。所以用sp定义的字体大小可以自适应各种大小的系统字体设置。Android规定在屏幕密度160dpi的设备上缩放比例为100%时1sp

= 1px, 所以sp和物理像素px的换算关系是:

a4c26d1e5885305701be709a3d33442f.png

具体函数实现如下,其中scaledDensity=scale * (DPI/160)。

public static intsp2px(Context context, floatspValue){

floatfontScale = context.getResources().getDisplayMetrics().scaledDensity;return(int) (spValue * fontScale + 0.5f);}

public static intpx2sp(Context context,floatpxValue){

floatfontScale = context.getResources().getDisplayMetrics().scaledDensity;return(int) (pxValue / fontScale + 0.5f);}

所以使用sp定义的字体是根据系统字体设置而变化的。如果不希望UI的字体大小随系统设置变化,可以用dp定义字体大小。

二. 视觉大小一致性

Android为了使一套UI自动适应不同分辨率的屏幕,实现“与设备密度无关的视觉大小一致性”,也就是说无论是在高分辨率手机、还是在低分辨率的平板上,某个控件或者图片在物理尺寸上都是一样的,这样UI就不会因为设备的不同而显示得千奇百怪,才不会让用户觉得别扭。

所以发明了dp并定义了dp与物理像素的对应关系,同时把手机屏幕根据屏幕密度分成5个级别:

a4c26d1e5885305701be709a3d33442f.png

根据上表,为了让APP的UI或者说图片在不同屏幕密度上保持视觉大小一致,也就是在不同屏幕上占有相同的dp,

那么应该针对不同屏幕提供特定比例的布局或图片, 比如mdpi下某个icon尺寸是48X48,

那么这个icon在ldpi下应该为36X36, hdpi为72X72, xhdpi为96X96,

xxhpdi为144X144,xxxhdpi为192X192。

三.

Android适配规则

o UI元素的大小尽量以dp为单位或直接指定为 wrap_content。

o LinearLayout中尽量使用weight分配大小。

o

图片由于缩放可能会导致变形,在小屏幕上加载大图片会占用过多内存,因此需要针对不同屏幕密度的设备提供不同大小的图片。一般会提供drawable-mdpi、drawable-hdpi、drawable-xhdpi等图片目录以适应不同设备。

o

dimens适配,可以根据屏幕密度设置特定的values目录让满足设定的设备进行加载,比如values-mdpi、values-hdpi、values-xhdpi、values-xxhdpi、values-800x400等等,然后每个目录放置一个demins.xml,使不同分辨率的设备应用不同的尺寸设置。

o 字符串国际化,可以建立values-zh、values-en等多语言目录。

o 图片国际化,

可以建立drawable-en-mdpi、drawable-en-hdpi等语言相关的drawable目录。

o 如果需要为不同屏幕单独写不同的layout,

那么layout目录也可以根据屏幕密度设置多个目录。如layout-1280x720、layout-800x480 。

o 横竖屏切换时使用不同layout,那么就设计layout-port和layout-land两个目录。

四.

Android资源加载规则

o 图片加载

当App在特定设备上运行时对应dpi目录下没有找到某个资源时,遵循“先高再低”原则,然后按比例缩放图片。比如,当前为xhdpi设备,并且只有以下几个目录,则drawable的寻找顺序为:

xhdpi->xxhdpi->xxxhdpi(如果没有更高的了)->nodpi(如果有的话)->hdpi->mdpi,如果在xxhdpi中找到目标图片,则压缩2/3来使用,如果在mdpi中找到图片,则放大2倍来使用。

这很好理解,如果我们按规则放置两张图片,mdpi中为48x48,xxhdpi中为144x144,那么不管我们最后从哪个目录拿到图片,在xhdpi设备上显示的像素大小都是96x96,只是一个被拉伸而来,一个被压缩而来。由于xhdpi定义了96个像素点的物理尺寸,那么这张图的物理尺寸实际就被定下来了。同样的,mdpi中48个像素点的物理尺寸与xhdpi中96个像素点的物理尺寸是相同的,这就保证了该图片在任何设备上显示出的视觉大小一致。

那么,一个结论就是,对于期望保持视觉大小一致的那部分图片而言,如果你也能接受android为你拉伸/压缩图片导致一定程度的模糊或者锐化,那么这些图片是不需要在每个drawable目录下都制作一份的。以现在主流设备来说一般可能在drawable-xxhdpi放置一份即可,这样可以尽量避免Android为我们放大图片所导致的OOM。

当然,在某些情况下,我们会主观希望打破android提供的“视觉大小一致”这种机制,此时我们就可以建立另外的drawable目录来放置需要变化的图片了。

o values加载

当App在特定设备上运行,如果在当前dpi对应目录的demins.xml中没有找到目标条目时,采用“就近匹配”原则:比如,当前为hdpi设备,则values的寻找顺序为:

hdpi->xhdpi->mdpi->values,即先向上级dpi目录查找,再向下级dpi目录查找,最后一路向下查找到values目录,如果values下都找不到,就只有找values-ldpi,当然,现在有这个目录的应用不多了。

那么,我们需要将mdpi目录下的值都乘以相应的倍数来放置在其他目录下面吗?答案当然是否定的,由于我们对期望屏幕密度无关的值都定义为了dp或者dip的单位,无论android从哪个目录最终找到该值,都会直接应用这个值与当前设备的密度来计算最终的尺寸。

也就是说,如果我们同样在values-xhdpi和values下写 length=10dp

那么在mdpi设备上得到的都是10px,在xhdpi设备上得到的都是20px。

但它们看起来“都是一样宽”,这样就已经是“保证视觉大小一致性了”。

48dp法则告诉我们,48dp的物理尺寸约等于9mm,是人的手指比较容易点击到的大小,并且是独立于设备的。

显而易见,如果我们在values目录下写length=10dp,values-xhdpi目录下写length=20dp,mdpi设备上得到的将是10px,而xhdpi设备上得到的将是40px,得到视觉结果就是,该控件在xhdpi设备上看起来比mdpi设备上大了一倍。

考虑这样一个情况:有一个BottomBar,左右两端各有一个按钮,按钮长宽用dp定义,这样在一个大屏手机中,两个按钮可能就相隔更远了,因为按钮的视觉尺寸是没有变化的。如果你想保持按钮在BottomBar中所占的比例,最好办法不是添加一个values-xxx,然后重写这两个dp值,而是精心设计你的布局。

那么,既然最后都要找到values,并且能够保证视觉大小一致性,那何必再添加其他values分辨率目录呢?答案是在某些情况下,我们主观希望某些尺寸不去保持视觉一致性。例如一个Button,在手机上那么大刚好,但如果在平板设备上,是的,它看起来和在手机上一样大,但是,它显得有点小了。

也就是说,我们应该把希望在任何设备上视觉大小都一样的尺寸都放置在values目录下并且只放置这一份,其他需要有变化的尺寸则放置在对应目录下即可

一般而言,使用在物理尺寸相差不大的几套设备上,一个values可能就够了,因为它本身就保证了“视觉大小一致性”,但是如果你的应用需要兼容平板,甚至电视,那么这种一致性可能是一种灾难。这时可以考虑添加一个对应dpi的values目录,把需要变化的值拷贝进去重写,但我更推荐采用values-xhdpi-2560x1600,我们很容易通过这里的屏幕分辨率+dpi计算得到该设备的物理尺寸,显而易见这是一个平板设备,如此我们的改动便不至于影响同DPI的低物理尺寸设备(手机),而物理尺寸差不多的设备是可以共用一套dimens.xml的。

那么,如果当前设备为xhdpi-1184x800,当前目录有values-xhdpi-1184x800,values-xhdpi-1184x960,values-xhdpi-1184x720,android的寻找顺序则是:

values-xhdpi-1184x800->values-xhdpi-1184x720->values-xhdpi

只向低于自己分辨率的目录下寻找,直到values-xhdpi,如果依然没有找到,按照之前的顺序继续进行。(hdpi-1280x800

-> hdpi-1280x720 -> hdpi -> …)

也就是说,对于同dpi的多台不同分辨率平板设备,如果布局足够通用,我们可以只针对最低分辨率设计dimens即可,上面的例子中,则是values-xhdpi-1184x720。

我们还可以将这个分辨率写得更低,低到我们有把握:如果再出现比这个分辨率更低的设备,那么它的物理尺寸一定满足即使采用values-xhdpi中针对手机物理尺寸设计的大小也没有问题。

再举一个复杂的例子

=============

在 720x1280 xhdpi 的机器上,搜寻顺序是:

values-xhdpi-720x1280(1080x1920 不会访问)

values-xhdpi-480x800

values-xhdpi-320x480(到底)

values-xh

values-xxh

values-xxxh(到顶)

values-h

values-m

values-720x1280(1080x1920 不会访问)

values-480x800

values-320x480(到底)

values

values-l

如果还没找到则报错

====================================

这篇关于android ppi 对应资源,Android适配原则及资源加载规则的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/172002

相关文章

JAVA项目swing转javafx语法规则以及示例代码

《JAVA项目swing转javafx语法规则以及示例代码》:本文主要介绍JAVA项目swing转javafx语法规则以及示例代码的相关资料,文中详细讲解了主类继承、窗口创建、布局管理、控件替换、... 目录最常用的“一行换一行”速查表(直接全局替换)实际转换示例(JFramejs → JavaFX)迁移建

Android使用java实现网络连通性检查详解

《Android使用java实现网络连通性检查详解》这篇文章主要为大家详细介绍了Android使用java实现网络连通性检查的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录NetCheck.Java(可直接拷贝)使用示例(Activity/Fragment 内)权限要求

2025最新版Android Studio安装及组件配置教程(SDK、JDK、Gradle)

《2025最新版AndroidStudio安装及组件配置教程(SDK、JDK、Gradle)》:本文主要介绍2025最新版AndroidStudio安装及组件配置(SDK、JDK、Gradle... 目录原生 android 简介Android Studio必备组件一、Android Studio安装二、A

springboot+mybatis一对多查询+懒加载实例

《springboot+mybatis一对多查询+懒加载实例》文章介绍了如何在SpringBoot和MyBatis中实现一对多查询的懒加载,通过配置MyBatis的`fetchType`属性,可以全局... 目录springboot+myBATis一对多查询+懒加载parent相关代码child 相关代码懒

MyBatis延迟加载与多级缓存全解析

《MyBatis延迟加载与多级缓存全解析》文章介绍MyBatis的延迟加载与多级缓存机制,延迟加载按需加载关联数据提升性能,一级缓存会话级默认开启,二级缓存工厂级支持跨会话共享,增删改操作会清空对应缓... 目录MyBATis延迟加载策略一对多示例一对多示例MyBatis框架的缓存一级缓存二级缓存MyBat

Python之变量命名规则详解

《Python之变量命名规则详解》Python变量命名需遵守语法规范(字母开头、不使用关键字),遵循三要(自解释、明确功能)和三不要(避免缩写、语法错误、滥用下划线)原则,确保代码易读易维护... 目录1. 硬性规则2. “三要” 原则2.1. 要体现变量的 “实际作用”,拒绝 “无意义命名”2.2. 要让

Python异常处理之避免try-except滥用的3个核心原则

《Python异常处理之避免try-except滥用的3个核心原则》在Python开发中,异常处理是保证程序健壮性的关键机制,本文结合真实案例与Python核心机制,提炼出避免异常滥用的三大原则,有需... 目录一、精准打击:只捕获可预见的异常类型1.1 通用异常捕获的陷阱1.2 精准捕获的实践方案1.3

深入浅出Java中的Happens-Before核心规则

《深入浅出Java中的Happens-Before核心规则》本文解析Java内存模型中的Happens-Before原则,解释其定义、核心规则及实际应用,帮助理解多线程可见性与有序性问题,掌握并发编程... 目录前言一、Happens-Before是什么?为什么需要它?1.1 从一个问题说起1.2 Haht

Android实现图片浏览功能的示例详解(附带源码)

《Android实现图片浏览功能的示例详解(附带源码)》在许多应用中,都需要展示图片并支持用户进行浏览,本文主要为大家介绍了如何通过Android实现图片浏览功能,感兴趣的小伙伴可以跟随小编一起学习一... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

在Android中使用WebView在线查看PDF文件的方法示例

《在Android中使用WebView在线查看PDF文件的方法示例》在Android应用开发中,有时我们需要在客户端展示PDF文件,以便用户可以阅读或交互,:本文主要介绍在Android中使用We... 目录简介:1. WebView组件介绍2. 在androidManifest.XML中添加Interne