今日头条屏幕适配深度剖析

news2024/11/23 15:46:01

基本概念

首先几个基本概念解释:
● dpi:该值代表的是一英寸上有多少个像素点,常见取值为120,160,240。一般这个值才叫做密度

在android里面获取的方法为 metrics.densityDpi;
屏幕尺寸/分辨率得出DPI,一个单位尺寸显示多少像素点。

● density:名字上虽然叫做密度,但是dpi才是密度,这个就叫做density。这个值是一个和标准DPI(默认160dpi后面解释)的比例,一般为 2,1.5 , 1.0,0.75

在android里面获取的方法为 metrics.density;
或者 metrics.densityDpi / 160DPI(标准DPI)

● dp(dip):设备无关像素,系统会自动根据density自动转换为px。
在android里面获取的方法为dp转px公式为

px= dpvalue *metrics.density;
px= dpvalue * (metrics.densityDpi / 160DPI(标准DPI))

● px:代表的是分辨率

这些值上面对应在现实生活中是这几个常用词汇:

● 屏幕尺寸:代表的屏幕宽高信息尺寸(单位cm)
● 屏幕分辨率:代表屏幕宽和高分别有多少像素点(单位px)
● 屏幕密度:代表一个单位屏幕尺寸上显示多少个像素点(单位dpi)

采用PX编写控件宽高尺寸出现的问题

接下来的讲的控件宽高尺寸适配都是用的px单位

为什么出现DPI,不进行直接对屏幕尺寸和分辨率进行适配

可以说我们安卓写控件宽高大小(用px)不需要关心屏幕尺寸也不需要关心分辨率(这样做会累死,因为很多设备虽然屏幕尺寸相同但是分辨率不同或者反过来,不同情况下控件宽高(用px)也不一样,一个个去适配宽高大小太复杂了),所以就需要个东西对尺寸和分辨率都进行考虑。
接着就会发现虽然屏幕尺寸和分辨率都很乱,但是大致上可以找到规律,就是 一个屏幕尺寸上显示多少个像素点主要就四种,所以DPI大体上只有四种,只需要关心这四种DPI就行,不需要陷入到具体的屏幕尺寸和分辨率上。

Android Design [1] 里把主流设备的 dpi 归成了四个档次,120 dpi、160 dpi、240 dpi、320 dpi。

为什么出现density而不是对DPI进行适配

由于市面上的设备DPI不相同,如果不进行DPI适配的话,就会出现大小不一问题

比如在120DPI上(一个屏幕单位显示120个像素点)设计的120px的控件尺寸 在屏幕上显示会占用一个屏幕单位。
跑在240DPI上(一个屏幕单位显示240个像素点),就会只占用0.5个屏幕单位,因此120DPI上跑的所有控件到了240DPI的设备上都会缩小一半。

所以就需要进行适配不同DPI的设备,虽然DPI我们只关心四种,比起适配不同屏幕尺寸和不同分辨率的设备需要适配的工作量大大降低,但是还是需要适配四种也就是四倍的工作量。

安卓的资源目录(图片,布局,drawable等)会带着后缀比如mdpi,xdpi,xxdpi…这些不同的资源目录下面存放着的就是对应DPI设备上使用的资源。

对于图片来说我们不需要关心,让UI去做不同DPI的图就行;但是 对于同一个布局里面的控价宽高尺寸(用px)来说仅仅因为尺寸不一样就需要重新写四套布局吗?UI也需要对每个标注出四套标注吗? 这可是四倍的工作量
所以我们希望可以根据不同DPI去做一个尺寸的比例缩小放大

首先要适配,就需要我们设计图采用一个基准DPI去设计控件尺寸大小,然后在不同DPI的设备上,根据我们设计图用的基准DPI的值 去除以 对应显示设备的DPI,就可以得到我们需要进行缩放的比例了,最后进行对应尺寸X比例即可实现放大缩小在不同DPI的设备上完成适配。

比如如果我们设计图是在120DPI的设备上出的标注,那么上面说的120DPI上跑的120px的控件要在240DPI上采用240PX的控件才可以,可以看到是120*2得出来的;

但是如果要泡在160和320的设备上,对应的比例就可能除不尽导致最后得出的尺寸有小数,不够精准。

所以我们设计图该采用哪种基准DPI进行出标注呢?

我们会发现这四个主流的DPI也有个规律:

