一种粗暴快速的Android全屏幕适配方案

简介:

一、现状

由于Android碎片化严重,屏幕适配一直是开发中较为头疼的问题。面对市面上五花八门的屏幕大小与分辨率,Android基于dp与res目录名称来适配的方案已无法满足一次编写全屏幕适配的需求,为了达到最优的视觉效果,开发过程中总是需要花费较多资源进行适配。也有开发者给出了一些自己的解决方案。首先来分析一下一些常见的解决方案的现状: 1. 官方适配方案 – dp。dp是Android开发中特有的一个单位。与px不同,dp是基于屏幕像素密度的一种单位。在密度低的屏幕上或许1dp=1px,但在密度高的屏幕上可能1dp=4px。编写布局xml时,如果一个控件的长宽都使用dp来指定,那么能确保该控件在各种大小与分辨率的屏幕下的绝对大小都大致相当。也就是说无论在pad下还是大小屏手机下,我们实际看到的该控件的大小是差不多的:

- 资源目录名。上图可见虽然使用dp确保了控件在不同屏幕中的绝对大小一致。这样的好处在于,在大小相近的屏幕中,无论分辨率多大都不会对布局造成影响;但是当屏幕大小相差较大时,仅保证控件的绝对大小看起来就有些问题了。在res目录下可以给各资源目录都加上例如’-1920×1080′等后缀来适配不同的屏幕,具体规则可见官网文档。这样可以针对不同的屏幕提供不同的布局,甚至针对pad与手机提供两套完全不同的布局样式。但是通常情况下,设计师并不会对不同屏幕提供不同的设计图,他们的需求仅仅是不同屏幕下控件对屏幕的相对大小一致,所以dp并不能满足这一点,而对各种屏幕适配一遍又显得略为繁琐,并且修改也较为麻烦。通常我们需要的适配是这样的:

- 百分比布局支持库。没有使用过,但是deprecated in API level 26.0.0-beta1。

- ConstraintLayout。百分比支持库deprecated之后推荐使用的布局,看起来似乎略复杂。 2. 玩家适配方案。广大玩家的适配目的很明确,目的就是要确保控件在不同屏幕的相对大小一致,看起来一毛一样的。以一位大神玩家的两种适配方案为例:

- 方案一。编写脚本将长度转换成各分辨率下的长度,缺点是难以覆盖市面上的所有分辨率。

- 方案二。AutoLayout支持库。该库的想法非常好:对照设计图,使用px编写布局,不影响预览;绘制阶段将对应设计图的px数值计算转换为当前屏幕下适配的大小;为简化接入,inflate时自动将各Layout转换为对应的AutoLayout,从而不需要在所有的xml中更改。但是同时该库也存在以下等问题:

- 扩展性较差。对于每一种ViewGroup都要对应编写对应的AutoLayout进行扩展,对于各View的每个需要适配的属性都要编写代码进行适配扩展; – 在onMeasure阶段进行数值计算。这对于非LayoutParams中的属性存在较多不合理之处。比如在onMeasure时对TextView的textSize进行换算并setTextSize,那么玩家在代码中动态设置的textSize都会失效,因为在每次onMesasure时都会重新被AutoLayout重新设置覆盖。 – issue较多并且作者已不再维护。

二、想法

