前一段时间无意中看到今日头条的适配方案,使用到项目中,感觉真的是无比丝滑。所以特意写一篇文章分享给小伙伴们!

本文知识点:

为什么要做屏幕适配

今日头条的适配方案(划重点)

今日头条的适配方案的一些问题

1. 为什么要做屏幕适配

做Android开发的都了解,由于Android屏幕碎片化严重,虽然Android官方提供了dp为单位的适配方案,但是由于各种千奇百怪的机型,所以变现往往不尽如人意。所以需要进行屏幕适配。说白了就是让所有机型都进行保持UI的设计原貌!

2. 今日头条的适配方案

终于到了本文的重点了。为了大家能深刻理解其中的含义,这里从最基本的开始说起。

2.1 传统的dp适配的流程

android中的dp在渲染前会将dp转为px,计算公式:

px = density * dp;

density = dpi / 160;

px = dp * (dpi / 160);

复制代码

而dpi是根据屏幕真实的分辨率和尺寸来计算的,每个设备都可能不一样的。那么dpi是怎么计算的呢?

上面图片说明dpi是怎么计算得来的。举个例子,当屏幕分辨率为1920 * 1080屏幕尺寸为5寸的手机。计算得来的dpi为440。不信的话可以计算一下!

那么问题来了?

假设我们UI设计图是按屏幕宽度为360dp来设计的,那么在上述设备上,屏幕宽度其实为1080/(440/160)=392.7dp,也就是屏幕是比设计图要宽的。这种情况下, 即使使用dp也是无法在不同设备上显示为同样效果的。 同时还存在部分设备屏幕宽度不足360dp,这时就会导致按360dp宽度来开发实际显示不全的情况。

而且上述屏幕尺寸、分辨率和像素密度的关系,很多设备并没有按此规则来实现, 因此dpi的值非常乱,没有规律可循,从而导致使用dp适配效果差强人意。

3.2 今日头条的适配方式说明

其实,当我们拿到设计图的时候,一般都是根据苹果的6进行设计的,往往在Android中,存在16:9和4:3的一些机型,那么这些机型中的宽高比不同,如果想完全按照设计图进行适配是不可能的,也是不现实的。但是如果我们以一个维度,也就是宽这个维度来进行适配的话,如果高度超出了屏幕我们就使用可滑动的控件进行展示。这就是今日头条的适配方案。

因此,采用以宽度为标准去进行适配,保持该维度上和设计图一致

2.3 今日头条的适配方案

先科普几个内容,

dp和px的转换公式为:px = dp * density

dp转换的场景都是通过DisplayMetrics来进行计算的,

DisplayMetrics#density 就是上述的density

DisplayMetrics#densityDpi 就是上述的dpi

DisplayMetrics#scaledDensity 字体的缩放因子,正常情况下和density相等,但是调节系统字体大小后会改变这个值

因为所有关于dp的计算都是通过DisplayMetrics这个类进行的。所以只需要针对这个类进行操作就可以了。

我简单把DisplayMetrics类分为三个层面,第一个是System(可以理解成初始分配)的,第二个是APP(可以理解成Application)的,第三个是Activity的。当你适配的时候,尽量不要去修改第一个System中的Displaymetris的,因为可能第三方的库不会按照你的方式去适配,所以这里只修改后面两个就可以了。第一个不修改是便于之后的还原!!!

以下是三个层面获取DisplayMetrics中的代码:

// 系统的屏幕尺寸

final DisplayMetrics systemDm = Resources.getSystem().getDisplayMetrics();

// app整体的屏幕尺寸

final DisplayMetrics appDm = Utils.getApp().getResources().getDisplayMetrics();

// activity的屏幕尺寸

final DisplayMetrics activityDm = activity.getResources().getDisplayMetrics();

复制代码

接下来我们看看需要怎么适配,这里就只以屏幕宽度为基准进行相应的适配了。这里模拟360dp为基准的适配,当然这个值你是可以修改成任何尺寸的!

先计算一下屏幕的宽度

//这里widthPixels代表屏幕的宽度

activityDm.density = activityDm.widthPixels / 360;

复制代码计算一下字体的density

//这里通过一个比例确定activity字体的density

activityDm.scaledDensity = activityDm.density * (systemDm.scaledDensity / systemDm.density);

复制代码计算相应的dpi

//上面有相应的公式

activityDm.densityDpi = (int) (160 * activityDm.density);

复制代码复制相应的内容

//进行相应的赋值操作

appDm.density = activityDm.density;

appDm.scaledDensity = activityDm.scaledDensity;

appDm.densityDpi = activityDm.densityDpi;

复制代码

整体代码如下:

/**

* 适配的主要代码

*

* @param activity 上下文

* @param sizeInPx 你要适配的相应尺寸

* @param isVerticalSlide 水平还是垂直为参考

*/

private static void adaptScreen(final Activity activity,

final int sizeInPx,

final boolean isVerticalSlide){

// 系统的屏幕尺寸

final DisplayMetrics systemDm = Resources.getSystem().getDisplayMetrics();

// app整体的屏幕尺寸

final DisplayMetrics appDm = Utils.getApp().getResources().getDisplayMetrics();

// activity的屏幕尺寸

final DisplayMetrics activityDm = activity.getResources().getDisplayMetrics();

if (isVerticalSlide) {

activityDm.density = activityDm.widthPixels / (float) sizeInPx;

Log.e(TAG, "adaptScreen: "+activityDm.widthPixels );

} else {

activityDm.density = activityDm.heightPixels / (float) sizeInPx;

}

// 字体的缩放因子,这个是通过一个比例计算得来的!

activityDm.scaledDensity = activityDm.density * (systemDm.scaledDensity / systemDm.density);

// 计算得到相应的dpi

activityDm.densityDpi = (int) (160 * activityDm.density);

//进行相应的赋值操作

appDm.density = activityDm.density;

appDm.scaledDensity = activityDm.scaledDensity;

appDm.densityDpi = activityDm.densityDpi;

}

复制代码

因为上面涉及到横竖屏的问题,所以这里有个if判断。上面是主要代码。

3 今日头条的适配方案的一些问题

3.1 适配之后Toast的问题?

进行上面的适配之后,Toast会变得很小。其实也不难理解,因为你修改了APP的density,所以整个图片的界面都会发生相应的变化也就很好理解了。那么怎么解决呢?其实就想上面说的,使用System的density对App和Activity进行还原。怎么说呢?其实就是在show()方法之前还原,在之后在进行适配。

怎么取消呢?看下面的代码。

public static void cancelAdaptScreen(final Activity activity){

final DisplayMetrics systemDm = Resources.getSystem().getDisplayMetrics();

final DisplayMetrics appDm = Utils.getApp().getResources().getDisplayMetrics();

final DisplayMetrics activityDm = activity.getResources().getDisplayMetrics();

activityDm.density = systemDm.density;

activityDm.scaledDensity = systemDm.scaledDensity;

activityDm.densityDpi = systemDm.densityDpi;

appDm.density = systemDm.density;

appDm.scaledDensity = systemDm.scaledDensity;

appDm.densityDpi = systemDm.densityDpi;

}

复制代码

其实就是使用System的density把APP和Activity的density修改回来就可以了!

然后在show()方法之后使用下面方法重新对界面进行适配!

public static void restoreAdaptScreen(Activity activity, boolean isVerticalSlide, int sizeInPx){

final DisplayMetrics systemDm = Resources.getSystem().getDisplayMetrics();

final DisplayMetrics appDm = Utils.getApp().getResources().getDisplayMetrics();

final DisplayMetrics activityDm = activity.getResources().getDisplayMetrics();

if (isVerticalSlide) {

activityDm.density = activityDm.widthPixels / (float) sizeInPx;

} else {

activityDm.density = activityDm.heightPixels / (float) sizeInPx;

}

activityDm.scaledDensity = activityDm.density * (systemDm.scaledDensity / systemDm.density);

activityDm.densityDpi = (int) (160 * activityDm.density);

appDm.density = activityDm.density;

appDm.scaledDensity = activityDm.scaledDensity;

appDm.densityDpi = activityDm.densityDpi;

}

复制代码

调用代码就变成了这个样子

//取消适配

ScreenUtils.cancelAdaptScreen(this);

//弹出Toast

Toast.makeText(this, "点击了第一个内容", Toast.LENGTH_SHORT).show();

//重新适配

ScreenUtils.restoreVerticalAdaptScreen(this, 720);

复制代码

像什么Toast、dialog什么的都会出现上面的情况,所以解决办法是一样的

3.2 webview加载后发现density复原

由于 WebView 初始化的时候会还原 density 的值导致适配失效,继承 WebView,重写如下方法:

@Override

public void setOverScrollMode(int mode){

super.setOverScrollMode(mode);

ScreenUtils.restoreAdaptScreen();

}

复制代码