如果以 160 dpi 作为基准的话,只要尺寸的 DP 是 4 的公倍数,XHDPI 下乘以 2,HDPI 下乘以 1.5,LDPI 下乘以 0.75 即可满足所有尺寸下都是整数 pixel 。

所以我们默认设计图和我们最终编写 适配的都是在160DPI设备上跑的,不同DPI的设备进行对应的缩放比例调整即可,这个缩放比例就是density。

因为记忆这四个DPI的数值还是比较麻烦,所以我们直接记忆density即可,也就是说我们的控件宽高尺寸X对应的density即可。最后得出的公式就是:
最终显示在不同DPI设备上的控件宽高尺寸 = 160DPI标注图上控件宽高尺寸 X 对应的density(显示设备DPI / 160DPI得出)。

我们只需要根据这个公式就可以计算出不同DPI下的宽高尺寸,但是好像我们并没有解决根本问题,上面说的只是节省了UI的工作量他们不需要出四套不同dpi上不同宽高尺寸的图了,我们还是依然需要写四个不同的布局文件

采用DP编写控件宽高尺寸

接上面说的,我们依然还是需要写四套布局写四个不同的宽高尺寸,如果有个工具可以自动帮我们做转换就好了,我们上面一直说的都是用的px进行的适配,如果我们自定义一个尺寸单位,这个尺寸单位如果在变成px的过程中进行上面我们说的density转换 那么是不是就可以达到我们只写一个布局文件的目的了。

没错,这个单位就是dp,密度无关像素,也就是dpi无关,因为dp最终转换px的时候会进行不同DPI的适配(也就是X对应的density)现在是不是就可以理解为什么叫做密度无关了吧。

这样我们以后编写尺寸都用dp进行编写(采用160DPI的设计图),dp转换为px的时候 乘以 对应设备缩放的density(显示设备DPI/160DPI)即可。

这样在160DPI上采用的dp就是px,因为我们就是在160DPI上出的px标注。
在320dpi上采用的dp最终转换为px的时候会乘以2,因为我们是按照160DPI设计的。
可以看出dp是px的一个封装

国内屏幕参数太乱导致density精度不足导致最终显示有问题

假设宽分辨率1080px,480DPI的设备得出屏幕宽度518400英寸;
另外一个设备分辨率1440px,560DPI的设备得出屏幕宽度806400英寸。

如果一个100dp宽度的控件显示在这两个设备上分别占用300px,350px像素点,对应显示在屏幕上的尺寸分别为0.625英寸,0.625英寸(不同尺寸屏幕 显示的控件尺寸居然一样);
得出对应占用整个屏幕宽度的百分比分别为0.000000121,0.00000078。

我们发现经过系统转换DP为PX,最终占据的px已经经过转换但是 在屏幕上显示的百分比却有问题(从不同屏幕尺寸显示的控件尺寸一样就可以看出不对了),可以发现 根本原因还是分辨率和尺寸太乱了也就是说DPI太乱了,安卓官方想的是主流DPI适配即可 (主流dpi经过160基准DPI的转换因为density都是整数所以都可以正常转换,显示的尺寸比例不同设备也都一样),

但是国内形形色色的手机太多了(转换的density有小数最终转换为px会精度丢失,导致比例不同),官方的适配方案已经在国内不可行了,所以出现了今日头条的方案。

今日头条

根据上面的分析我们已经知道了 官方的density计算方案是设备DPI/基准DPI,但是对于国内来说由于设备DPI太多太乱(屏幕尺寸和分辨率太乱)且没有规律因此导致density精度丢失转换出问题。

我们就需要另外想办法了,像当初dp诞生一样我们在重新创建一个单位进行转换?改动太大且无法兼容;改变每个 View 的 dp 值?不现实,在每个设备上都要通过代码动态计算 View 的 dp 值,工作量太大(这和当初改变每个view的px值思路一样);修改density计算方案看起来可行,因为官方已经有这种转换的机制了我们修改转换机制即可。

如何才能保证不同dpi最终计算出来的density不存在精度丢失问题呢?

之前的办法在于找到DPI之间的比例进行等比缩放,但是DPI太多了比例会丢精度导致数值不精准;既然DPI不固定,我们就找到固定的部分,我们发现我们写的dp是固定的,之前一直迁就设备,主动权在设备上导致我们被动,所以要让主动权在我们手上,我们控件写的dp是固定的,如果可以让所有设备屏幕的总dp都一样是不是也就可以保证比例一样。

