【Android】App 屏幕适配方案

自 Android 智能手机于2008年10月发布至今,已有十几年的历史,在这十几年里,Android 版本不断发生变化,搭载 Android 系统的设备也在不断的发生变化,屏幕的分辨率也从一开始的 320x480 分辨率到 1440x2560 分辨率。

Android 官方似乎一开始就意识到 app 的适配问题,推出了多达六种的像素单位,不同的单位针对不同的使用场景,分别是:dp、px、sp、pt、mm、in。

  • dp :用于布局尺寸。
  • px :表示屏幕上的实际像素数目。
  • sp :用于文本大小。
  • pt :用于印刷和排版。
  • mm :用于确保在屏幕上的物理尺寸一致。
  • in :用于确保物理尺寸一致。

虽然推出了 '如此之多' 的像素单位,但并不能根治屏幕适配的问题,于是,第一种适配方案应运而生。

系统自适应

系统自适应,是什么意思呢?

其实就是,准备好多个屏幕的尺寸,应用在安装的时候根据设备屏幕的密度自动选择合适的资源文件。

它的原理与 drawable、mipmap 文件的原理相同,都是安装应用后,Android 系统会根据设备屏幕的密度自动选择合适的资源文件。这也就是为什么优化安装包大小时,部分博主会给出尽量只使用 mipmap-xhdpi 的原因之一,图片资源是真的占用 App 大小。

通过系统自适应的方式实现系统自适应屏幕大小,需要运行一套 Java 代码,运行 Java 代码的 main 函数来创建对应的屏幕分辨率。

java 复制代码
public class MakeXml {
    // 生成地址 C 盘layoutroot目录下,这个路径可以更改
    private final static String rootPath = "C:\\layoutroot\\values-{0}x{1}\\";
    /**
     * 设置基准分辨率
     * 一般标注按照多大的图标,这里我们就设置多大尺寸,单位:px
     */
    private final static float dw = 1080f;
    private final static float dh = 1920f;
    private final static String WTemplate = "<dimen name=\"x{0}\">{1}px</dimen>\n";
    private final static String HTemplate = "<dimen name=\"y{0}\">{1}px</dimen>\n";
	private final static String INDENTATION_TAG1 = "    "; 
    // 手机分辨率
    public static void main(String [] args){
        makeString(320, 480);
        makeString(480, 800);
        makeString(480, 854);
        makeString(540, 960);
        makeString(600, 1024);
        makeString(720, 1184);
        makeString(720, 1196);
        makeString(720, 1280);
        makeString(768, 1024);
        makeString(800, 1280);
        makeString(1080, 1812);
        makeString(1080, 1920);
        makeString(1440, 2560);
    }

    public static void makeString(int w, int h) {
        StringBuffer sb = new StringBuffer();
        sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
        sb.append("<resources>\n");
        float cellw = w / dw;
        for (int i = 0; i < dw; i++) {
			sb.append(INDENTATION_TAG1);
            sb.append(WTemplate.replace("{0}", i + "").replace("{1}", change(cellw * i) + ""));
        }
        //此处可将1080换为自己的基准尺寸宽度
		sb.append(INDENTATION_TAG1);
        sb.append(WTemplate.replace("{0}", "1080").replace("{1}", w + ""));
        sb.append("</resources>");
        StringBuffer sb2 = new StringBuffer();
        sb2.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
        sb2.append("<resources>\n");
        float cellh = h / dh;
        for (int i = 0; i < dh; i++) {
			sb2.append(INDENTATION_TAG1);
            sb2.append(HTemplate.replace("{0}", i + "").replace("{1}", change(cellh * i) + ""));
        }
        //此处可将1920换为自己的基准尺寸高度
		sb2.append(INDENTATION_TAG1);
        sb2.append(HTemplate.replace("{0}", "1920").replace("{1}", h + ""));
        sb2.append("</resources>");
        String path = rootPath.replace("{0}", h + "").replace("{1}", w + "");
        File rootFile = new File(path);
        if (!rootFile.exists()) {
            rootFile.mkdirs();
        }
        File layxFile = new File(path + "lay_x.xml");
        File layyFile = new File(path + "lay_y.xml");
        try {
            PrintWriter pw = new PrintWriter(new FileOutputStream(layxFile));
            pw.print(sb.toString());
            pw.close();
            pw = new PrintWriter(new FileOutputStream(layyFile));
            pw.print(sb2.toString());
            pw.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static float change(float a) {
        int temp = (int) (a * 100);
        return temp / 100f;
    }
}

执行成功后会在指定的地址生成各种屏幕分辨率的目录,根据自己设计图的尺寸,添加相对应的尺寸的 dimen 值放至 res/values/dimen.xml ,作为基本的设计尺寸。然后再其它的文件拷贝至项目的 res 目录下,使用 xml 编写 UI 时,组件的宽度从 dimen 中选择,接着运行项目,即可完成适配。

PS:

1、该方式目前在手机上测试是正常的,不同的分辨率系统会在打开应用的时候自动切换成对应的分辨率。问题出在于开发板上,部分开发板只支持默认的分辨率,应用打开后系统不会自动选择合适的分辨率。

2、屏幕适配工作在项目开发初期就应该去做了,越是拖后面,屏幕的适配难度就越大。

AndroidAutoSize

如果 系统自适应 的适配方式不起效果,可以使用 AndroidAutoSize 框架去实现屏幕适配。

AndroidAutoSize 和 系统自适应 的方式实现的原理各不相同,因此 系统自适应 实现不了适配的时候可以使用 AndroidAutoSize 去做,虽然也会有点坑,但完全可以通过 AndroidAutoSize 的 issues 给出的方式去处理问题。

AndroidAutoSize 的使用出奇的简单,只需要两个步骤即可实现适配:

  • 第一步:添加依赖
groovy 复制代码
dependencies {
	implementation 'me.jessyan:autosize:1.2.1'
}
  • 第二步:在 AndroidManifest.xml 文件添加屏幕尺寸
xml 复制代码
<manifest>
    <application>
    	<!-- 设计稿大小,根据项目自行设置 -->
    	<meta-data
            android:name="design_width_in_dp"
            android:value="360" />
        <meta-data
            android:name="design_height_in_dp"
            android:value="640" />
    </application>
</manifest>

这样就完成了 AndroidAutoSize 对屏幕的适配工作。

点击前往 👉 AndroidAutoSize

AndroidAutoSize 存在的问题

1、无法适配 Dialog ,需要自己手动去设置、自定义的方式去调整 Dialog 的大小。

2、横屏应用部分情况会适配失败,AndroidAutoSize 出现的问题可查看 Github 的 issues,作者已在 issues 公布了部分问题出现的原因与处理方法。

Compose

详情请看 👉Jetpack Compose 中适配不同的屏幕尺寸

相关推荐
千里马学框架4 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台4 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone4 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc4 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo4 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077004 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
ai2work4 天前
ch23 综合复刻:从零做一个最小可用版本(capstone)
kotlin
其实防守也摸鱼4 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
ai2work4 天前
ch21 签名、校验与发版
kotlin
AFinalStone4 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui