一种粗暴快速的Android全屏幕适配方案_meta-inf/androidx.customview_customview.versi-程序员宅基地

技术标签: android  屏幕适配  

一、现状
由于Android碎片化严重,屏幕适配一直是开发中较为头疼的问题。面对市面上五花八门的屏幕大小与分辨率,��Android基于dp与res目录名称来适配的方案已无法满足一次编写全屏幕适配的需求,为了�达到最优的视觉效果,开发过程中总是需要花费较多资源进行适配。也有开发者给出了一些自己的解决方案。首先来分析一下一些常见的解决方案的现状:
官方适配方案
dp。dp是Android开发中特有的一个单位。与px不同,dp是基于屏幕像素密度的一种单位。在�密度低的屏幕上或许1dp=1px,但在密度高的屏幕上可能1dp=4px。编写布局xml时,如果一个控件的长宽都使用dp来指定,那么能确保该控件在各种大小与分辨率的屏幕下的绝对大小都大致相当。也就是说无论在pad下还是大小屏手机下,我们实际看到的该控件的大小是差不多的:
在这里插入图片描述
资源目录名。上图可见虽然使用dp确保了控件在不同屏幕中的绝对大小一致。这样的好处在于,在大小相近的屏幕中,�无论分辨率多大都不会对布局造成影响;但是当屏幕大小相差较大时,仅保证控件的�绝对大小看起来就有些问题了。在res目录下可以给�各资源目录都加上例如’-1920x1080’等后缀来适配不同的�屏幕,具体规则可见官网文档。这样可以针对不同的屏幕提供不同的布局,甚至针对pad与手机提供两套完全不同的布局样式。但是通常情况下,设计师并不会对不同屏幕提供不同的设计图,他们的需求仅仅是不同屏幕下控件对屏幕的相对大小一致,所以dp并不能满足这一点,而对各种屏幕适配一遍又显得略为繁琐,并且修改也较为麻烦。通常我们需要的适配是这样的:
在这里插入图片描述
百分比布局支持库。没有使用过,但是deprecated in API level 26.0.0-beta1。
ConstraintLayout。百分比支持库deprecated之后推荐使用的布局,看起来似乎略复杂。
玩家适配方案。广大玩家的适配目的很明确,目的就是要确保控件在不同屏幕的相对大小一致,看起来一毛一样的。�以一位大神玩家的两种适配方案为例:
�方案一。�编写脚本将长度转换成各分辨率下的长度,缺点是难以覆盖市面上的所有分辨率。
方案二。AutoLayout支持库。该库的想法非常好:对照设计图,使用px编写布局,不影响预览;绘制阶段将对应设计图的px数值计算转换为当前屏幕下适配的大小;为简化接入,inflate时自动将�各Layout转换为对应的AutoLayout,从而不需要在所有的xml中更改。但是同时该库也存在以下等问题:
�扩展性较差。对于每一种ViewGroup都要对应编写对应的AutoLayout进行扩展,对于各View的每个需要适配的属性都要编写代码进行适配扩展;
在onMeasure阶段进行数值计算。消耗性能,并且这对于非LayoutParams中的属性存在较多不合理之处。比如在onMeasure时对TextView的�textSize进行换算并setTextSize,那么��玩家在代码中动态设置的textSize都会失效,因为在每次onMesasure时都会重新被�AutoLayout重新设置覆盖。
issue较多并且作者已不再维护。
二、想法
对于大小差异较大的屏幕,本不该使用同一套设计方案,否则大屏的优势没有完全体现出来,从官方的适配方案也似乎是表达了这个意思。但是在实际设计与开发中,对于一个普通的App,很少有项目有意愿有精力来对各屏幕来分别设计与开发一套设计方案来适配。

通常的一个简单的适配需求是:假如设计图宽度为200,一个控件在设计图上标注的长度为3,那么该控件长度相当于总宽度的3/200,那么我们希望在任何大小的屏幕上该控件所表现的长度都为屏幕宽度的3/200。

个人觉得AutoLayout的设计思想非常优秀,但是将LayoutParams与�属性作为切入口在mesure过程中进行�转换计算的方案存在效率与扩展性等方面的问题。那么Android计算长度的收口在哪里,能不能在Android计算长度时进行换算呢?如果能在Android计算长度时进行换算,那么就不需要一系列多余的计算以及适配,一切问题就都迎刃而解了。

经过一番寻觅,发现系统进行长度计算的收口为�TypedValue中的applyDimension函数,传入单位与value将其计算为对应的px数值。