我们首先需要让UI出图的标准是根据宽高总DP进行出图,而不是之前的基准160DPI出图,UI出的屏幕宽高DP就是实际的屏幕宽高DP,而屏幕宽高dp=屏幕宽高px(像素)/density,所以我们想要最终的屏幕宽高dp(设计图宽高dp)一样就需要重新计算density也就是:

当前设备屏幕总宽度(单位为像素)/ 设计图总宽度(单位为 dp) = density

这样动态修改desnity就可以认为所有设备的总dp都和设计图的dp一样了

方案验证

在这里插入图片描述

方案优缺点

优点是一刀切不需要改动density;但是缺点也是这个,由于采用的是让屏幕总dp和设计图dp一样的方案,如果是我们自己写的view那么对应的dp比例就可以正常转换; 但是如果我们用了别人的view,而别人view的dp不是按照我们设计图dp写的并且和我们设计图dp差别很大,就会出现问题。

这就是两个设计图尺寸不一致导致的非常严重的问题,当两个设计图尺寸差距越大,那适配的效果也就天差万别了

方案一

无法让三方库来适应我们项目的设计图尺寸,所以只有我们自身作出修改,去适应三方库的设计图尺寸,我们将项目自身的设计图尺寸修改为这个三方库的设计图尺寸,就能完成项目自身和三方库的适配

方案二

在这里插入图片描述

参考链接

基础概念方面文章:https://blog.csdn.net/qq_30196607/article/details/50803392
https://www.imooc.com/article/260877
头条方案的理解:https://blog.csdn.net/xcbyaya/article/details/137981609

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1850128.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring Boot集成vaadin快速入门demo

1.什么是vaadin? Vaadin 是用于构建单页 Web 应用的流行 Java 框架。 它由一家专门从事富 Internet 应用设计和开发的芬兰公司开发。 估计有 15 万开发者使用 Vaadin。 它的开发始于 2002 年。 Vaadin 框架特性 以下是 Vaadin 特性的列表: 这是一个 J…

这周,接连两位程序员猝死...

这周接连发生了两起不幸的事。俩位程序员去世的消息,深感悲伤和惋惜。 6月17号下午,一位负责研发的女员工在虾皮研发中心办公室猝死,年仅 30 岁。 官方通告: 同一天,另一位科大讯飞的高级测试工程师在家突发不适离世…

修改文件的权限(linux篇)

1.在yl用户下创建一个demo.txt文件 [rootlocalhost ~]# su yl [yllocalhost root]$ cd [yllocalhost ~]$ cd Desktop/ [yllocalhost Desktop]$ ls [yllocalhost Desktop]$ vim demo.txt 填入一些信息进行保存 2.查看文件信息以及所对应的组 [yllocalhost Desktop]$ ll 总用量…

一颗B+树可以存储多少数据?

一、前言 这个问题,非常经典,考察的点很多: 比如: 1、操作系统存储的单元,毕竟mysql也是运行在操作系统之上的应用。 2、B树是针对Mysql的InnoDB存储引擎,所以要理解InnoDb的最小存储单元,页&…

解两道四年级奥数题(等差数列)玩玩

1、1~200这200个连续自然数的全部数字之和是________。 2、2,4,6,……,2008这些偶数的所有各位数字之和是________。 这两道题算易错吧,这里求数字之和,比如124这个数的全部数字之和是1247。 …

【yolov8语义分割】跑通:下载yolov8+预测图片+预测视频

1、下载yolov8到autodl上 git clone https://github.com/ultralytics/ultralytics 下载到Yolov8文件夹下面 另外:现在yolov8支持像包一样导入,pip install就可以 2、yolov8 语义分割文档 看官方文档:主页 -Ultralytics YOLO 文档 还能切…

使用 DISPATCHERS 进行 Blueprint 之间的通信

文章目录 初始准备DISPATCHERS 的创建和绑定实现效果 初始准备 首先 UE5 默认是不提供 静态网格体编辑器也就是 Modeling Mode 的,这里需要从插件中添加 Modeling Tools Editor Mode 进入 Modeling Mode 模式,创建一个正方体 然后利用 PolyGroup Edit 和…

告别手抖尴尬!教你轻松缓解手部震颤的小秘诀!

