`
haliluya4
  • 浏览: 123446 次
  • 性别: Icon_minigender_1
  • 来自: 福州
社区版块
存档分类
最新评论

Android Dimension转换算法原理分析

阅读更多

最近在做深度主题,要实现类似小米那种在主题包中设置dimension值,然后在系统中替换原值的功能。

特地研究了一下Android系统中dimension类型的值的存储方式以及相关的转换算法。

 

Android中,我们可以在values文件夹中定义各种资源,其中有一种就是dimension

dimension是一个包含单位(dpdipspptpxmmin)的尺寸,可以用于定义视图的宽度、字号等。如下图所示。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="textview_height">25dp</dimen>
    <dimen name="textview_width">150dp</dimen>
    <dimen name="ball_radius">30dp</dimen>
    <dimen name="font_size">16sp</dimen>
</resources>
<TextView
    android:layout_height="@dimen/textview_height"
    android:layout_width="@dimen/textview_width"
    android:textSize="@dimen/font_size"/>

而在代码中,我们可以通过getDimension方法获取到资源文件中定义的dimension值。

Resources res = getResources();
float fontSize = res.getDimension(R.dimen.font_size);

从上图可以发现,不论之前在资源文件中定义的dimension是什么单位,在代码中均转换成了float类型的数值。

但两个dimension值,如果数值部分相同,但单位不同,显然转换后的float值应该不同。

为了证明以上结论,我做了一个实验。

首先,定义一组dimension,数值部分相同,单位不同。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="tdp">10dp</dimen>
    <dimen name="tdip">10dip</dimen>
    <dimen name="tsp">10sp</dimen>
    <dimen name="tpt">10pt</dimen>
    <dimen name="tpx">10px</dimen>
    <dimen name="tmm">10mm</dimen>
    <dimen name="tin">10in</dimen>
</resources>

然后,在代码中分别使用getDimensiongetValue方法获取这些dimension的值。

Resources r = getResources();
TypedValue tv = new TypedValue();
r.getValue(R.dimen.tdp, tv, true);
System.out.println("10dp="+r.getDimension(R.dimen.tdp)+" data="+Integer.toBinaryString(tv.data));
r.getValue(R.dimen.tdip, tv, true);
System.out.println("10dip="+r.getDimension(R.dimen.tdip)+" data="+Integer.toBinaryString(tv.data));
r.getValue(R.dimen.tsp, tv, true);
System.out.println("10sp="+r.getDimension(R.dimen.tsp)+" data="+Integer.toBinaryString(tv.data));
r.getValue(R.dimen.tpt, tv, true);
System.out.println("10pt="+r.getDimension(R.dimen.tpt)+" data="+Integer.toBinaryString(tv.data));
r.getValue(R.dimen.tpx, tv, true);
System.out.println("10px="+r.getDimension(R.dimen.tpx)+" data="+Integer.toBinaryString(tv.data));
r.getValue(R.dimen.tmm, tv, true);
System.out.println("10mm="+r.getDimension(R.dimen.tmm)+" data="+Integer.toBinaryString(tv.data));
r.getValue(R.dimen.tin, tv, true);
System.out.println("10in="+r.getDimension(R.dimen.tin)+" data="+Integer.toBinaryString(tv.data));

最后,可以从下图看到输出的结果。

从上图可以看出,不同单位情况下,即使数值相同,转换成的float值也是千差万别。

但从后面的data值中,我们却发现,对于不同的单位,其最高位大部分是相同的,仅仅是后面几位有所区别。我们可以大胆地猜想:“dimension在系统中是以数值+单位的形式存储的。”

分析了AndroidResoureces类的getDimension方法的源码后我们发现,对于不同的dimension,在使用getValue获取到对应的int值之后,会通过TypedValuecomplexToDimension方法将其转换为float
complexToDimension方法主要是调用applyDimension方法,将getValue获取到的int值,拆成单位和数值两部分,然后根据单位的不同,对数值进行处理。
其中, (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK的作用是将该int值与上0xf,以获取其最低4位,4位是单位。而complexToFloat则是使用该int值的最高24位当作数值,4-7位作为radix,进行计算,转成float

最后,在applyDimension中根据单位的不同,将float乘上不同的系数。如dip/dp需乘上屏幕系数,sp需乘上字号的缩放系数,ptinmm等也是根据相应的算法进行换算。(从COMPLEX_UNIT_PX直接返回float可以看出,该方法是将数值转成像素数

至此,我们之前的猜想大致上是正确的,只是需要加上一个radix部分。即“dimension在系统中是以数值+4radix+4位单位的形式存储的”。

因此,为了实现将形如“10dip”的dimension转成getValue返回的int值,我们需要进行以下处理(参考com.androi.layoutlib.bridge.impl.ResourceHelperparseFloatAttribute方法)。

首先,将dimension字符串拆成数值与单位两部分,并将数值转成浮点数。

从上文可以知道,dimension的数值部分在实际存储时,系统只提供了24位存储空间。再考虑到一个dimension是有符号的,可正可负。故最高位表示正负。因此,真正的数值只有23位进行存储。

所以,接下来,对于负数要先转成对应的正数,并乘上2230.5(四舍五入)后转成long。(即仅保留整数和小数部分各23位)

接着,对转换后的long值进行判断。

若最低23位为0,即小数部分为0,标记radixTypedValue.COMPLEX_RADIX_23p0shift23,即只保留整数部分。

若最高41位为0,即整数部分为0javalong8个字节存储),标记radixTypedValue.COMPLEX_RADIX_0p23shift0,即只保留小数部分。

若最高330,即整数部分最多只有8位有效,标记radixTypedValue.COMPLEX_RADIX_8p15shift8,即只保留整数部分8位,小数部分15位。

若最高25位为0,即整数部分最多只有16位有效,标记radixTypedValue.COMPLEX_RADIX_16p7shift16,即只保留整数部分16位,小数部分7位。

若以上都不符合,说明小数部分不为0,整数有效部分超过16位,则标记radixTypedValue.COMPLEX_RADIX_23p0shift23,即只保留整数部分。

然后,根据shift将转换后的long值进行右移,取最低24位,转为int。若原值为负数,将右移的数转成负数后再取最低24位。

最后,将最终数值左移8位,最低4-7位或上radix0-3位或上单位。


上图给出了123113.51213dp的处理流程,按照算法,该dimension值会被转换成31516929存储在系统中。为了验证算法的正确性,笔者做了以下实验。

首先,在资源文件中添加一个值为123113.51213dpdimension

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="tdp">123113.51213dp</dimen>
</resources>

 然后,在代码中获取该值。

Resources r = getResources();
TypedValue tv = new TypedValue();
r.getValue(R.dimen.tdp, tv, true);
System.out.println("123113.51213dp="+r.getDimension(R.dimen.tdp)+" data="+(tv.data));

 最后,查看输出结果,完全符合!

至此,dimension的处理算法分析完毕。

  • 大小: 2.9 KB
  • 大小: 9 KB
  • 大小: 4.4 KB
  • 大小: 5.5 KB
  • 大小: 10.5 KB
  • 大小: 29.7 KB
  • 大小: 1.3 KB
分享到:
评论
4 楼 hety163 2014-12-20  
niubility~
3 楼 Tyler3419 2014-11-26  
你好,大神,能不能封装出一个方法,输入一个string的dimen字符,得到data呢?
最近也在做资源重定向,修改系统层东西,图片和颜色都弄好了,发现dimen文件最麻烦了。
2 楼 snowdream 2014-11-03  
分析很透彻,谢谢分享。
1 楼 xiangxm 2013-12-22  
牛人啊    

相关推荐

    优化算法——粒子群算法(PSO)原理及MATLAB代码

    ### 优化算法——粒子群算法(PSO)原理及MATLAB代码 #### 一、粒子群算法概述 粒子群算法(Particle Swarm Optimization, PSO)是一种基于群智能的优化技术,最初由Kennedy和Eberhart于1995年提出。它受到自然界中...

    数据库行列转换算法

    【数据库行列转换算法】 在数据库处理中,行列转换是一种常见的数据操作,特别是在数据分析和报表生成时。Oracle数据库提供了多种方法来实现这种转换,本篇将详细介绍如何在Oracle中进行行列转换,包括列转行、行转...

    Dimension

    "Dimension" 在IT行业中通常指的是维度,特别是在数据分析、数据库管理和数据仓库领域。维度是描述业务实体特性的属性或特征,例如在销售数据中,产品维度可能包括产品ID、产品名称、类别、品牌等。这些维度提供了...

    Line Item Dimension

    "Line Item Dimension"是一个在数据仓库和商业智能领域中常见的概念,主要涉及到多维数据分析(OLAP)和维度建模。这篇博客文章可能是对这一概念的深入解析,但原文链接无法直接访问,所以我们将根据常见知识来解释...

    Distance Preserving Dimension Reduction for Manifold Learning

    根据给定的文件信息,本篇文章主要探讨了在流形学习中,如何利用距离保持降维(Distance Preserving Dimension Reduction, DPDR)算法来降低高维数据处理的计算复杂性。下面将详细介绍文章中提到的相关知识点。 ### ...

    Dimension Reduction:A Guided Tour

    - **多维尺度分析 (MDS)**:MDS是一种将距离矩阵转换为低维空间中点的位置的方法,以便保持数据点之间的相对距离。 - **地标MDS**:这种方法是MDS的一种变体,通过仅使用选定的数据点(称为“地标”)来加速计算过程...

    分形维度指数(Fractal Dimension Index) - MetaTrader 5脚本.zip

    分形维度指数(Fractal Dimension Index,简称FDI)是一种技术分析工具,它源自于分形几何学原理,用于衡量金融市场中的价格波动性。在MetaTrader 5交易平台中,FDI脚本被用来帮助交易者识别市场的趋势变化和潜在的...

    DELL DIMENSION 2400说明书

    DELL DIMENSION 2400是一款由Dell公司生产的个人电脑,属于Dell Dimension系列。该电脑主要面向普通消费者及小型企业用户,具备一定的可扩展性,以及较为丰富的连接接口。从提供的文件内容来看,该说明书涉及了DELL ...

    Android代码-Android流式标签布局

    A FlowLayout for Android, which allows child views flow to next row when there is no enough space. The spacing between child views can be calculated by the FlowLayout so that the views are evenly ...

    oracle行列转换总结

    在Oracle数据库中,行列转换是一项常用且强大的功能,它允许数据在不同的维度上进行转换,以便于数据分析和报告。本文将深入探讨Oracle中实现行列转换的几种方法,包括使用`UNION ALL`、`MODEL`子句以及集合类型(`...

    Android编程入门很简单.(清华出版.王勇).part1

    书名:《Android编程入门很简单》(清华大学出版社.王勇)。 压缩打包成2部分,这是第1部分。 本书是一本与众不同的Android学习读物,是一本化繁为简,把抽象问题具体化,把复杂问题简单化的书。本书避免出现...

    correlation-dimension(GP-method).rar_GP关联维数_GP算法关联维_lorenz dimen

    在IT领域,特别是数据分析和复杂系统研究中,关联维数(Correlation Dimension)是一个重要的概念,用于描述系统的混沌性质和复杂度。标题中的"correlation-dimension(GP-method)"指的是利用Gibbs-Pearson(GP)方法...

    Two Dimension Signal and image processing Part1

    Two Dimension Signal and image processing MIT Textbook 麻省理工教材

    Android简单实现自定义控件

    通过这个过程,我们可以深入理解Android UI组件的工作原理以及如何扩展它们。 首先,我们需要创建一个新的Java类,继承自`LinearLayout`。在Android Studio中,可以右键点击项目中的`java`目录,选择"New" -&gt; "Java...

    Three_dimensiona_ThreadConnection_YAN.

    标题中的"Three_dimensiona_ThreadConnection_YAN."似乎指的是一个关于三维螺纹连接的特定研究或技术,而描述中提到的"Three dimensional ThreadConnection,基于ANSYS分析得出的三维分析"进一步证实了这是一个利用...

    Android AutoLayout全新的适配库

    Android AutoLayout是一个强大的适配库,专为解决Android平台上的屏幕适配问题而设计。在Android生态系统中,设备种类繁多,屏幕尺寸和分辨率各异,这给开发者带来了不小的挑战。AutoLayout通过提供一种灵活的布局...

    android 重写控件添加自定义属性

    首先,我们要理解Android控件重写的基本原理。Android控件是基于Java语言的,我们可以通过继承已有的View或ViewGroup类来创建新的自定义控件。例如,如果要重写Button,我们可以这样做: ```java public class ...

    java.awt.Dimension 制作指定图片

    综上所述,这篇博客可能详细讲解了如何在Java中使用Dimension类来定制图片的显示尺寸,涉及到源码分析、GUI布局管理和可能与JMagick这样的图像处理库的集成。学习这些内容对于进行Java GUI编程和图像处理的开发者来...

Global site tag (gtag.js) - Google Analytics