今日头条Android适配方案,android 今日头条的屏幕适配理解相关推荐

  1. 安卓屏幕适配方案(根据今日头条方案,升级版)

    前言 屏幕适配方案有很多,比如原生的dp,鸿洋大神的AutoLayout,宽高限定符,今天我用缺点比较小的今日头条方案 头条适配方案的文章链接:https://mp.weixin.qq.com/s/d ...

  2. 今日头条适配方案_AppStore今日推荐 追书、看漫画 资源全的好评软件

    首先声明如果软件界面有广告,大帆会说明, 如果介意请谨慎下载 复制软件名称到App Store中搜索粘贴即可,还是找不到可以私信发送免费获取链接. (今日头条极速版请下载今日头条或者关注公众号:张大帆 ...

  3. 今日头条适配方案_AppStore今日分享 价值78元的恋爱游戏 秋之回忆6

    如果对游戏或者应用有兴趣强烈建议仔细看一下图文方法 分享不易如果对你有帮助请花点时间评论转发一下 不要问私信在哪看最下面的文字 这是这是一款恋爱游戏 玩家将在校园里和几位性格不同的女生纯真的谈一次恋爱 ...

  4. Android适配--最详细的限定符屏幕适配方案解析 附带values-Dimens文件生成工具

    屏幕适配 前言 适配缘由 相关概念 适配方案 db适配 设计最大分辨率图片 屏幕分辨率限定符(宽高限定符) dimens文件生成原理 使用样例1 使用样例2 dimens文件生成脚本 总结 最小宽度限 ...

  5. android ui布局适配,Android适配全面总结(一)----屏幕适配

    前言 Android适配是一个老生常谈的问题,很多程序员觉得很恶心,不愿意做适配,但是又不得不做.然后老板说,这位兄弟,做好了,今天晚饭给你加个鸡腿,然后程序员开始找各种资料,忙活起来了,最终在苦逼的 ...

  6. android屏幕适配:一个很棒的屏幕适配文章

    转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992 Android的屏幕适配一直以来都在折磨着我们这些开发者,本篇文章以Google的官方文档为基础,全面而深入 ...

  7. Android适配全面总结(一)----屏幕适配

    版权声明:本文为博主原创文章(部分引用他人博文,已加上引用说明),未经博主允许不得转载.https://www.jianshu.com/p/7aa34434ad4d 转载请标明出处: https:// ...

  8. android 渠道方案,Android多渠道打包时获取当前渠道的方法

    作为Androidapp,发布多个分发平台是常规操作.然后,有时由于个渠道面对的用户不同,或平台审核标准不同,需要在各渠道使用不同的业务逻辑,这就需要根据渠道使用选择差异化代码. 这里把简单的代码记一 ...

  9. android 渠道方案,Android 不同渠道差异代码

    前言 在开发过程中,会遇到这种业务. 在某一个渠道,需要引入一些三方sdk,需要写一些差异性代码,跟原来的业务有重叠.如果所有的判断逻辑都写在一起,会出现很多if(flavor==xxx),并且三方s ...

最新文章

  1. LeetCode实战:最大子序和
  2. 吴恩达邀请9位AI大牛畅想2020:李开复看好医疗教育,LeCun强调自监督学习
  3. QT的QScxmlCppDataModel类的使用
  4. 【TensorFlow】:解决TensorFlow的ImportError: DLL load failed: 动态链接库(DLL)初始化例程失败...
  5. css 文字重叠_html网页文字重叠 字体叠加显示css如何解决
  6. Java 线程详解(一)线程的基础
  7. 两个offer如何做选择?年薪20万vs年薪15万
  8. 【动态规划】牛客网:把数字翻译成字符串
  9. linux查看服务_Linux服务下通过指令查看JVM(非原创侵删)
  10. win10 桌面右键菜单内容修改
  11. rfc3315_DHCPv6-RFC3315(中文).pdf
  12. 交换机常用功能配置案例总结
  13. Ubuntu系统切换jdk版本
  14. 基于Open CV的植物图像分类识别项目
  15. php启动 大量sess文件,关于PHP中Session文件过多的有关问题
  16. azkaban 调度任务一直处于preparing状态
  17. unity android 不锁屏,Screen.sleepTimeout=SleepTimeOut.NeverSleep 禁止屏幕锁屏
  18. 关于Ajax请求服务器端的处理
  19. 蓝牙突然消失,ubuntu连接音箱没有声音问题
  20. anaconda中安装PIV库

热门文章

  1. myeclipse优化配置指南、myeclipse常用功能设置、 myeclipse快捷键
  2. 【Linux】ab命令实现网站性能压力测试
  3. Amazon Shield Advanced 更新 – 自动应用程序层 DDoS 防御
  4. 85后独立手游开发者专访:为游戏而坚持
  5. Tiled源码分析: 序
  6. ferguson博弈_组合博弈游戏
  7. 《易中天中华史 - 第二卷 国家》读书笔记
  8. html 中二维数组创建,【百度】js基础任务2-二维数组,dom操作
  9. eve模拟器上虚拟服务器,没有真机怎么做实验?EVE模拟器了解一下
  10. 练习STM32动态更改PWM波频率和占空比