美文网首页androidAndroidAndroid
一种粗暴快速的Android全屏幕适配方案

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

作者: 布隆 | 来源:发表于2017-07-26 17:05 被阅读25121次

转载请联系作者并注明出处 http://www.jianshu.com/p/b6b9bd1fba4d


目前发现有少量情况没有hold住,具体可能出现问题的场景与解决方案见github
有空会看看上述问题能否集成到sdk中来处理
github


一、现状

由于Android碎片化严重,屏幕适配一直是开发中较为头疼的问题。面对市面上五花八门的屏幕大小与分辨率,��Android基于dp与res目录名称来适配的方案已无法满足一次编写全屏幕适配的需求,为了�达到最优的视觉效果,开发过程中总是需要花费较多资源进行适配。也有开发者给出了一些自己的解决方案。首先来分析一下一些常见的解决方案的现状:

  1. 官方适配方案
    • dp。dp是Android开发中特有的一个单位。与px不同,dp是基于屏幕像素密度的一种单位。在�密度低的屏幕上或许1dp=1px,但在密度高的屏幕上可能1dp=4px。编写布局xml时,如果一个控件的长宽都使用dp来指定,那么能确保该控件在各种大小与分辨率的屏幕下的绝对大小都大致相当。也就是说无论在pad下还是大小屏手机下,我们实际看到的该控件的大小是差不多的:
      图一.png
    • 资源目录名。上图可见虽然使用dp确保了控件在不同屏幕中的绝对大小一致。这样的好处在于,在大小相近的屏幕中,�无论分辨率多大都不会对布局造成影响;但是当屏幕大小相差较大时,仅保证控件的�绝对大小看起来就有些问题了。在res目录下可以给�各资源目录都加上例如'-1920x1080'等后缀来适配不同的�屏幕,具体规则可见官网文档。这样可以针对不同的屏幕提供不同的布局,甚至针对pad与手机提供两套完全不同的布局样式。但是通常情况下,设计师并不会对不同屏幕提供不同的设计图,他们的需求仅仅是不同屏幕下控件对屏幕的相对大小一致,所以dp并不能满足这一点,而对各种屏幕适配一遍又显得略为繁琐,并且修改也较为麻烦。通常我们需要的适配是这样的:
      图二.png
    • 百分比布局支持库。没有使用过,但是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较多并且作者已不再维护。

二、想法

对于大小差异较大的屏幕,本不该使用同一套设计方案,否则大屏的优势没有完全体现出来,从官方的适配方案也似乎是表达了这个意思。但是在实际设计与开发中,对于一个普通的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(1334^2+750^2))/72)。�预览时选择这个设备即可。

    图三.png
    图四.png
  • 代码处理。在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):

图五.png

适配后(左图API19 400x800, 右图API24 1440x2560):


图六.png

虽然方案比较简单,但是为了方便使用也整理成了一个library,代码及demo见github


欢迎大家一起讨论完善,如有问题请统一提github issue方便汇总与处理

相关文章

