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

相关文章

Android开发中gradle下载缓慢的问题级解决方法

《Android开发中gradle下载缓慢的问题级解决方法》本文介绍了解决Android开发中Gradle下载缓慢问题的几种方法,本文给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、网络环境优化二、Gradle版本与配置优化三、其他优化措施针对android开发中Gradle下载缓慢的问

Rust中的Drop特性之解读自动化资源清理的魔法

《Rust中的Drop特性之解读自动化资源清理的魔法》Rust通过Drop特性实现了自动清理机制,确保资源在对象超出作用域时自动释放,避免了手动管理资源时可能出现的内存泄漏或双重释放问题,智能指针如B... 目录自动清理机制:Rust 的析构函数提前释放资源:std::mem::drop android的妙

Python重命名文件并移动到对应文件夹

《Python重命名文件并移动到对应文件夹》在日常的文件管理和处理过程中,我们可能会遇到需要将文件整理到不同文件夹中的需求,下面我们就来看看如何使用Python实现重命名文件并移动到对应文件夹吧... 目录检查并删除空文件夹1. 基本需求2. 实现代码解析3. 代码解释4. 代码执行结果5. 总结方法补充在

spring-boot-starter-thymeleaf加载外部html文件方式

《spring-boot-starter-thymeleaf加载外部html文件方式》本文介绍了在SpringMVC中使用Thymeleaf模板引擎加载外部HTML文件的方法,以及在SpringBoo... 目录1.Thymeleaf介绍2.springboot使用thymeleaf2.1.引入spring

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

Android里面的Service种类以及启动方式

《Android里面的Service种类以及启动方式》Android中的Service分为前台服务和后台服务,前台服务需要亮身份牌并显示通知,后台服务则有启动方式选择,包括startService和b... 目录一句话总结:一、Service 的两种类型:1. 前台服务(必须亮身份牌)2. 后台服务(偷偷干

关于Spring @Bean 相同加载顺序不同结果不同的问题记录

《关于Spring@Bean相同加载顺序不同结果不同的问题记录》本文主要探讨了在Spring5.1.3.RELEASE版本下,当有两个全注解类定义相同类型的Bean时,由于加载顺序不同,最终生成的... 目录问题说明测试输出1测试输出2@Bean注解的BeanDefiChina编程nition加入时机总结问题说明

关于Gateway路由匹配规则解读

《关于Gateway路由匹配规则解读》本文详细介绍了SpringCloudGateway的路由匹配规则,包括基本概念、常用属性、实际应用以及注意事项,路由匹配规则决定了请求如何被转发到目标服务,是Ga... 目录Gateway路由匹配规则一、基本概念二、常用属性三、实际应用四、注意事项总结Gateway路由

Redis 多规则限流和防重复提交方案实现小结

《Redis多规则限流和防重复提交方案实现小结》本文主要介绍了Redis多规则限流和防重复提交方案实现小结,包括使用String结构和Zset结构来记录用户IP的访问次数,具有一定的参考价值,感兴趣... 目录一:使用 String 结构记录固定时间段内某用户 IP 访问某接口的次数二:使用 Zset 进行

Android kotlin语言实现删除文件的解决方案

《Androidkotlin语言实现删除文件的解决方案》:本文主要介绍Androidkotlin语言实现删除文件的解决方案,在项目开发过程中,尤其是需要跨平台协作的项目,那么删除用户指定的文件的... 目录一、前言二、适用环境三、模板内容1.权限申请2.Activity中的模板一、前言在项目开发过程中,尤