public static float applyDimension(int unit, float value,
DisplayMetrics metrics)
{
switch (unit) {
case COMPLEX_UNIT_PX:
return value;
case COMPLEX_UNIT_DIP:
return value * metrics.density;
case COMPLEX_UNIT_SP:
return value * metrics.scaledDensity;
case COMPLEX_UNIT_PT:
return value * metrics.xdpi * (1.0f/72);
case COMPLEX_UNIT_IN:
return value * metrics.xdpi;
case COMPLEX_UNIT_MM:
return value * metrics.xdpi * (1.0f/25.4f);
}
return 0;
}
可以看见换算方法非常简单,而DisplayMetrics的�所有属性都是public的,不用反射就能修改;
pt的原意是长度单位磅,根据当前屏幕与设计图尺寸将metrics.xdpi�进行修改就可以实现将pt这个单位重定义成我们所需要的相对长度单位,使修改之后计算出的1pt实际对应的px/屏幕宽度px=1px/设计图宽度px。
而这个DisplayMetrics从哪来?从源码中可以看出一般为mContext.getResources().getDisplayMetrics(),这个mContext即为所在Activity;
�横竖屏切换等Configuration的变化会导致DisplayMetrics�的�重新计算还原;
px,dp与sp都是平时常用的单位,而pt,in与mm几乎没有看见过,从这些不常见的单位下手正好可以不影响其他常用的单位。
基于以上几点,便有了以下方案。

三、方案
本适配方案的目标是:完全按照设计图上标注的尺寸来编写页面,所编写的页面在所有大小与分辨率的屏幕上都表现一致,即控件在所有屏幕上相对于整个屏幕的相对大小都一致(看起来只是将设计图等比缩放至屏幕宽度大小)。

核心。使用冷门的pt作为长度单位,按照上述想法将其重定义为与屏幕大小相关的相对单位,不会对dp等常用单位的使用造成影响。

绘制。编写xml时�完全对照设计稿上的尺寸来编写,只不过单位换为pt。假如设计图宽度为200,一个控件在设计图上标注的长度为3,只需要在初始化时定义宽度为200,绘制该控件时长度写为3pt,那么在任何大小的屏幕上该控件所表现的长度都为屏幕宽度的3/200。如果需要在代码中动态转换成px的话,使用�TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PT, value, metrics)。

预览。实时预览时绘制页面是很重要的一个环节。以1334x750的设计图为例,为了实现于正常绘制时一样的预览功能,创建一个长为1334磅,宽为750磅的设备作为预览,经换算约为21.5英寸((sqrt(13342+7502))/72)。�预览时选择这个设备即可。
在这里插入图片描述
在这里插入图片描述
代码处理。在activityonCreate时修改DisplayMetrics即可,推荐写在基类或ActivityLifecycleCallbacks中,参考github demo。
Point size = new Point();
activity.getWindowManager().getDefaultDisplay().getSize(size);
context.getResources().getDisplayMetrics().xdpi = size.x / designWidth * 72f;
这样绘制出来的页面就跟设计图几乎完全一样,无论大小屏上看起来就只是将设计图缩放之后的结果。
适配前(左图API19 400x800, 右图API24 1440x2560):
在这里插入图片描述
适配后(左图API19 400x800, 右图API24 1440x2560):

在这里插入图片描述
链接:https://www.jianshu.com/p/b6b9bd1fba4d

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/mingming_space/article/details/102893469

智能推荐

正点原子的串口助手XCOM V2.0编码问题-程序员宅基地

文章浏览阅读8k次,点赞4次,收藏11次。该串口助手文本和16进制之间的转换是通过GBK2312来实现的,我还一直以为是Unicode方式如下以“博客园”三个汉字为例:_xcom v2.0

最新opencv-c++安装及配置教程(VS2019 C++ & opencv4.4.0)_c++ opencv配置-程序员宅基地

文章浏览阅读5.2w次,点赞104次,收藏458次。以前写过opencv python的安装教程,后来有一些同学开始私信我如何安装及配置opencv c++。本文是以最新的版本入手,一步步详解opencv c++ 的安装及配置过程。:第一步,下载解压opencv 算法库进入到以下链接:https://opencv.org/releases/ , 点击Windows,即可下载。其他系统可忽略本教程。笔者下载的是opencv 4.4.0 ,如果想尝试预发行版,可以选择opencv 4.5.0。下载之后双击,在抽取文件的目录中选择你想要存放的磁盘和文件即_c++ opencv配置

小蔺的米哈游数据分析师之路——MYSQL篇增删改查篇-程序员宅基地

