文档章节

android 尺寸和适配

神手-追魂
 神手-追魂
发布于 2017/07/14 14:39
字数 2931
阅读 37
收藏 0
点赞 0
评论 0

写过多少布局,做过多少适配。我认真着,你的不知所措。这种迷茫心情 我想谁都会有,幸运的是能分担你的愁。我tm居然唱出来了。你敢信?

没错,今天鸡排君从头讲设备尺寸和适配这点事情。也许当时跑得太急,没好好回头欣赏它的美。学习的时候只看到了怎么用,却没有思考这些是怎么出现的。现在握紧我的手,带你一步一步推导这些看上去很基础,却有时模模糊糊的东西。(比如自定义View里的单位如何适配?)

本篇你能收获什么?

  • 如标题一样,彻底搞清楚android上的适配由来而不是背了概念

  • 还有抓住一直大鸡排。

目录

  • 什么是屏幕尺寸

  • 一寸到底是多少?

  • DPI每英寸点数

  • 独立的像素密度是什么?

  • 屏幕相关的api

注:这里的推导是自己的理解,非官方的解释

什么是屏幕尺寸?

我们来看下面这幅图,屏幕对角线的长度。(即:设备的左上角至右边下角那条线)

注意:我们需要知道对角线的长度怎么算的,其实很简单,利用勾股定律即可。

根号下720平方+1280平方等于设备对角线像素。

√720*720+1280*1280
=√518400+1638400
=√2156800
≈1468.6047800(px)

另一个疑惑就出现了,我们平时描述的4.3寸、5寸是指屏幕的什么。
这里的寸是指什么鬼?
为什么我们算出了是1468这么大?
黑人问号脸??why

一寸到底是多少?

那哦跟浓港啊,介锅一寸 巴拉巴拉啦.....
停 打住,我听不懂那些。

那好吧,我们现在手上这台设备是720*1280,我们前面计算过它的屏幕对角尺寸约等于1468个像素密度。注意这里说的是屏幕对角尺寸不是屏幕尺寸。商家描述说这台碉堡的手机是4.5寸的。既然这里的尺寸就是指对角线。我们反向推算。

1468/4.5
≈326.2222

这里得到326.222就是我们这台设备的一寸所占的像素点。

DPI每英寸点数

我们首先知道,谷歌官方把android设备的参考标准定义为一寸是160px 
这里会get一个概念叫dpi(dpi:dots per inch )。即每寸的像素有多少个点。面试的时候经常有同学把dpi、dip、dp弄混了。下面我接着推。

现在要说一下独立的像素密度了。独立的像素密度??听着就好绕口,俺有一句mmp,不知道当讲不当讲,这又是蛇?

独立像素密度DIP/DP

好,既然谷歌的一寸是160px,为什么我们是刚刚算出来的是320px?(为了方便计算,省去那6个像素点,别跟我纠结了)

嗯,这个问题问得好!

因为android设备中160px每寸的密度无法满足用户的钛合金眼,甚至觉得颗粒感爆炸好喵?
所以厂商将 原本160个像素中又插入一波160像素。就变成 了320像素。如下图所示。(真实的屏幕生产不是这样插像素的,这里只是便于理解。)


一开始只有红色的像素点,后面插入了一些像素进来。在同样的空间下密度增大了一倍。所以320像素得到了解释。

由此我们又得到一个概念叫密度。(density)

320/160
=2

这里的密度就是2了,所以我们开发中写1dp在720*1280的设备上会变成2px。有兴趣的小伙伴可以写一个自定义View把1dp设置成宽度,然后在View里打印一下1dp的宽度得到的是不是2px。同理在其他分辨率上也是一样的算法。
如:240/160=1.5(倍密度)

实际情况下,你现在的设备如果密度是2.0,那么你布局时1dp将转换成2px在设备上呈现。
到这里我们总算是明白了,什么是独立像素密度。即:dp转换成px代表几个像素。业界把它叫做 Density independent pixels 简称dip,直译过来的意思是独立的像素密度。

用我自己的话来讲,*dp是运行在物理设备之前用来描述控件大小的一种描述单位,其中我们开发中用的单位dp就是dip一个意思。而dpi是指每寸像素密度。不要再弄混了喔。喔喔喔!!!

现在回过头来看下面的概念,是不是清晰多了?

  • dip: Density independent pixels ,设备无关像素。

  • dp :就是dip(以后别纠结dip和dp的区别了好么)

  • px : 像素

  • dpi :dots per inch ,一英寸多少个像素点。素密度

  • density : 密度

  • 分辨率 : 横纵2个方向的像素点的数量

  • 屏幕尺寸: 屏幕对角线的长度

