首页 > 其他分享 >Android屏幕适配的几种方案

Android屏幕适配的几种方案

时间:2023-06-19 11:32:16浏览次数:35  
标签:density 适配 px Android 屏幕 dp 分辨率


前言

由于 Android设备存在有不同的屏幕尺寸,屏幕分辨率,像素密度,Android应用在开发的过程必须要考虑到屏幕尺寸适配的问题,以保证在不同尺寸的Android设备上都能够正常运行。

我们需要利用适配这一个过程把同一张原型图设计的样式尽可能以同样地视觉效果呈现在不同地屏幕上。

适配核心问题

  • 把设计图转化为App界面的过程是否高效
  • 保证实现UI界面在不同尺寸和分辨率的手机中UI的一致性。

屏幕各项参数

  • 手机像素(px):一个小黑点就是像素;
  • 手机尺寸:屏幕的对角线的长度;
  • 手机分辨率:整个屏幕一共有多少个点(像素),常见取值 480X800 ,320X480等;
  • 像素密度(dpi):
  1. 每英寸中的像素数(假如设备分辨率为320*240,屏幕长2英寸宽1.5英寸,dpi=320/2 = 240/1.5 =160)
  2. 对应于DisplayMetrics类中属性densityDpi的值;
  • 密度(density):
  1. 每平方英寸中的像素数(density = dpi / 160 );
  2. 对应于DisplayMetrics类中属性density的值;
  3. 可用于px与px与dip的互相转换 :dp = px / density ;

屏幕适配方案

1、dp+自适应布局+weight比例布局直接适配

这基本是最原始的Android适配方案。

wrap_content,match_parent,layout_weight等,我们就要毫不犹豫的使用,而且在高这个维度上,我们要依照情况设计为可滑动的方式,或者match_parent,尽量不要写死。总之,所有的适配方案都不是用来取代match_parent,wrap_content的,而是用来完善他们的。

2、dimens基于px的适配(宽高限定符适配)

原理

根据市面上手机分辨率的占比分析,我们选定一个占比例值大的(比如1280*720)设定为一个基准,然后其他分辨率根据这个基准做适配。

基准的意思(比如320*480的分辨率为基准)是: 宽为320,将任何分辨率的宽度分为320份,取值为x1到x320 长为480,将任何分辨率的高度分为480份,取值为y1到y480

例如对于800 * 480的分辨率设备来讲,需要在项目中values-800x480目录下的dimens.xml文件中的如下设置(当然了,可以通过工具自动生成):

<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="x1">1.5px</dimen>
<dimen name="x2">3.0px</dimen>
<dimen name="x3">4.5px</dimen>
<dimen name="x4">6.0px</dimen>
<dimen name="x5">7.5px</dimen>

可以看到x1 = 480 / 基准 = 480 / 320 = 1.5 ;它的意思就是同样的1px,在320/480分辨率的手机上是1px,在480/800的分辨率的手机上就是1*1.5px,px会根据我们指定的不同values文件夹自动适配为合适的大小。

Android屏幕适配的几种方案_android

Android屏幕适配的几种方案_android_02

3、dimen 基于dp的适配(smallestWidth适配)

原理

这种适配依据的是最小宽度限定符。指的是Android会识别屏幕可用高度和宽度的最小尺寸的dp值(其实就是手机的宽度值),然后根据识别到的结果去资源文件中寻找对应限定符的文件夹下的资源文件。这种机制和上文提到的宽高限定符适配原理上是一样的,都是系统通过特定的规则来选择对应的文件。

举个例子,小米5的dpi是480,横向像素是1080px,根据px=dp(dpi/160),横向的dp值是1080/(480/160),也就是360dp,系统就会去寻找是否存在value-sw360dp的文件夹以及对应的资源文件。

Android屏幕适配的几种方案_Android_03

Android屏幕适配的几种方案_Android_04

smallestWidth限定符适配和宽高限定符适配最大的区别在于,有很好的容错机制,如果没有value-sw360dp文件夹,系统会向下寻找,比如离360dp最近的只有value-sw350dp,那么Android就会选择value-sw350dp文件夹下面的资源文件。这个特性就完美的解决了上文提到的宽高限定符的容错问题。

4、今日头条适配(修改手机的设备密度 density)