文章浏览阅读609次。开三方了,开始逼签[牛泪],秋招基本结束,先签一个保底了,三方只能违约一次留给成都华子。内推成功率大大增加!马上面试了[赞][赞][赞][赞][赞][赞][赞]内推码:NTAM81Q投递地址如下!公司是华橙网络,岗位是嵌入式软件开发,学历是硕士985,地点是杭州,校招薪资是20*15,每天餐补17,晚上10点以后打车报销,公积金12%。投递岗位:结构工程师base:东莞投递时间:2023/8/11OPPO三面是hr面,整体感觉挺糟糕的,面试官全程很严肃,问你问题你回答她始终低头记录,对于你的回。

spark常见RDD练习_spark rdd有哪些经典练习案例-程序员宅基地

文章浏览阅读2.1k次。Spark 常用RDD练习其实还是推荐这个网站,写的很棒,点我一、Transformation1 map Applies a transformation function on each item of the RDD and returns the result as a new RDD. (返回一个新的RDD,该RDD有每一个输入元素经过func函数转换后组成)def map[..._spark rdd有哪些经典练习案例

(python)正则表达式提取字符串中的各种信息(持续更新)_正则表达式 获取所有内容(1)-程序员宅基地

文章浏览阅读275次,点赞4次,收藏6次。前两位数字代表省级行政区,中间两位数字代表市级行政区,后两位数字代表县级行政区、县市辖区或直辖市的行政区划。手机号码有自己特定的特征,比如1开头,手机号码长度 11位,一般来说,中国的邮政编码由6位数字组成。省级行政区 市级行政区 县级行政区。不同运营商的号段分布。

方舟编译器最新技术细节,2024年最新简短的面试总结-程序员宅基地

文章浏览阅读217次,点赞5次,收藏3次。希望本文对你有所启发,有任何面试上的建议也欢迎留言分享给大家。好了,今天的分享就到这里,如果你对在面试中遇到的问题,或者刚毕业及工作几年迷茫不知道该如何准备面试并突破现状提升自己,对于自己的未来还不够了解不知道给如何规划,来看看同行们都是如何突破现状,怎么学习的,来吸收他们的面试以及工作经验完善自己的之后的面试计划及职业规划。好了~如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言。一定会认真查询,修正不足。

随便推点

for循环倒序java_for循环-程序员宅基地

文章浏览阅读5.4k次。除了while和do while循环,Java使用最广泛的是for循环。for循环的功能非常强大,它使用计数器实现循环。for循环会先初始化计数器,然后,在每次循环前检测循环条件,在每次循环后更新计数器。计数器变量通常命名为i。我们把1到100求和用for循环改写一下:// for----public class Main {public static void main(String[] arg..._java for 倒序

VS中未定义标识符cout,endl_未定义标识符 "endl-程序员宅基地

文章浏览阅读1w次,点赞6次,收藏10次。VS中未定义标识符vs2017中显示未定义标识符cout,endl。一种方法是:先看有没有包含输入输出流#include,以及命名空间using namespace std;第二种:如果上面都已包含,还是显示未定义标识符的话,检查一下,#include"pch.h"是否是在#include上面我就是犯了第二个错误..._未定义标识符 "endl

python 实现AES-CMAC算法验证_aescmac算法验证-程序员宅基地

文章浏览阅读797次,点赞7次,收藏14次。如果你也是看准了Python,想自学Python,在这里为大家准备了丰厚的免费。_aescmac算法验证

VUE实现网页中滚动鼠标时导航背景颜色透明度的改变_vue可以监听鼠标滚轮滑动,导航条透明度变化-程序员宅基地

文章浏览阅读2.9k次,点赞11次,收藏28次。1、HTML<div id="topNav" :style="topNavBg"> 这里是导航内容</div>2、JSexport default { data () { return { topNavBg: { backgroundColor: '' } } }, mounted () { window.addEventListener('scroll', this.handleScroll) // 监听_vue可以监听鼠标滚轮滑动,导航条透明度变化

【数据结构】单链表-练习_设 l 为带头结点的单链表,编写算法实现从尾到头反向输出每个结点的值-程序员宅基地

文章浏览阅读191次。2. 每当访问一个结点时,先递归输出它后面的结点,再输出该结点自身,这样链表就反向输出了。2. 将上述单链表中的元素按从头到尾的顺序,使用头插法新建一个链表 reverse;【题目】设 L 为带头结点的单链表,编写算法实现从尾到头反向输出每个结点的值。3. 打印输出 reverse 中的元素。【思路】 1. 尾插法建立单链表 L;【答案】 1. 建立一个单链表;_设 l 为带头结点的单链表,编写算法实现从尾到头反向输出每个结点的值

(一) ansible (架构,安装,java代理模式面试题-程序员宅基地

文章浏览阅读982次,点赞15次,收藏12次。其它面试题(springboot、mybatis、并发、java中高级面试总结等)既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)