屏幕相关的api

  DisplayMetrics metric =Resources.getSystem().getDisplayMetrics();
        int DMwidth = metric.widthPixels;  // 屏幕宽度(px)
        int DMheight = metric.heightPixels;  // 屏幕高度(px)
        float DMdensity = metric.density;  // 屏幕密度(/ 1.0 / 1.5/ 2.0)
        int DMdensityDpi = metric.densityDpi;  // 屏幕密度DPI(160 / 240/ 320)
  Log.e("metric","屏幕宽度="+DMwidth+" 屏幕高度="+DMheight+" 屏幕密度="+DMdensity+" 屏幕密度DPI"+DMdensityDpi);
      

在自定义View上做适配,多数情况下可以根据权重和获取整个控件的宽高然后根据百分比去设置某个特殊的属性需要用到的值。but,这些都太常见了。也不是一个我们今天要讲的重点。

不知道大家有没有纠结一个问题,在自定义View里,经常要定义Paint用来绘制。但是setStrokeWidth(float width)里的入参接受的到底是以pxdp? 哪个为单位。这里有本质上的区别。比如你写了一个控件,自己的开发机器没问题,结果换一个设备就尺寸就不准了。

我先卖个关子,不告诉你答案╭(╯^╰)╮。为此我们用官方TextVIew源码和TypedArray源码作为分析。

这是一条温柔的提示:来么,宝贝儿!打开我们的AndroidStudio快速轻击Shift两下,然后输入TextView,我们一起看流星吧。(里面真的有很多小星星都是注释)

目录

  • TextView中的textSize源码分析

  • TypedArray源码分析

TextView中的textSize源码分析

textSize默认大小

我们可以看到默认情况下,TextViewtextSize是15。

重绘方法

而后我发现了这样一个方法,用于重新设置FontSize,这里逻辑很清晰,判断Paint的Size和刚刚重设是否一致,一致就重设Paint的参数,并重新绘制View。

最后调用的是Native方法,java层已经看不到了。

setTextSize发现TypedValue

不过这些不是重点,我们还发现了另外一个方法。TextVIew设置字体有重载方法。我们重点去看两个参数的。

这里说明了Size的单位大小是由unit来决定的,最后它调用了SetRawTextSize方法,而这个方法我们前面分析了是用来重绘的。我们来看Unit是个什么值。

通过TypedValue类发现实际所有的单位都是定义在这里的。而我们的setTextSize需要的单位也在这里。

TypedValue.applyDimension

重头戏来了,如果我们用了两个参数构造方法进行设置字体大小,那么。
TypedValue.applyDimension( unit, size, r.getDisplayMetrics())做了什
么,他是如何转换单位的。我跟进去看。

我们来看最典型的一条case语句 case COMPLEX_UNIT_DIP: return value * metrics.density;
这里的density就是我们上个章节里讲到的密度,也就是说如果你用dp作为单位,他就已当前的size乘以密度返回。
好家伙,恍然大悟把?实际上这里把你传入的任意单位最后都转换成了像素来处理的,最后设置给了Paint

那么这里就说明了一个问题,Paint对象接受的参数最后都是px像素来使用的,不要漏掉了这一点喔。

这里我推荐直接使用TypedValue.applyDimension()来处理。这是android已经具备的Api,不需要自己再从零写了。可能有小伙伴用过类似dp2Px()这种类库。我个人不是很推荐往项目里堆叠繁杂的库进来,一来是会变得越来越臃肿,而是如果单纯的依赖不方便去修改源码,出了问题,你要么选择copy出代码出来进行修改,要么反射一下。但这都不是很优雅。尽可能使用系统已有的。

参考代码:

 TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, Resources.getSystem().getDisplayMetrics());

TypedArray源码分析

什么是TypedArray

如果有常写自定义View属性的小伙伴一定对TypedArray不陌生,我们常用来在Java文件中取自定义View上的属性。这些属性可以是布尔、dp、整型、字符串甚至是一个布局文件的id等。

现在我们思考一个问题,平时在一个控件里描述一个长度用了dp为单位,他是如何适配在不同设备上的?

带着这个疑惑,我们来看源码如何解析的。首先我们不管是原生控件也好,还是自定义控件也好,我们都需要在构造方法中去取出XML布局文件中的属性。

获取TypedArray

这里获取TypedArray对象,其中R.styleable.xxx是该控件拥有的属性。

TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.xxx);  

接着我们来看一眼TypedArray都有那些方法。

TypedArray的使用

实际上,我们的控件从XML中去解析就是通过该TypedArray的API来操作的。见TextView获取textSize源码如下。


我们来看一眼,getDimensionPixelSize方法内部的逻辑。

注意关键的一行`TypedValue.complexToDimensionPixelSize(

            data[index+AssetManager.STYLE_DATA], mMetrics);`, 我们跟进去看。


是不是似曾相识?熟悉吧,没错,该方法最终还是调用了TypedValue.applyDimension()进行了单位换算。我们上一章节讲过这个。我就不再展开里面的逻辑了。到这里真相大白。实际上在xml写的dp、pt、px等,最终都要来这里一趟,将其转换为px。再画出来。所以又一次证明了,我们的画图操作都是基于px为单位的。

流程总结

  • 1.xml定义一个属性

  • 2.在构造方法里用TypedArray来get这个属性。

  • 3.调用getDimensionPixelSize()方法获取该属性上的具体值,并转换单位为像素。

  • 4.绘制出来

我们发现它并不复杂,但很多时候往往是没有去阅读过源码,在工作中不能流畅的解决这些问题。
有小伙伴反应说他的自定义View通过java代码设置尺寸就是不能适配,但是通过属性就可以。这里其实就是忘记调用TypedValue.applyDimension( unit, size, r.getDisplayMetrics())方法。
再比如面试过程中再有面试官问如何做适配的时候,你就不会再是背诵面试题上的答案了吧?

题外话,我反对那些面试宝典类的东西,不是说这些知识的对错性,而是很多新人在学习的过程中往往是囫囵吞枣,出发的目的如果是为了面试通过背诵这些东西,而不理解其中的概念,甚至想都没有想过为什么是这样。这样的结果绝对不是面试官想看到的。也不是我们应该做的。我们慢一点不要紧,多花点时间,不能途一时之快,那些偷过的懒,都是要还的。

本文转载自:http://www.apkbus.com/blog-889706-68242.html,http://www.apkbus.com/blog-889706-68239.html

共有 人打赏支持
神手-追魂
粉丝 0
博文 27
码字总数 2357
作品 0
苏州
高级程序员
0-2岁的app开发人员必读,Android开发APP前的准备事项

随着移动互联网的兴起,各行各业对移动应用的需求越来越大,从事APP开发的人也越来越多,APP开发行业可以说是方兴未艾。APP开发是比较复杂的事情,涉及产品、美工设计、服务器端开发、Andro...

传授知识的天使 ⋅ 06/06 ⋅ 0

Android初级第九讲之适配和调试

本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! Android适配需要考虑方方面面,主要是图片字体大小和API,但也要考虑其他场景下的一些问题。 先熟悉一下Android设备的dpi...

liuzxgeek ⋅ 2016/12/14 ⋅ 0

号外!号外!全网第一手Android P刘海屏适配大揭秘,唯一Kotlin算法

1. 背景   Apple一直在引领设计的潮流,自从iPhone X发布之后,刘海屏就一直存在争议。不过不管你怎样,Android也要跻入“刘海屏“的行列,Android P预览版增加了很多亮点新特性,其中最接...

keyu88888 ⋅ 05/04 ⋅ 0

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

一、现状 由于Android碎片化严重,屏幕适配一直是开发中较为头疼的问题。面对市面上五花八门的屏幕大小与分辨率,Android基于dp与res目录名称来适配的方案已无法满足一次编写全屏幕适配的需求...

一个敲代码的前端妹子 ⋅ 05/10 ⋅ 0

Android机型尺寸适配入门

学习自 https://zhuanlan.zhihu.com/p/37199709 机型适配目前暂时我认为分两块:1.尺寸2.代码(不同系统引发的莫名其妙的crash) 本文简单介绍尺寸 dp、px的换算 dp*dpi/160=px(dpi/160也就...

qq_36523667 ⋅ 05/24 ⋅ 0

华为云测平台服务再升级!华为M5系列平板调测能力正式上线!

6月1日,华为M5系列平板设备兼容性测试和远程真机调试功能在华为终端开放实验室正式上线!助力您的产品在大屏适配上快人一步! 华为终端开放实验室DevEco平台现已提供基于华为M5系列平板设备...

华为终端开放实验室 ⋅ 06/08 ⋅ 0

一大波 Android 刘海屏来袭,全网\Maybe/最全适配技巧!