个人觉得AutoLayout的设计思想非常优秀,但是将LayoutParams与属性作为切入口在mesure过程中进行转换计算的方案存在效率与扩展性等方面的问题。那么Android计算长度的收口在哪里,能不能在Android计算长度时进行换算呢?如果能在Android计算长度时进行换算,那么就不需要一系列多余的计算以及适配,一切问题就都迎刃而解了。 经过一番寻觅,发现系统进行长度计算的收口为TypedValue中的applyDimension函数,传入单位与value将其计算为对应的px数值。

 
 
  1. public static float applyDimension(int unit, float value, 
  2.                                        DisplayMetrics metrics) 
  3.     { 
  4.         switch (unit) { 
  5.         case COMPLEX_UNIT_PX: 
  6.             return value; 
  7.         case COMPLEX_UNIT_DIP: 
  8.             return value * metrics.density; 
  9.         case COMPLEX_UNIT_SP: 
  10.             return value * metrics.scaledDensity; 
  11.         case COMPLEX_UNIT_PT: 
  12.             return value * metrics.xdpi * (1.0f/72); 
  13.         case COMPLEX_UNIT_IN: 
  14.             return value * metrics.xdpi; 
  15.         case COMPLEX_UNIT_MM: 
  16.             return value * metrics.xdpi * (1.0f/25.4f); 
  17.         } 
  18.         return 0; 
  19.     }  
  • 可以看见换算方法非常简单,而DisplayMetrics的所有属性都是public的,不用反射就能修改;
  • 而这个DisplayMetrics从哪来?从源码中可以看出一般为mContext.getResources().getDisplayMetrics(),这个mContext即为所在Activity;
  • Activity中所拿到的DisplayMetrics与Application中拿到的DisplayMetrics虽然不是一个实例,但是所有数值都相同,在Application中进行更改也会影响到所有Activity中;
  • 横竖屏切换等Configuration的变化会导致DisplayMetrics的重新计算还原,需要重新处理;
  • px,dp与sp都是平时常用的单位,而pt,in与mm几乎没有看见过,从这些不常见的单位下手正好可以不影响其他常用的单位;
  • pt的原意是长度单位磅,根据当前屏幕与设计图尺寸将metrics.xdpi进行修改就可以实现将pt这个单位重定义成我们所需要的相对长度单位,使修改之后计算出的1pt实际对应的px/屏幕宽度px=1px/设计图宽度px。

基于以上几点,遍有了以下方案。