在我们的日常生活中,手抖这个现象可能并不罕见。不论是因为紧张、疲劳还是某些健康问题,手抖都会给我们的生活带来诸多不便。今天,就让我们一起探讨如何缓解手部震颤,让你告别手抖的尴尬! 一、手抖的成因及影响 手抖&…

定点计算与浮点计算在MCU上的较量:以电机控制系统算法实现为例

在嵌入式系统尤其是电机控制算法的实现过程中,定点计算与浮点计算的选取始终是一个重要议题。电机控制系统对实时性和计算效率有着极高要求,而MCU(微控制器)作为其核心处理器,其计算模式的选择直接影响整个系统的性能。…

pycharm中的使用技巧

1、更改主题:找到设置,然后更改主题 点击选择自己喜欢的主题,然后就可以更改主题了 2、设置字体的快捷键 找到设置,如下: 找到increase,如下: 右键选择,增加字体快捷键 按住ctrl滑轮…

压缩包文件密码破解软件 Ziperello 下载及使用教程

使用 Ziperello https://qweree.cn/index.php/416/ 对加了密码的压缩包进行密码破解,教程如下: 第一步,双击运行 Ziperello双击我打开程序.exe,如下图: 第二步,打开一个加了密的 ZIP 压缩包,再…

LCR 142.训练计划IV

1.题目要求: /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/ int compare(const void* a,const void* b) {return (*(int*)a - *(int*)b); } struct ListNode* trainningPlan(struct ListNode* l1, struct Li…

Linux驱动开发笔记(十三)Sysfs文件系统

文章目录 前言一、Sysfs1.1 Sysfs的引入1.2 Sysfs的目录结构1.2 Sysfs的目录详解1.2.1 devices1.2.2 bus1.2.3 class1.2.4 devices、bus、class目录之间的关系1.2.5 其他子目录 二、Sysfs使用2.1 核心数据结构2.2 相关函数2.2.1 kobject_create_and_add2.2.2 kobject_put()2.2.…

转让5000万内资融资租赁公司变更需要的条件和变更时间

我们现在有一家陕西的融资租赁公司公司是非常干净的非常适合接手后直接开展业务如果北京的不能够变更了我们这边还有渠道可以变更现在能做的越来越少了,详情流程致电咨询或者来我们公司面谈。 现成融资租赁公司转让: 1、公司名称:陕西xxX融资…

【龙晰 离线安装openssl-devel】openssl-devel rpm 离线安装 需要下载哪些安rpm 包

进入龙晰镜像源地址下载 http://mirrors.openanolis.cn/anolis/8/BaseOS/x86_64/os/Packages/(base) [rootAI lib64]# yum install openssl-devel Last metadata expiration check: 14:03:32 ago on Fri 21 Jun 2024 07:26:56 AM CST. Dependencies resolved. Package …

Linux扩展lvm分区实践 -- 使用其他磁盘的空间

如图,根分区900G,计划将另一块磁盘sdb分出1T来给根分区 步骤 1:创建新的分区 sudo fdisk /dev/sdb输入 n 创建一个新分区 然后选择分区类型,输入p 设置起始扇区(默认),然后设置分区大小&…

nginx启动之后任务管理器里面没有nginx进程

原因1:确保你的nginx文件夹里面只包含英文路径!绝对不能有中文! 原因2: 到conf\nginx.conf里面查看端口和IP地址是否正确设置,ip地址有无正确输入

MySQL之复制(十)

复制 改变主库 确定期望的日志位置 如果有备库和新主库的位置不相同,则需要找到该备库最后一条执行的时间在新主库的二进制日志中相应的位置,然后再执行CHANGE MASTER TO.可以通过mysqlbinlog工具来找到备库执行的最后一条查询,然后在主库上…

JupyterLab使用指南(二):JupyterLab基础

第2章 JupyterLab基础 2.1 JupyterLab界面介绍 JupyterLab的用户界面非常直观和灵活。它包括文件浏览器、工作区、多标签页、命令面板和侧边栏等功能。以下是各个部分的详细介绍: 2.1.1 文件浏览器 文件浏览器位于界面左侧,用于导航和管理文件。你可…

【英伟达GPU的挑战者】Groq—AI大模型推理的革命者

目录 引言第一部分:Groq简介第二部分:Groq的特点与优势1、高性能推理加速2、近存计算技术3、专用ASIC芯片设计4、低延迟与高吞吐量5、成本效益分析6、易用性与集成性7、软件与硬件的协同设计 第三部分:Groq的使用指南1、准备工作2、简单使用样…