一、序 Hi,大家好,我是承香墨影! Apple 一直在引领设计的潮流,自从 iPhone X 发布之后,"刘海屏" 就一直存在争议。不过不管你怎样,Android 也要跻入 "刘海屏" 的行列,尤其是 Android ...

承香墨影 ⋅ 04/12 ⋅ 0

Android app 在线更新那点事儿(适配Android6.0、7.0、8.0)

一、前言 app在线更新是一个比较常见需求,新版本发布时,用户进入我们的app,就会弹出更新提示框,第一时间更新新版本app。在线更新分为以下几个步骤: 在线更新就上面几个步骤,前2步比较简...

codeGoogle ⋅ 04/28 ⋅ 0

android开发常用工具类、高仿客户端、附近厕所、验证码助手、相机图片处理等源码

Android精选源码 android开发过程经常要用的工具类源码(http://www.apkbus.com/thread-599826-1-1.html) Android类似QQ空间个人主页下拉头部放大的布局效果(http://www.apkbus.com/thread-5...

逆鳞龙 ⋅ 05/29 ⋅ 0

Android 性能优化:手把手教你优化Bitmap图片资源的使用

前言 在 开发中,性能优化策略十分重要 本文主要讲解性能优化中的Bitmap 使用优化,希望你们会喜欢 目录 1. 优化原因 即 为什么要优化图片资源,具体如下图:

Carson_Ho ⋅ 04/24 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

JDK1.6和JDK1.7中,Collections.sort的区别,

背景 最近,项目正在集成测试阶段,项目在服务器上运行了一段时间,点击表格的列进行排序的时候,有的列排序正常,有的列在排序的时候,在后台会抛出如下异常,查询到不到数据,而且在另外一...

tsmyk0715 ⋅ 26分钟前 ⋅ 0

spring RESTful

spring RESTful官方文档:http://spring.io/guides/gs/rest-service/ 1. 可以这么去理解RESTful:其实就是web对外提供的一种基于URL、URI的资源供给服务。不是一个原理性知识点。是一个方法论...

BobwithB ⋅ 28分钟前 ⋅ 0

C++ 中命名空间的 5 个常见用法

相信小伙伴们对C++已经非常熟悉,但是对命名空间经常使用到的地方还不是很明白,这篇文章就针对命名空间这一块做了一个叙述。 命名空间在1995年被引入到 c++ 标准中,通常是这样定义的: 命名...

柳猫 ⋅ 31分钟前 ⋅ 0

@Conditional派生注解

@Conditional派生注解(Spring注解版原生的@Conditional作用) 作用:必须是@Conditional指定的条件成立,才给容器中添加组件,配置配里面的所有内容才生效; @Conditional扩展注解 作用(判...

小致dad ⋅ 31分钟前 ⋅ 0

适配器模式

适配器模式 对象适配器 通过私有属性来实现的类适配器 通过继承来实现的接口适配器 通过继承一个默认实现的类实现的

Cobbage ⋅ 35分钟前 ⋅ 0

Java 限流策略

概要 在大数据量高并发访问时,经常会出现服务或接口面对暴涨的请求而不可用的情况,甚至引发连锁反映导致整个系统崩溃。此时你需要使用的技术手段之一就是限流,当请求达到一定的并发数或速...

轨迹_ ⋅ 39分钟前 ⋅ 0

GridView和子View之间的间隙

默认的情况下GridView和子View之间会有一个间隙,原因是GridView为了在子View被选中时在子View周围显示一个框。去掉的办法如下: android:listSelector="#0000" 或 setSelector(new ColorDra...

国仔饼 ⋅ 42分钟前 ⋅ 0

idea插件开发

1 刷新页面要使用多线程 2 调试要使用restart bug 不要去关闭调试的idea 否则再次启动会卡住

林伟琨 ⋅ 42分钟前 ⋅ 0

Java 内存模型

物理机并发处理方案 绝大多数计算任务,并不是单纯依赖 cpu 的计算完成,不可避免需要与内存交互,获取数据。内存要拿到数据,需要和硬盘发生 I/O 操作。计算机存储设备与 cpu 之间的处理速度...

长安一梦 ⋅ 49分钟前 ⋅ 0

思路分析 如何通过反射 给 bean entity 对象 的List 集合属性赋值?

其实 这块 大家 去 看 springmvc 源码 肯定可以找到实现办法。 因为 spirngmvc 的方法 是可以 为 对象 参数里面的 list 属性赋值的。 我也没有看 具体的 mvc 源码实现,我这里只是 写一个 简...

之渊 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部