这套方案对老项目是不太友好的,因为修改了系统的density值之后,整个布局的实际尺寸都会发生改变,如果想要在老项目文件中使用,恐怕整个布局文件中的尺寸都可能要重新按照设计稿修改一遍才行。因此,如果你是在维护或者改造老项目,使用这套方案就要三思了。

原理

通过修改density值,强行把所有不同尺寸分辨率的手机的宽度dp值改成一个统一的值,这样就解决了所有的适配问题。

比如,设计稿宽度是360px,那么开发这边就会把目标dp值设为360dp,在不同的设备中,动态修改density值,从而保证(手机像素宽度)px/density这个值始终是360dp,这样的话,就能保证UI在不同的设备上表现一致了。

UI设计图是按屏幕宽度为360dp来设计的,那么在上述设备上,屏幕宽度其实为1080/(440/160)=392.7dp,也就是屏幕是比设计图要宽的。这种情况下, 即使使用dp也是无法在不同设备上显示为同样效果的。 同时还存在部分设备屏幕宽度不足360dp,这时就会导致按360dp宽度来开发实际显示不全。加上16:9、4:3甚至其他宽高比层出不穷,宽高比不同,显示完全一致就不可能了。

通常下,我们只需要以宽或高一个维度去适配,比如我们Feed是上下滑动的,只需要保证在所有设备中宽的维度上显示一致即可,再比如一个不支持上下滑动的页面,那么需要保证在高这个维度上都显示一致,尤其不能存在某些设备上显示不全的情况。

  • 支持以宽或者高一个维度去适配,保持该维度上和设计图一致;
  • 支持dp和sp单位,控制迁移成本到最小。

今日头条的适配方式,今日头条适配方案默认项目中只能以高或宽中的一个作为基准,进行适配。

px = dp * density(dp是360dp),想要px正好是屏幕宽度的话,只能修改density。

/**
     * 适配:修改设备密度
     */
    private static float sNoncompatDensity;
    private static float sNoncompatScaledDensity;

    public static void setCustomDensity(@NonNull Activity activity, @NonNull final Application application) {
        DisplayMetrics appDisplayMetrics = application.getResources().getDisplayMetrics();
        if (sNoncompatDensity == 0) {
            sNoncompatDensity = appDisplayMetrics.density;
            sNoncompatScaledDensity = appDisplayMetrics.scaledDensity;
            // 防止系统切换后不起作用
            application.registerComponentCallbacks(new ComponentCallbacks() {
                @Override
                public void onConfigurationChanged(Configuration newConfig) {
                    if (newConfig != null && newConfig.fontScale > 0) {
                        sNoncompatScaledDensity = application.getResources().getDisplayMetrics().scaledDensity;
                    }
                }

                @Override
                public void onLowMemory() {

                }
            });
        }
        float targetDensity = appDisplayMetrics.widthPixels / 360;
        // 防止字体变小
        float targetScaleDensity = targetDensity * (sNoncompatScaledDensity / sNoncompatDensity);
        int targetDensityDpi = (int) (160 * targetDensity);

        appDisplayMetrics.density = targetDensity;
        appDisplayMetrics.scaledDensity = targetScaleDensity;
        appDisplayMetrics.densityDpi = targetDensityDpi;

        final DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics();
        activityDisplayMetrics.density = targetDensity;
        activityDisplayMetrics.scaledDensity = targetScaleDensity;
        activityDisplayMetrics.densityDpi = targetDensityDpi;

    }

只需要在baseActivity中添加一句话即可。适配就是这么简单。

DisplayUtil.setCustomDensity(this, getApplication());

屏幕适配一直是困扰 Android 开发工程师的一大问题,但是随着近几年各种屏幕适配方案的诞生,以及谷歌各种适配控件的推出,屏幕适配也显得越来越容易。

标签:density,适配,px,Android,屏幕,dp,分辨率
From: https://blog.51cto.com/u_16163442/6512059