三、方案

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

  • 核心。使用冷门的pt作为长度单位。
  • 绘制。编写xml时完全对照设计稿上的尺寸来编写,只不过单位换为pt。 如果需要在代码中动态转换成px的话,使用TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PT, value, metrics)。
  • 预览。实时预览时绘制页面是很重要的一个环节。以1334×750的设计图为例,为了实现于正常绘制时一样的预览功能,创建一个长为1334磅,宽为750磅的设备作为预览,经换算约为21.5英寸((sqrt(1334^2+750^2))/72)。预览时选择这个设备即可。

  • 代码处理。代码处理有两种方案:如果所有页面的设计图尺寸都一样,则在Applicalition中的onCreate中与onConfigurationChanged中处理即可;如果每个页面的设计图尺寸不一样,则需要在每个activity的onCreate中处理(Activity中不需要处理onConfigurationChanged,因为配置变化页面会重新生成)。
    • 全局处理方案。在Application的onCreate中与onConfigurationChanged中更改DisplayMetrics(其中DESIGN_WIDTH是绘制页面时参照的设计图宽度): 
 
 
  1. public class MyApplication extends Application{ 
  2.  
  3. public final static float DESIGN_WIDTH = 750; //绘制页面时参照的设计图宽度 
  4.  
  5. @Override 
  6. public void onCreate() { 
  7.     super.onCreate(); 
  8.  
  9.     resetDensity(); 
  10.  
  11. @Override 
  12. public void onConfigurationChanged(Configuration newConfig) { 
  13.     super.onConfigurationChanged(newConfig); 
  14.     resetDensity(); 
  15.  
  16. public void resetDensity(){ 
  17.     Point size = new Point(); 
  18.     ((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay().getSize(size); 
  19.  
  20.     getResources().getDisplayMetrics().xdpi = size.x/DESIGN_WIDTH*72f; 
  21.  

这样绘制出来的页面就跟设计图几乎完全一样,无论大小屏上看起来就只是将设计图缩放之后的结果。 适配前(左图API19 400×800, 右图API24 1440×2560):

适配后(左图API19 400×800, 右图API24 1440×2560): 





本文作者:佚名
来源:51CTO
目录
相关文章
|
XML 编解码 Android开发
一种粗暴快速的Android全屏幕适配方案
一、现状 由于Android碎片化严重,屏幕适配一直是开发中较为头疼的问题。面对市面上五花八门的屏幕大小与分辨率,Android基于dp与res目录名称来适配的方案已无法满足一次编写全屏幕适配的需求,为了达到最优的视觉效果,开发过程中总是需要花费较多资源进行适配。
5283 0
|
2天前
|
Linux 编译器 Android开发
FFmpeg开发笔记(九)Linux交叉编译Android的x265库
在Linux环境下,本文指导如何交叉编译x265的so库以适应Android。首先,需安装cmake和下载android-ndk-r21e。接着,下载x265源码,修改crosscompile.cmake的编译器设置。配置x265源码,使用指定的NDK路径,并在配置界面修改相关选项。随后,修改编译规则,编译并安装x265,调整pc描述文件并更新PKG_CONFIG_PATH。最后,修改FFmpeg配置脚本启用x265支持,编译安装FFmpeg,将生成的so文件导入Android工程,调整gradle配置以确保顺利运行。
22 1
FFmpeg开发笔记(九)Linux交叉编译Android的x265库
|
25天前
|
Java Android开发
Android 开发获取通知栏权限时会出现两个应用图标
Android 开发获取通知栏权限时会出现两个应用图标
12 0
|
1月前
|
XML 缓存 Android开发
Android开发,使用kotlin学习多媒体功能(详细)
Android开发,使用kotlin学习多媒体功能(详细)
101 0
|
1月前
|
设计模式 人工智能 开发工具
安卓应用开发:构建未来移动体验
【2月更文挑战第17天】 随着智能手机的普及和移动互联网技术的不断进步,安卓应用开发已成为一个热门领域。本文将深入探讨安卓平台的应用开发流程、关键技术以及未来发展趋势。通过分析安卓系统的架构、开发工具和框架,本文旨在为开发者提供全面的技术指导,帮助他们构建高效、创新的移动应用,以满足不断变化的市场需求。
18 1
|
1月前
|
机器学习/深度学习 调度 Android开发
安卓应用开发:打造高效通知管理系统
【2月更文挑战第14天】 在移动操作系统中,通知管理是影响用户体验的关键因素之一。本文将探讨如何在安卓平台上构建一个高效的通知管理系统,包括服务、频道和通知的优化策略。我们将讨论最新的安卓开发工具和技术,以及如何通过这些工具提高通知的可见性和用户互动性,同时确保不会对用户造成干扰。
33 1
|
16天前
|
XML 开发工具 Android开发
构建高效的安卓应用:使用Jetpack Compose优化UI开发
【4月更文挑战第7天】 随着Android开发不断进化,开发者面临着提高应用性能与简化UI构建流程的双重挑战。本文将探讨如何使用Jetpack Compose这一现代UI工具包来优化安卓应用的开发流程,并提升用户界面的流畅性与一致性。通过介绍Jetpack Compose的核心概念、与传统方法的区别以及实际集成步骤,我们旨在提供一种高效且可靠的解决方案,以帮助开发者构建响应迅速且用户体验优良的安卓应用。
|
18天前
|
监控 算法 Android开发
安卓应用开发:打造高效启动流程
【4月更文挑战第5天】 在移动应用的世界中,用户的第一印象至关重要。特别是对于安卓应用而言,启动时间是用户体验的关键指标之一。本文将深入探讨如何优化安卓应用的启动流程,从而减少启动时间,提升用户满意度。我们将从分析应用启动流程的各个阶段入手,提出一系列实用的技术策略,包括代码层面的优化、资源加载的管理以及异步初始化等,帮助开发者构建快速响应的安卓应用。
|
18天前
|
Java Android开发
Android开发之使用OpenGL实现翻书动画
本文讲述了如何使用OpenGL实现更平滑、逼真的电子书翻页动画,以解决传统贝塞尔曲线方法存在的卡顿和阴影问题。作者分享了一个改造后的外国代码示例,提供了从前往后和从后往前的翻页效果动图。文章附带了`GlTurnActivity`的Java代码片段,展示如何加载和显示书籍图片。完整工程代码可在作者的GitHub找到:https://github.com/aqi00/note/tree/master/ExmOpenGL。
19 1
Android开发之使用OpenGL实现翻书动画
|
18天前
|
Android开发 开发者
Android开发之OpenGL的画笔工具GL10
这篇文章简述了OpenGL通过GL10进行三维图形绘制,强调颜色取值范围为0.0到1.0,背景和画笔颜色设置方法;介绍了三维坐标系及与之相关的旋转、平移和缩放操作;最后探讨了坐标矩阵变换,包括设置绘图区域、调整镜头参数和改变观测方位。示例代码展示了如何使用这些方法创建简单的三维立方体。
15 1
Android开发之OpenGL的画笔工具GL10