TypedValue 和 TypedArray
来源:互联网 发布:淘宝二姐家是正品吗 编辑:程序博客网 时间:2024/06/06 20:25
获取自定义属性值常会使用TypedValue 和 TypedArray 类
TypedValue
- applyDimension ( return float )
- complexToDimension (return float)
TypedArray
- getDimension (return float)
下面从一个小例子逐步的解释这几个方法
在自定义View构造体中获取属性经常会这样写:
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MiUiClockView); int n = typedArray.getIndexCount(); int defaultSize = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics());//默认Paint textSize for (int i = 0; i < n; i++) { int attr = typedArray.getIndex(i); switch (attr) { case R.styleable.MiUiClockView_highColor: mHighColor = typedArray.getColor(attr, Color.WHITE); break; case R.styleable.MiUiClockView_textSize: textSize = typedArray.getDimension(attr,defaultSize); Log.e(TAG,textSize+""); break; } } typedArray.recycle(); Paint paint = new Paint(); paint.setTextSize(textSize);
xml 定义如下:
<com.example.javris.paintdemo.MiUiClockView android:layout_width="match_parent" android:layout_height="match_parent" app:highColor="#ffffff" app:textSize="12sp"/>
attrs.xml中属性定义如下:
<declare-styleable name="MiUiClockView"> <attr name="highColor" format="color"/> <attr name="textSize" format="dimension"/> <attr name="intSize" format="integer"/> </declare-styleable>
这是自定义View获取属性的老套路了。首先Paint 设置textSize的大小单位是sp,这个大家是知道的,从上面代码得知:获取paint 所需要的textSize有两种方案:
TypedArray — getDimension(int index, float defValue)
TypedValue — applyDimension(int unit, float value,DisplayMetrics metrics)
TypeValue applyDimension()
首先看一下TextView setTextSize()方法源码
public void setTextSize(float size) { setTextSize(TypedValue.COMPLEX_UNIT_SP, size); } public void setTextSize(int unit, float size) { Context c = getContext(); Resources r; if (c == null) r = Resources.getSystem(); else r = c.getResources(); setRawTextSize(TypedValue.applyDimension( unit, size, r.getDisplayMetrics())); } private void setRawTextSize(float size) { if (size != mTextPaint.getTextSize()) { mTextPaint.setTextSize(size); if (mLayout != null) { nullLayouts(); requestLayout(); invalidate(); } } }TypeValue类 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; }
其中textView 的单位为sp所以单位参数为COMPLEX_UNIT_SP,通过调用setRawTextSize方法给Paint设置textSize,而paint所需的textSize值单位位px,正是通过TypeValue 的 applyDimension()方法进行转换的,从Switch case 语句中可以很容易看出 sp 转px dp 转 px 。
那么现在做出如下总结:
TypeValue的applyDimension方法其作用就是通过传递不同的单位和数值,最终转换成为像素值.
TypedArray getDimension()
public float getDimension(@StyleableRes int index, float defValue) { ... //省略部分代码 final int attrIndex = index; index *= AssetManager.STYLE_NUM_ENTRIES; final int[] data = mData; final int type = data[index+AssetManager.STYLE_TYPE]; if (type == TypedValue.TYPE_NULL) { return defValue; } else if (type == TypedValue.TYPE_DIMENSION) { return TypedValue.complexToDimension( data[index + AssetManager.STYLE_DATA], mMetrics); } ... }
代码比较长省去一些,可以看到调用了TypedValue的complexToDimension(),看一下这个方法的源码
TypeValue 类 public static final int COMPLEX_UNIT_SHIFT = 0; public static final int COMPLEX_UNIT_MASK = 0xf; public static float complexToDimension(int data, DisplayMetrics metrics) { return applyDimension( (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK, complexToFloat(data), metrics); }
可以看到又调用到了applyDimension()方法,第一个参数为单位, 那么(data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK 运算的目的就是为了让data 0-3位和0xf (二级制 1111)进行与运算,所以Data的低四位存储的是单位。
第二个参数则是通过complexToFloat()方法。
public static final int COMPLEX_MANTISSA_MASK = 0xffffff; public static final int COMPLEX_MANTISSA_SHIFT = 8; private static final float[] RADIX_MULTS = new float[] { 1.0f*MANTISSA_MULT, 1.0f/(1<<7)*MANTISSA_MULT, 1.0f/(1<<15)*MANTISSA_MULT, 1.0f/(1<<23)*MANTISSA_MULT }; public static final int COMPLEX_RADIX_SHIFT = 4; public static final int COMPLEX_RADIX_MASK = 0x3;public static float complexToFloat(int data) { return (data&(TypedValue.COMPLEX_MANTISSA_MASK <<TypedValue.COMPLEX_MANTISSA_SHIFT)) * RADIX_MULTS[(data>>TypedValue.COMPLEX_RADIX_SHIFT) & TypedValue.COMPLEX_RADIX_MASK]; }
0xffffff 转成2进制 1111 1111 1111 1111 1111 1111 左边移动8位 则为1111 1111 1111 1111 1111 1111 0000 0000 这就是一个32位的整形,data& (…)实际上也就想得到高24位的值,在看RADIX_MULTS[….] data>> 4 向右移动4位,还记得上面complexToDimension 方法中data 低四位(0-3位)是为了求换算单位,所以data 要先右移4位然后在和0x3 (二进制 0011)作与运算,这样实际上获取data 4-7位数值,并且最大数值超不过3,这样就能在RADIX_MULTS数组中选择一个数值了,这样来看实际上data 数据的低4位存储着数值的单位而高24则存储着数值。最终通过TypeValue的applyDimension 依旧可以得到px.
那么现在做出如下总结:
TypeArray 的getDimension()方法实际上则是通过调用TypeValue的complexToDimension()方法实现的,complexToDimension中传递的data 数据 0-3存储着转换单位,4-7位为了获取一个radix ,高24位则存储着数值。
其实像这种形式的存储数据方式在Android 中并不少见,比例MeasureSpec 同样是一个int 类型,它的高2位存储的是Mode,低30位存储的是Size.目的为的就是减少内存的分配。对MeasureSpec不理解可参考博客
http://blog.csdn.net/wning1/article/details/64137354
ok,到这TypeValue 和 TypeArray 就算讲完了,你可能会有疑问TypeValue中complexToDimen中传递的data为什么低4位就存储着单位,高24位存储着数值呢?实际上这是系统在解析自定义xml布局的时候如: app:textSize=”12sp”时就会将数值12和单位sp利用位运算存储到data中了,在这就不再看android中的源码。
- TypedValue 和 TypedArray
- ?attr/selectableItemBackground的使用(TypedArray,TypedValue)
- TypedArray和obtainStyledAttributes使用
- TypedArray和obtainStyledAttributes使用
- TypedArray和obtainStyledAttributes使用
- TypedArray和obtainStyledAttributes使用
- TypedArray和obtainStyledAttributes使用
- TypedArray和obtainStyledAttributes使用
- TypedArray和attrs.xml
- TypedArray和attrs.xml
- TypedArray和obtainStyledAttributes使用
- TypedArray和obtainStyledAttributes使用
- TypedArray和obtainStyledAttributes使用
- TypedArray和obtainStyledAttributes使用
- TypedArray和obtainStyledAttributes使用
- TypedArray和obtainStyledAttributes使用
- 初探TypedArray和AttributeSet
- TypedArray和obtainStyledAttributes使用
- Dom4j解析XML
- PHP:自动加载类
- Latex使用小结
- 2017尔雅中国历史人文地理答案 中国历史人文地理葛剑雄
- C++中的循环
- TypedValue 和 TypedArray
- linux学习路线
- slam相关文章
- seetaface配置 未出现dll文件和lib文件解决方法
- Mysql 安装出现问题的 解决办法
- 软删除与唯一索引冲突的解决方案
- the best description to SYS module in python
- 1 docker环境使用tensorflow以及jupyter notebook的使用
- Could not read from remote repository