网友评论

  • JessYan:感谢前辈的贡献,之前发布的 AndroidAutoSize 使用的是今日头条的方案,但发现和你方案的原理都是一样的,只是它使用的单位是 dp,你使用的单位是 pt,最后借鉴前辈的代码优化后 AndroidAutoSize 继续支持了 pt、in、mm 三个单位,至此 dp、sp、pt、in、mm 五个单位 AndroidAutoSize 全部支持, 并且可以随意关闭开启或组合任意单位, https://github.com/JessYanCoding/AndroidAutoSize
    醉卧赏血:@JessYan 按正确区分也就三种,那来的5种!!!
    JessYan:@醉卧赏血 自己看源码
    醉卧赏血:请问一下,pt与in与mm都是一个同一个变量控制的,你是怎么区分开来的?
  • 5c823c4cef37:这个方案不行,Tablayout+ViewPager卡的不行,内存会飙升
  • wangzhiwei:在fragment 中 大部分组件显示正常, 但是有个别会很大, 这是怎么回事啊大神?
  • 前行的乌龟:dm.xdpi = dm.xdpi / designWidth ; 这样算不是更容易理解吗
  • 进击的大东:只是适配了宽度,有很多高度不同的情况需要适配
  • 171Arios:怎么预览啊我的哥
    jiangbin1992:@布隆 我照着新建了额一个预览 750x1334,选择了 不管用啊 我这边那不对啊 亲
    布隆:@171Arios 写了如何预览的方法了的
    171Arios:我刷新了下as可以了
  • 5360fff89701:大哥,你现在这个适配怎么样,比如全面屏,鸿洋大神的需要在 注册文件中 设定好设计尺寸,造成全面屏的适配不是很好,你这个对全面如何?
  • 任半生嚣狂:想法真的很好
    任半生嚣狂:@布隆 那兼容就成了问题
    布隆:@橘之缘之空 但是现在的方法总是有一些地方没有handle住,因为系统总是在某些时候会重置你改掉的值
  • 宇宙只有巴掌大:请问大神,我之前看了你说一切按照pt来,为了这个我今天装逼让ui妹子以后给我尺寸就给pt,结果刚才一看你又说设计图按照px来,只是把这个像素尺寸到xml中直接写成pt,这咋搞啊,逼已经装了我该咋挽回?
    1fb05eee4ef1:int designWidth = 375;
    new RudenessScreenHelper(this, designWidth).activate();
    取375应该可以
    布隆:@宇宙只有巴掌大 抱歉我没看懂你说的啥意思
  • mas_wang:按照这个思路的话,用in和mm单位也是一样的吧
    布隆:@mas_wang 是的
  • 21ee2c8b4921:借楼 https://github.com/yatoooon/AndroidScreenAdaptation 这是我写的一个安卓屏幕适配库,走到这发现和楼主思路差不多,都是按宽度适配的.希望能帮到大家,谢谢!
  • 一叶丶枫凌:Resources resources = context.getResources();
    DisplayMetrics dm = resources.getDisplayMetrics();
    dm.xdpi = dm.widthPixels / designWidth * 72f;
    请问 你这句话的 72f 从哪得来的
    布隆:@一叶丶枫凌 文中解释过了吧
  • 北极瞭望塔:哥们,我使用中遇到了一些问题,是华为mate10,在同样的两k屏上跑是正常的,但是mate10显示不正常,个别的Fragment
    布隆:@北极瞭望塔 私聊
  • b150404c4076:新人请问一下,用了这个还需要在drawable文件夹下配置多套图片吗?
    布隆:@长孙无名 看你需求
  • a8c04441f604:老哥,在fragmnet中,有时操作后,ui显示巨大,重新进入程序后又恢复正常,在Application中进行初始化的.
    a8c04441f604:@布隆 麻烦老哥了
    布隆:@下次_时 我了解一下
  • 旧歌i:老哥,您这个适配手机没有问题,但是换成平板的话 就有问题 了
    布隆:@简书superman 啥问题
  • dadb03a1bc03:这样属性值全部按照宽和宽的比例缩放 还是不完美。需要想办法把值区分计算~
    布隆:@dadb03a1bc03 嗯嗯 确实有点麻烦
    dadb03a1bc03:@布隆 我们现在是通过很麻烦的方式适配的 把每个需要设置宽高的控件取出来 在代码里转换之后设置上去的
    布隆:@dadb03a1bc03 兄弟你想想办法吧
  • 416d6ec73848:适配关键在于修改DisplayMetrics中xdpi的值,但不知系统什么时候会reset这个值。存在一定的适配失败风险。
  • 7b985d48fdc1:博主,你好,你的demo里面pt是怎么计算出来的呢?
  • Jason漂:测试不同设备后觉得 DisplayMetrics 配置效果不太理想,容易出现 DisplayMetrics 配置被还原的情况;主要发生在 APP 切换到后台再切换回前台的情况;这对于动态添加的控件(代码中添加 View、切换 Fragment 等)影响较大;改为在 Application 中初始化并配置 xdpi,在 Application 中监听 onConfigurationChanged 并重新配置 xdpi,目前手头的设备显示正常;UP 主可以参考下;
    Jason漂:@布隆 邮件已发送;若两种方案都存在问题,可以两个方案同时使用,避免出错;仅在 onConfigurationChanged 中设置 Application 的 DisplayMetrics,会造成哪些问题呢?
    布隆:@Jason漂 最开始的版本就是你说的这样,你可以看一下github的提交历史,因为有问题才改成现在这样子。你能够整理一个有问题的demo我来看看吗
    Jason漂:ActivityLifecycleCallbacks 倒是没有用到,目前仅设置了 Application 的 DisplayMetrics;
  • 33248ccd96dd:有时候某个页面会变的很大,导致ui混乱,但是重新安装APP后又可以解决该问题,存在这个隐患 怎么解决 在线求教
    33248ccd96dd:@布隆 怎么能和你沟通一下 这个问题我不知道怎么解决 大神求教
    33248ccd96dd:@布隆 能给个邮箱 发邮箱给你吗
    我拍了个视频
    布隆:@___a7dd 麻烦整理一个能复现的demo我看一下
  • 醉卧赏血:准备深入研究一下你这个东东!有意思!
    布隆:@醉卧赏血 1.关于高度适配。a. 方案上来讲如果按照宽与高同时缩放,那么自然会导致与设计图的长宽比不一样产生误差,当然可能有时候我们并不care这一点点的长宽比变化,只要填满屏幕就行了;b. 技术性来讲,系统计算长度时并不区分长宽,如果需要同时缩放长与宽的话就必须区分,在该方案的基础上开发难度较大,或者就鸿洋的解决方案,需要对每一种控件与属性都进行适配,开销较大并难以覆盖全面,对代码的侵入性也较大。所以综合以上得与失来看,我选择只按照宽度进行等比缩放,在宽度上的适配则只能在开发上注意一点,科学使用wrap_content等属性或预留一些空间等手段来达到目的。第二,这个计算几乎没有什么开销吧。
    醉卧赏血:@布隆 最近没事就顺带看了一下,说说我的问题吧!第一:因为作者这里只做了宽度的百分比适配,那么自然就不会存在高度百分比的适配问题,但是不得不说,高度百分比的适配也是实际存在的,我已经做了高度的百分比适配,但是也引发了鸿洋的那个问题,当我设置一个控件的宽高分别都根据宽高百分比时,一般的字体控件是没有多大问题,但是如果是图片就会发生问题,宽高的换算不一致,导致无法直接通过效果图设置pt达到完美适配,这样一来,我们暂时只能要么根据宽度去设置显示比例,要么根据高度去设置显示比例,但是这也会引发一个问题,打乱效果图整体数字综合的计算,楼主对待这个问题有什么看法,有没有什么好的思路?第二:楼主当前的计算步骤总是发生在每个activity的生命周期函数里面,并且就我所知并不是每个计算都有作用,有些计算只能单纯的消耗性能,比如oncreate里面就没有必要去设置百分比,因为onstart也会计算,前者实则更多是无用功,也是因此,建议作者在onresume进行比例计算,也建议作者可以设置整个app的百分比计算或者单个activity百分比计算,这样用起来更方便(害怕UI善变)。第三,貌似忘记了。。。如果作者有什么好的想法,还望不吝赐教!谢谢老
    布隆:@袁小龙 谢谢支持!
  • Mythqian:横屏是不是不能适配呀, 我预览的和运行的 根本不是一回事,这是为什么
    布隆:@Myth骞 私聊我描述一下?
  • Mr_Gao666:是不是,目前不支持kotlin适配?
    Mr_Gao666:@布隆 我测试了下,可以的额
    布隆:@Mr_Gao666 兄弟你太潮了
  • Jason漂:跳转到桌面后再返回到应用中,显示效果误差很大;xdpi 变回了默认值;经测试在 onActivityPaused 回调中打印 xdpi 值正常,onActivitySaveInstanceState 回调中打印 xdpi 值变回默认值;改为在 onActivityStarted 回调中设置 xdpi 可以正常显示,建议修复下;未做过太多测试,有条件可以测试下不同机型的显示效果;
    布隆:@Jason漂 谢谢 , 已更新并同步至jcenter
    Jason漂:@布隆 小米 2,华为荣耀 3C 均存在这个问题,应该比较常见;这个问题对已加载的控件没有影响,对新添加的控件有影响;如跳转到桌面后再返回到应用中,切换 fragment,则 fragment 按照默认的 xdpi 来显示;
    布隆:@Jason漂 谢谢反馈 我稍后看一下。你的测试机型是?我目前没有遇到过。
  • 3737779bc346:作者你好,目前我项目中也用了你的方式,90%的机型都没有问题, 但是HUAWEI手机的屏幕下面会有虚拟返回键一栏,导致整个屏幕下方,都向上挤了一小部分。这样的问题应该怎么适配呀。
    3737779bc346:@布隆 请问楼主,高度上面的适配,你是怎么适配的呀。:relaxed:
    3737779bc346:@布隆 嗯,目前我也是这样做的,if(有虚拟键){width=750}else{
    width=800},目前适应大部分手机,但是还有一个问题就是 这个width=750屏幕宽度绽放比 和虚拟键的高度单位是不是一样的, 如果是一样的话,就可以算出虚拟键的高度大小+750屏幕宽度绽放比=最终屏幕宽度绽放比,这样的适配可以堪称是完美。
    布隆:@梅川酷子丶 因为方案中只以宽度为标准等比缩放,所以需要在编写时自行考虑到高度上的适配,预留出底部导航栏的空间。
  • 任飞:楼主,如何处理对底部导航栏的适配呢?
  • Jason漂:RecyclerView 的宽或高设置为 wrap_content 时误差很大;
    布隆:@Jason漂 好的
    Jason漂:@布隆 晚点吧;原因待考,目前在 Fragment 中的 RecyclerView 显示效果误差很大;
    布隆:@Jason漂 给个demo看看?
  • 518b63a6bf3f:有想学习 最新技术,OpenCV OpenGl NDK AR VR 等新技术可以加入本群306978835
  • 1b5057877c64:厉害,困扰我很久的问题,看了这个文章,终于有思路了
  • 徐伟咯:安卓的兼容性真是大问题,着直接影响到了App的性能,我们在开发视频图像SDK的时候也必须在性能和兼容性上做出平衡,这也是大部分开发者会遇到的坑
    布隆:@徐伟TuSDK 特别是一大批国产厂商大量修改系统框架。
    布隆:@徐伟TuSDK 同感
  • Tiger_Hu:您好,作者,我看了您的Demo,dp对应的pt是成倍的,可是UI设计图给的单位都是px,那px对应的pt应该给多少呢:blush:
    布隆:@Tiger_Hu 本案中的pt是一个相对宽度,在不同屏幕上的值都不一样。加入设计图宽度是200,那么1pt就相当于屏幕宽度的1/200
  • RedRainM:666666
  • WANGCHONG_:我按照这个方式弄得 但是很ui图完全不一样 怎们回事
    布隆:fixed
    布隆:@害虫_84f3 能私聊我描述一下具体的情况吗
    WANGCHONG_:按照ui图375pt应该填充屏幕 但是效果并不是这样的
  • a1a6e877a389: 博主,我如果是自定义控件的话,也是用成pt作为但单位吗?
    布隆:@安你所知 都可以吧
  • 78983551cc90:我发现还是有误差, 只不过不是很大, 不超过一厘米
  • Jason_Jan:小米4C android版本5.1.1LMY47V 屏幕完全无法正常显示,基本上各种错位,求楼主救命~
    Jason_Jan:@布隆 我直接运行的demo,然后依旧屏幕无法适应,希望楼主能够加一下我QQ
    1211241203 我把截图发给你~
    Jason_Jan:@布隆 好的,我先把我的问题整理一下。
    布隆:@Jason_Jan 我联系你
  • Thebloodelves:然而我觉得dp显示出来的才是正常逻辑的,等比缩放看着别扭
    布隆:@Thebloodelves 按照dp并且大小屏各出不同方案显出大屏优势才是最佳方案;但是通常情况下很少有设计师会出多套适配方案,一套方案要满足多种屏幕只能有所取舍。
  • 844b9a3a3a68:Math.sqrt(1334 ^ 2 + 750 ^ 2) / 21.25 怎么运行都不是21.5啊?你是如何算到的呢?还有创建的模拟器如何在预览时选中?貌似找不到那个选项。。。
    布隆:@有梦想的程序丶猿 注意英寸与磅的单位换算
  • Trilen:楼主的适配原理就是按照宽度来等比缩放,但这样不存在一个问题嘛?忽略了高度!举个不恰当的例子,如果480*800原稿设计的尺寸,有一个控件显示高度是原稿的一半,按你这个方法来,若要适配目标恰好假设是480*1600的机型,这个控件的高度肯定不是一半的高度而是四分之一。因为宽度没有变,适配后得到尺寸值还是480*800的值。你这种方式仅仅适合宽高比是和原稿相同的机型,但这样就是dp没有什么区别了。
    布隆:@Trilen 宽或高只能选其一进行等比缩放,否则长宽比失调;与dp方案最大的区别在于:dp大致确保了1dp在所有屏幕上的物理长度大致相等;本方案大致确保了1pr在所有屏幕上相对于整个屏幕的相对长度大致相等
  • jiamws:我下载了你的demo 在as预览的时候用pt单位编写的控件会变的很大 这样不是会影响开发吗,你那边是怎么处理的
    布隆:@jiamws 文中有写处理方法
  • 15b91cc14715:有个问题,布局中都是以pt来写,实际开发中设计都是dp来的
  • M星空:类弘扬大神的思路,问题是,这样做的话,大屏的优势一点没发挥
    布隆:道理是这个道理。但是有多少设计师会专业到对各种屏各出一份方案呢。
  • 帅气凌风:推荐在在BaseActivity里设置,因为如果Activity是继承FragmentActivity,在Application里设置无效,因为FragmentActivity和Application获得displayMetrics不是同一个对象,看源码也能看出来,希望大家注意点,
    布隆:@帅气凌风 私聊一下给我个demo一起看下?
    帅气凌风:@布隆 这个也不是必现的,有时可以有时不可以,(打印出来看的时候,有时候相等有时候又不相等)所以我就干脆有写了一遍,也是醉了,刚才又出现一个问题,首页的两个fragment,一个fragment可以正常适配,另一个就不行了,醉了啊:joy:
    布隆:是的 我上面也提到了activity与application里获取的确实不是同一个displayMetrics对象,而且我最一开始确实是在BaseActivity里设置的,后来为了图省事才改的。。。。。不过我这边在Application中设置在FragmentActivity中是有效的,你具体是什么case?
  • WzpCy: private void resetDensity(){
    Point size = new Point();
    ((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay().getSize(size);

    getResources().getDisplayMetrics().xdpi = size.x/DESIGN_WIDTH*72f;
    }
    在上面这段代码中 我用720*1280为基础的设计图 是不是把 DESIGN_WIDTH 值改为720就可以 。
    我尝试了改为720 运行时 我设计一个textview textsize大小 为36pt 运行时 却发现字体很大,这是为什么呢
    布隆:@WzpCy 好的 麻烦了
    WzpCy:@布隆 好的,不过晚点才有时间。晚点喊你。
    布隆:你私聊我一下具体描述一下可以吗?
  • LuckyFan:这样的话会导致元素虚化吗?视觉效果不好?
    布隆:如果设计师足够优秀的话会对各种屏幕都出一份适配方案;但是如果人只给你一份图,只要你选择类似方案,都会有这个问题吧。。。
  • 帅气凌风:Imageview貌似不能使用wrapcontent属性了,要写图片具体的数值,单位改为pt
    布隆:这个方案并没有对warp_content属性造成影响吧。Imageview如果使用warp_content的话,应该尽量对各种屏幕密度都给一份适配图才能保证大小吧,但是设计师一般很少这么做,所以我一般确实都是写死长宽的。
  • 帅气凌风:getResources().getDisplayMetrics().xdpi = size.x/DESIGN_WIDTH*72f;这句代码可以解释一下吗,
    帅气凌风:@布隆 不错,完美适配,哈哈哈,博主能想到这个方法厉害啊
    布隆:@帅气凌风 在TypedValue的applyDimension中可以看到系统进行转换时value * metrics.xdpi * (1.0f/72) ,那么 设计图上标注的尺寸/设计图宽度*实际屏幕宽度=我们想要得到的尺寸值=value * metrics.xdpi * (1.0f/72)
  • fcf910b30984:用这个计算,设置drawableTop这类的就很尴尬。
    在7.1测试的时候,如果加载webview,webview 布局混乱,然后回退到主界面,可能会导致布局大小不一致。(原因未查明,现场为:加了8个view ,重新回到这个界面需要重新绘制。每个view大小都是通过上述转换后)。
    推荐DP和SP 加这个混合编译。
    布隆:@侵灵 目前还没有解决,因为之前联系楼上那个朋友并没有回复我。我私聊你一下
    80621de1d3da:@布隆 楼主解决这个问题了吗? 在界面里有webview 的情况下,在setContentView前getResources().getDisplayMetrics().xdpi 获取到的值还是经过转换过后的,而在setContentView后却又变回系统默认值. 有什么好的解决方法,请告知.谢谢
    目前只是在含有webview的Activity的onDestroy()里再次 resetDensity(); 暂时避免了布局大小变化问题.
    布隆:@lingeringsmile 谢谢反馈,我研究一下你这个case
  • WzpCy:你好,博主。想问下 在RecyclerView 的item里面也是直接用PT 么? 设计图 多少px 就直接写多少pt?
    布隆:@WzpCy 可以
  • DOKONG:请问下怎么在AS的编辑预览图里就实现适配? 相当于在application里改宽度就可以对预览图进行同步更新?
    布隆:@DOKONG 如果是使用375*667的设计图来做,预览的话需要添加一个高为667磅,宽为375磅的设备定义,换算过来大约是10.63inch。在预览时选择这个设备即可
    DOKONG:@布隆 设计图纸按照4.7英寸的6S 375*667px来做 我加了一个这样尺寸的模拟器 ,预览的话还是不行...View变得巨大...
    布隆:假如你的设计图是1280x720的,那么需要创建一个1280磅x720磅的设备配置来进行预览
  • xwp:适配我接触到的就只是设计基于3倍图给出设计图,开发照着设计图布局。没发现有手机不行啊。至于图片缩放,我们用大部分图用svg,复杂图片小图出3套,大图出3倍图。
  • 60c8e0743465:博主好,“编写xml时�完全对照设计稿上的尺寸来编写”,设计稿的尺寸是px,对吧?
    布隆:@BingoRiver 写在xml中的属性与自定义属性一样,每个属性都会被解析成一个TypedValue,如果是dim类型就会调用该函数进行转换,而且通常我们代码中会用到的getgetResources().getDimensionPixelSize()等函数实际上也是调用到了该函数。
    60c8e0743465:@布隆 “经过一番寻觅,发现系统进行长度计算的收口为TypedValue中的applyDimension函数,传入单位与value将其计算为对应的px数值。”,不知道能不能将“一番寻觅”和“系统进行长度计算的收口”进行解释。
    布隆:@BingoRiver 嗯 只不过我们在xml上写成pt
  • 看我眼前007:getDefaultDisplay().getSize(size)
    这个 api 的最低版本是13
    布隆:@看我眼前007 干的漂亮
    看我眼前007:适配代码如下:
    public final static float DESIGN_WIDTH = 750;
    //更改DisplayMetrics为我们想要的与屏幕宽度相关的比例
    public void resetDensity(){
    Point size = new Point();
    WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
    Display display = wm.getDefaultDisplay();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
    display.getSize(size);
    }else {
    size.x = display.getWidth();
    size.y = display.getHeight();
    }
    Log.e("SK","size,x:"+size.x+",y:"+size.y);
    getResources().getDisplayMetrics().xdpi = size.x/DESIGN_WIDTH*72f;
    }
    布隆:@看我眼前007 兼容13以下的话可以使用getDefaultDisplay().getWidth()获取宽度; 不过从13开始就Deprecated改为推荐使用getSize了
  • Nightsong:不错,使用中会不会有问题?
    布隆:@Nightsong 目前还没发现问题,朋友要不要帮忙踩几个坑?
  • PatrickGao:博主真是个天才
    布隆:@PatrickGao 过奖
  • 碧海鱼龙:感觉能解决大问题,大胸弟这一看最起码5年的工作经验,写的很棒!
    布隆:@idealcn 私信
    b973150428c2:@布隆 刚两年就装的一手好比,确实厉害,不如留个qq,一起进步
    布隆:@最后的大魔王 哈哈刚两年
  • 借用腊鸡一个鸡:有点懵,这个:需要在代码中动态转换成px时使用TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PT, value, metrics)。
    是在具体哪里动态设置?是在activity中oncreat里面设置吗?急需demo
    布隆:@Mrsu_c2cf 这个动态转换不需要设置呀直接调用就可以了。文中已更新demo
  • 我叫小明哥:where is demo
    布隆:@我叫小明哥 https://github.com/Firedamp/RudeAdaptDemo
    布隆:@我叫小明哥 在整
  • o_o猫先森:通过这个代码适配,布局中的单位用什么,还是dp还是pt?
  • 英勇青铜5:想问下,为何不用ConstraintLayout啊,有啥顾虑吗?文章里的这种处理是更加灵活吗?开发也大半年了,没有做过适配。。。。
    Mike张小多:@伟大的小炮殿下 鸿洋大神的新文章 对ConstraintLayout做了详细的用法说明,实现你的这个要求应该也很简单的吧,可以去看一下。
    英勇青铜5: @英勇青铜5 嗦嘎,学习了,收藏
    伟大的小炮殿下:这么说吧,我提个这样的需求,需要一个屏幕50%宽度的正方形,这种用约束布局该怎么写?想来还是有点复杂是吧,但用autolayout就可以width=360px,height=360px,这玩意的优越性主要在这里.但约束布局也有很多自己的优势,例如显著减少layout层级.
  • shangwfa:weex的开发的适配原理就是这样的
    布隆:这样啊 看来想到一块去了。。
  • 旋哥:有在实际项目中使用过吗?
    布隆:正在使用
  • f0a189b84b74:我也想知道有没有 demo
    f0a189b84b74:@布隆 有一段时间没关注了 支持下
    布隆:https://github.com/Firedamp/RudeAdaptDemo
    布隆:我搞一个
  • loopq:思路看起来和auto差不多,到公司再详细看看,btw,有Demo吗?
    loopq: @布隆 多谢
    布隆:https://github.com/Firedamp/RudeAdaptDemo
    布隆:我搞一个
  • 不听话好孩子:思路很新👏这种方式对底部导航栏适配如何,有在实际项目使用过吗?
    FM小宇宙::joy: 同样碰到了这个问题,别的都兼容,但是有NavigationBar(虚拟导航栏)高度的适配就有些问题了
    不听话好孩子: @T801 了解,就是按宽度比例缩放了
    布隆:因为在适配中只使用宽度来计算适配的长度,所以实际效果看起来是将设计图缩放至屏幕宽度大小,这样保证了页面长宽比相等,不过没有考虑到高度,所以需要考虑到页面长度可能会超过整个屏幕的情况。

本文标题:一种粗暴快速的Android全屏幕适配方案

本文链接:https://www.haomeiwen.com/subject/wijokxtx.html