相关文章

  • android连接本地数据库sqlite,实现增删改查
    前言Android应用数据存储简单来说有这么几种:文件存储、SharedPreference存储、SQLite数据库存储、网络服务器存储、ContentProvider等。如果需要存储的数据量大的时候,那么使用文件存储会有很大的弊端,例如:你想修改其中很微小的项就要先读取整个文件的内容,修改后再全部保存,非常耗时。......
  • 2023-06-19 uniapp云打包报错:app-plus.distribute.icons.android.hdpi 文件不存在
    详细报错:[HBuilder]11:02:51.408Manifest.json文件以下节点配置错误,请检查修复[HBuilder]11:02:51.408app-plus.distribute.icons.android.hdpi 文件不存在[HBuilder]11:02:51.408app-plus.distribute.icons.android.xxhdpi 文件不存在[HBuilder]11:02:51.408ap......
  • 一文带你了解Android IO的底层原理
    前言最近在看《Linux内核设计与实现》的时候,就想着要不把知识串联一下吧。聊什么呢?今天先来聊聊AndroidIO的调用链路。说起IO,这可真是一个很复杂的过程,里面涉及了很多内容,先是软件,最后到硬件,用一张图来表示一下吧:本文打算简单得和大伙讨论一下IO的流程。一、应用层作为应用开......
  • Android 架构之 MVI 完全体 | 重新审视 MVVM 之殇,PartialChange & Reducer 来拯救
    作者:唐子玄MVI架构有三大关键词:“唯一可信数据源”+“单向数据流”+“响应式编程”,以及一些关键概念,比如Intent,State。理解这些概念之后,能更轻松地阅读本文。(强烈建议从第一篇开始阅读)引子在上一篇中,用MVI重构了“新闻流”这个业务场景。本篇在此基础上进一步拓展,引入MVI中......
  • 干了8年Android开发熬到年薪40万,突然接到被辞退消息,应该怎么办?
    0136岁Android开发,为公司工作8年,昨天HR说公司不准备续约前天晚上,有个读者给我留言,讲述了他自己比较气愤的一件事,感觉自己委屈又不值。这位朋友不愿意透露姓名,就叫他H先生吧。H先生是典型的学霸,大学也是211的牌子,又是计算机专业。研究生毕业以后就进入了现在的公司当了一名Android......
  • 方法对了,你做1年Android开发能顶别人做10年
    前几天后台有读者问我这样的问题。他在一家互联网公司工作3年了,每天都很忙,事情又多又杂。本想着学习多一些东西也不是坏事,可到头来一无所获,什么都没学会,满腔的热情也被消磨得差不多。三天两头动辞职的念头,但又不知道自己还能做什么,甚至开始后悔:如果当初选择另一个行业,是不是就会好......
  • 做Android开发,你后悔过吗?
    有同学跟我说,编程太难了,总是有学不完的技术、框架,新技术也层出不穷,马上三十了,还有各种学不完的东西,后悔做程序员了编程对我来讲,还难吗我主业是做Android的。我刚学编程的时候,觉得难点在于众多语法/API的学习,以及抓耳挠腮、苦思冥想捉bug的无奈。但无论语法多么复杂难用,终究会有学会......
  • 阿里钉钉Android实习面试也太太太太难了吧,对算法的要求堪比字节
    本人研究生在读,在2月26日找了师兄内推阿里钉钉团队,28号接到了约1面的电话。幸好我提前准备了一个多月的样子,刷面试题、刷LeetCode(面了之后才觉得自己刷少了),对于我这样一个实习生来说题目还是有些偏难,不过在4月20号终于拿到意向书了,听内推人说阿里实习面试没有rank,可能单纯就是流程......
  • 大厂技术总监总结的Android Framework开发笔记火了!知乎已1.7k赞!不吃透都对不起他
    为什么要学AndroidFramework?想要成为一名优秀的Android开发,就需要有一个完备的知识体系,AndroidFramework的知识是很重要的一个组成部分,他广泛的应用在各个领域。像掉帧监控,函数插装,慢函数检测,ANR监控,启动监控,都需要对Framework有比较深入的了解。只有这样才能知道怎么去做监......
  • 又一开源项目爆火于GitHub,Android高级插件化强化实战
    一、插件化起源插件化技术最初源于免安装运行Apk的想法,这个免安装的Apk就可以理解为插件,而支持插件的app我们一般叫宿主。想必大家都知道,在Android系统中,应用是以Apk的形式存在的,应用都需要安装才能使用。但实际上Android系统安装应用的方式相当简单,其实就是把应用Apk......