View自定义属性步骤与分析
来源:互联网 发布:linux端口重定向 编辑:程序博客网 时间:2024/05/22 03:27
我们在自定义View的过程中,通常会让用户通过自定义属性值来控制View的显示效果。那么我们应该如何自定义属性和使用这些属性呢?
第一:我们需要在工程目录下res/values新建一个attr.xml文件,在该文件中定义我们自己的自定义的属性名称。
<?xml version="1.0" encoding="utf-8"?><resources> <declare-styleable name="myTextView"> <attr name="mColor" format="color"/> <attr name="mBoolean" format="boolean"/> <attr name="mDimension" format="dimension"/> <attr name="mFloat" format="float"/> <attr name="mInteger" format="integer"/> <attr name="mString" format="string"/> <attr name="mEnum" format="enum"/> <attr name="mFlag"> <flag name="one" value="1"/> <flag name="two" value="2"/> </attr> <attr name="mFraction" format="fraction"/> <attr name="mReference" format="reference"/> </declare-styleable></resources>
第二: 我们就可以在我们布局文件使用这些自定义属性了。
<com.lgy.typearray.MyTextView android:layout_width="match_parent" android:layout_height="match_parent" lgy:mColor="@color/material_blue_grey_900" lgy:mBoolean="true" lgy:mDimension="@dimen/abc_action_bar_progress_bar_size" android:text="Hello World!" />
第三:我们此时就可以在我们自定义View的构造函数中获取我们在布局文件中设置的对应值。
public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setColor(Color.RED); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.myTextView); mPaint.setColor(typedArray.getColor(R.styleable.myTextView_mColor, Color.RED)); boolean mBoolean = typedArray.getBoolean(R.styleable.myTextView_mBoolean, false); Log.i(TAG, "mBoolean:" + mBoolean); float mDimension = typedArray.getDimension(R.styleable.myTextView_mDimension, 14f); Log.i(TAG, "mDimension:" + mDimension); int mDimensionSize = typedArray.getDimensionPixelSize(R.styleable.myTextView_mDimension, 14); Log.i(TAG, "mDimensionSize:" + mDimensionSize); int mDimensionPixelOffset = typedArray.getDimensionPixelOffset(R.styleable.myTextView_mDimension,14); Log.i(TAG, "mDimensionPixelOffset:" + mDimensionPixelOffset); typedArray.recycle();}
到此使用方法就介绍好了。
下面我想在介绍的就是我们在attr.xml中 format对应值。
1、color 代表颜色值。
在attr.xml中我们可以<attr name="mColor" format="color"/>
,
在我们布局文件中我们可以lgy:mColor="@color/mytextView"
,
颜色mytextView是我们在定义<color name="mytextView">#5896ae</color>
,
我们在代码中获取我们设置对应值
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.myTextView);
int mColor = typedArray.getColor(R.styleable.myTextView_mColor, Color.RED);
Log.i(TAG,"mColor:" + mColor);
typedArray.recycle();
运行代码结果图:
2、boolean代表真假true false
在attr.xml中我们可以<attr name="mBoolean" format="boolean"/>
,
在我们布局文件中我们可以lgy:mBoolean="true"
,
我们在代码中获取我们设置对应值
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.myTextView);
int mColor = typedArray.getColor(R.styleable.myTextView_mColor, Color.RED);
Log.i(TAG,"mColor:" + mColor);
boolean mBoolean = typedArray.getBoolean(R.styleable.myTextView_mBoolean, false);
Log.i(TAG, "mBoolean:" + mBoolean);
typedArray.recycle();
运行代码结果图:
3、float代表浮点数
在attr.xml中我们可以<attr name="mFloat" format="float"/>
,
在我们布局文件中我们可以lgy:mFloat="5"
,
我们在代码中获取我们设置对应值
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.myTextView);
int mColor = typedArray.getColor(R.styleable.myTextView_mColor, Color.RED);
Log.i(TAG,"mColor:" + mColor);
boolean mBoolean = typedArray.getBoolean(R.styleable.myTextView_mBoolean, false);
Log.i(TAG, "mBoolean:" + mBoolean);
float mFloat = typedArray.getFloat(R.styleable.myTextView_mFloat,0.0f);
Log.i(TAG,"mFloat:" + mFloat);
typedArray.recycle();
运行代码结果图:
4、integer 代表整形
在attr.xml中我们可以<attr name="mInteger" format="integer"/>
,
在我们布局文件中我们可以lgy:mInteger="16"
,
我们在代码中获取我们设置对应值
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.myTextView);
int mColor = typedArray.getColor(R.styleable.myTextView_mColor, Color.RED);
Log.i(TAG,"mColor:" + mColor);
boolean mBoolean = typedArray.getBoolean(R.styleable.myTextView_mBoolean, false);
Log.i(TAG, "mBoolean:" + mBoolean);
float mFloat = typedArray.getFloat(R.styleable.myTextView_mFloat,0.0f);
Log.i(TAG,"mFloat:" + mFloat);
int mInteger = typedArray.getInteger(R.styleable.myTextView_mInteger,1);
Log.i(TAG,"mInteger:" + mInteger);
int mInt = typedArray.getInt(R.styleable.myTextView_mInteger,2);
Log.i(TAG,"mInt:" + mInt);
typedArray.recycle();
运行代码结果图:
5、string 代表字符串
在attr.xml中我们可以<attr name="mString" format="string"/>
,
在我们布局文件中我们可以lgy:mString="自定义字符串"
,
我们在代码中获取我们设置对应值
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.myTextView);
int mColor = typedArray.getColor(R.styleable.myTextView_mColor, Color.RED);
Log.i(TAG,"mColor:" + mColor);
boolean mBoolean = typedArray.getBoolean(R.styleable.myTextView_mBoolean, false);
Log.i(TAG, "mBoolean:" + mBoolean);
float mFloat = typedArray.getFloat(R.styleable.myTextView_mFloat,0.0f);
Log.i(TAG,"mFloat:" + mFloat);
int mInteger = typedArray.getInteger(R.styleable.myTextView_mInteger,1);
Log.i(TAG,"mInteger:" + mInteger);
int mInt = typedArray.getInt(R.styleable.myTextView_mInteger,2);
Log.i(TAG,"mInt:" + mInt);
String mString = typedArray.getString(R.styleable.myTextView_mString);
Log.i(TAG,"mString:" + mString);
typedArray.recycle();
运行代码结果图:
6、enum 代表枚举类型
在attr.xml中我们可以:
<attr name="mEnum" format="enum">
<enum name="five" value="5"/>
<enum name="six" value="6"/>
<enum name="seven" value="7"/>
</attr>
在我们布局文件中我们可以lgy:mEnum="six"
,
我们在代码中获取我们设置对应值
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.myTextView);
int mColor = typedArray.getColor(R.styleable.myTextView_mColor, Color.RED);
Log.i(TAG,"mColor:" + mColor);
boolean mBoolean = typedArray.getBoolean(R.styleable.myTextView_mBoolean, false);
Log.i(TAG, "mBoolean:" + mBoolean);
float mFloat = typedArray.getFloat(R.styleable.myTextView_mFloat,0.0f);
Log.i(TAG,"mFloat:" + mFloat);
int mInteger = typedArray.getInteger(R.styleable.myTextView_mInteger,1);
Log.i(TAG,"mInteger:" + mInteger);
int mInt = typedArray.getInt(R.styleable.myTextView_mInteger,2);
Log.i(TAG,"mInt:" + mInt);
String mString = typedArray.getString(R.styleable.myTextView_mString);
Log.i(TAG,"mString:" + mString);
int mEnum = typedArray.getInteger(R.styleable.myTextView_mEnum,5);
Log.i(TAG,"mEnum:" + mEnum);
int mEnumInt = typedArray.getInt(R.styleable.myTextView_mEnum,7);
Log.i(TAG,"mEnumInt:" + mEnumInt);
typedArray.recycle();
运行代码结果图:
7、flag 代表自定义类型
在attr.xml中我们可以:
<attr name="mFlag">
<flag name="one" value="1"/>
<flag name="two" value="2"/>
</attr>
在我们布局文件中我们可以lgy:mFlag="two"
,
我们在代码中获取我们设置对应值
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.myTextView);
int mColor = typedArray.getColor(R.styleable.myTextView_mColor, Color.RED);
Log.i(TAG,"mColor:" + mColor);
boolean mBoolean = typedArray.getBoolean(R.styleable.myTextView_mBoolean, false);
Log.i(TAG, "mBoolean:" + mBoolean);
float mFloat = typedArray.getFloat(R.styleable.myTextView_mFloat,0.0f);
Log.i(TAG,"mFloat:" + mFloat);
int mInteger = typedArray.getInteger(R.styleable.myTextView_mInteger,1);
Log.i(TAG,"mInteger:" + mInteger);
int mInt = typedArray.getInt(R.styleable.myTextView_mInteger,2);
Log.i(TAG,"mInt:" + mInt);
String mString = typedArray.getString(R.styleable.myTextView_mString);
Log.i(TAG,"mString:" + mString);
int mEnum = typedArray.getInteger(R.styleable.myTextView_mEnum,5);
Log.i(TAG,"mEnum:" + mEnum);
int mEnumInt = typedArray.getInt(R.styleable.myTextView_mEnum,7);
Log.i(TAG,"mEnumInt:" + mEnumInt);
int mFlag = typedArray.getInteger(R.styleable.myTextView_mFlag,1);
Log.i(TAG,"mFlag:" + mFlag);
int mFlagInt = typedArray.getInt(R.styleable.myTextView_mFlag,1);
Log.i(TAG,"mFlagInt:" + mFlagInt);
typedArray.recycle();
运行代码结果图:
8、reference 代表引用 (布局文件、资源文件等)
在attr.xml中我们可以<attr name="mReference" format="reference"/>
在我们布局文件中我们可以lgy:mReference="@android:layout/simple_list_item_1"
,
我们在代码中获取我们设置对应值
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.myTextView);
int mColor = typedArray.getColor(R.styleable.myTextView_mColor, Color.RED);
Log.i(TAG,"mColor:" + mColor);
boolean mBoolean = typedArray.getBoolean(R.styleable.myTextView_mBoolean, false);
Log.i(TAG, "mBoolean:" + mBoolean);
float mFloat = typedArray.getFloat(R.styleable.myTextView_mFloat,0.0f);
Log.i(TAG,"mFloat:" + mFloat);
int mInteger = typedArray.getInteger(R.styleable.myTextView_mInteger,1);
Log.i(TAG,"mInteger:" + mInteger);
int mInt = typedArray.getInt(R.styleable.myTextView_mInteger,2);
Log.i(TAG,"mInt:" + mInt);
String mString = typedArray.getString(R.styleable.myTextView_mString);
Log.i(TAG,"mString:" + mString);
int mEnum = typedArray.getInteger(R.styleable.myTextView_mEnum,5);
Log.i(TAG,"mEnum:" + mEnum);
int mEnumInt = typedArray.getInt(R.styleable.myTextView_mEnum,7);
Log.i(TAG,"mEnumInt:" + mEnumInt);
int mFlag = typedArray.getInteger(R.styleable.myTextView_mFlag,1);
Log.i(TAG,"mFlag:" + mFlag);
int mFlagInt = typedArray.getInt(R.styleable.myTextView_mFlag,1);
Log.i(TAG,"mFlagInt:" + mFlagInt);
int mReference = typedArray.getResourceId(R.styleable.myTextView_mReference,0);
Log.i(TAG,"mReference:" + mReference);
typedArray.recycle();
运行代码结果图:
9、fraction 代表百分数
在attr.xml中我们可以<attr name="mFraction" format="fraction"/>
在我们布局文件中我们可以lgy:mFraction="30%"
,
我们在代码中获取我们设置对应值
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.myTextView);
int mColor = typedArray.getColor(R.styleable.myTextView_mColor, Color.RED);
Log.i(TAG,"mColor:" + mColor);
boolean mBoolean = typedArray.getBoolean(R.styleable.myTextView_mBoolean, false);
Log.i(TAG, "mBoolean:" + mBoolean);
float mFloat = typedArray.getFloat(R.styleable.myTextView_mFloat,0.0f);
Log.i(TAG,"mFloat:" + mFloat);
int mInteger = typedArray.getInteger(R.styleable.myTextView_mInteger,1);
Log.i(TAG,"mInteger:" + mInteger);
int mInt = typedArray.getInt(R.styleable.myTextView_mInteger,2);
Log.i(TAG,"mInt:" + mInt);
String mString = typedArray.getString(R.styleable.myTextView_mString);
Log.i(TAG,"mString:" + mString);
int mEnum = typedArray.getInteger(R.styleable.myTextView_mEnum,5);
Log.i(TAG,"mEnum:" + mEnum);
int mEnumInt = typedArray.getInt(R.styleable.myTextView_mEnum,7);
Log.i(TAG,"mEnumInt:" + mEnumInt);
int mFlag = typedArray.getInteger(R.styleable.myTextView_mFlag,1);
Log.i(TAG,"mFlag:" + mFlag);
int mFlagInt = typedArray.getInt(R.styleable.myTextView_mFlag,1);
Log.i(TAG,"mFlagInt:" + mFlagInt);
int mReference = typedArray.getResourceId(R.styleable.myTextView_mReference,0);
Log.i(TAG,"mReference:" + mReference);
float mFraction = typedArray.getFraction(R.styleable.myTextView_mFraction,2,4,0);
Log.i(TAG,"mFraction:" + mFraction);
typedArray.recycle();
运行代码结果图:
**注意:**lgy:mFraction=”30%”
**注意:**lgy:mFraction=”30%p”
注意到我们设置lgy:mFraction=”“值不同得到的结果不一样,那么我们在调用getFraction方法中需要传递4个参数,那么它们分别代表什么呢?为什么得到参数不一样呢?
我们需要查看getFraction源码:
public float getFraction(int index, int base, int pbase, float defValue) {
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_FRACTION) {
return TypedValue.complexToFraction(
data[index+AssetManager.STYLE_DATA], base, pbase);
}
throw new UnsupportedOperationException("Can't convert to fraction: type=0x"
+ Integer.toHexString(type));
}
通过查看源码我可以知道第一个参数和第四参数明白什么意思,第二参数和第三个参数目前我们知道和我们最终返回结果相关,我只有继续往下查看源码:
public static float complexToFraction(int data, float base, float pbase)
{
switch ((data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK) {
case COMPLEX_UNIT_FRACTION:
return complexToFloat(data) * base;
case COMPLEX_UNIT_FRACTION_PARENT:
return complexToFloat(data) * pbase;
}
return 0;
}
哦!通过查看源码我们知道了,当我们设置参数是COMPLEX_UNIT_FRACTION的时候需要*第二个参数base,当我们设置参数是COMPLEX_UNIT_FRACTION_PARENT的时候需要*第三个参数pbase。p代表父容器父布局。
现在我们在看一下我们的例子,当我们设置30%的时候,需要0.3 * 2 = 0.6我们看一下结果是0.599999,当我们设置30%p的时候,需要0.3 * 4 = 1.2我们看一下结果是1.199999,最终返回是一个浮点数。同时我们在看一下COMPLEX_UNIT_FRACTION和COMPLEX_UNIT_FRACTION_PARENT的源码解释就可以明白了。
/** {@link #TYPE_FRACTION} complex unit: A basic fraction of the overall * size. */ public static final int COMPLEX_UNIT_FRACTION = 0; /** {@link #TYPE_FRACTION} complex unit: A fraction of the **parent** size. */ public static final int COMPLEX_UNIT_FRACTION_PARENT = 1;
10、dimension 代表尺寸值
在attr.xml中我们可以<attr name="mDimension" format="dimension"/>
在我们布局文件中我们可以lgy:mDimension="32dp"
,
我们在代码中获取我们设置对应值
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.myTextView);
int mColor = typedArray.getColor(R.styleable.myTextView_mColor, Color.RED);
Log.i(TAG,"mColor:" + mColor);
boolean mBoolean = typedArray.getBoolean(R.styleable.myTextView_mBoolean, false);
Log.i(TAG, "mBoolean:" + mBoolean);
float mFloat = typedArray.getFloat(R.styleable.myTextView_mFloat,0.0f);
Log.i(TAG,"mFloat:" + mFloat);
int mInteger = typedArray.getInteger(R.styleable.myTextView_mInteger,1);
Log.i(TAG,"mInteger:" + mInteger);
int mInt = typedArray.getInt(R.styleable.myTextView_mInteger,2);
Log.i(TAG,"mInt:" + mInt);
String mString = typedArray.getString(R.styleable.myTextView_mString);
Log.i(TAG,"mString:" + mString);
int mEnum = typedArray.getInteger(R.styleable.myTextView_mEnum,5);
Log.i(TAG,"mEnum:" + mEnum);
int mEnumInt = typedArray.getInt(R.styleable.myTextView_mEnum,7);
Log.i(TAG,"mEnumInt:" + mEnumInt);
int mFlag = typedArray.getInteger(R.styleable.myTextView_mFlag,1);
Log.i(TAG,"mFlag:" + mFlag);
int mFlagInt = typedArray.getInt(R.styleable.myTextView_mFlag,1);
Log.i(TAG,"mFlagInt:" + mFlagInt);
int mReference = typedArray.getResourceId(R.styleable.myTextView_mReference,0);
Log.i(TAG,"mReference:" + mReference);
float mFraction = typedArray.getFraction(R.styleable.myTextView_mFraction,2,4,0);
Log.i(TAG,"mFraction:" + mFraction);
float mDimension = typedArray.getDimension(R.styleable.myTextView_mDimension, 14f);
Log.i(TAG, "mDimension:" + mDimension);
typedArray.recycle();
运行代码结果图:
我们设置lgy:mDimension=”32dp”不同单位得到的值是不相同的。
32dp –>01-03 03:49:23.800 10694-10694/com.lgy.typearray I/MyTextView: mDimension:48.0
32sp –>01-03 03:53:43.210 14638-14638/com.lgy.typearray I/MyTextView: mDimension:48.0
32px –>01-03 03:54:30.430 15446-15446/com.lgy.typearray I/MyTextView: mDimension:32.0
32pt –>01-03 03:57:24.300 18042-18042/com.lgy.typearray I/MyTextView: mDimension:120.41481
32in –>01-03 03:58:07.660 18733-18733/com.lgy.typearray I/MyTextView: mDimension:8669.866
32mm –>01-03 03:59:17.210 19773-19773/com.lgy.typearray I/MyTextView: mDimension:341.3333
为什么设置不同单位得到值不同呢?这也需要查看源码:
public float getDimension(int index, float defValue) { 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], mResources.mMetrics); } throw new UnsupportedOperationException("Can't convert to dimension: type=0x" + Integer.toHexString(type)); }
此时看不出什么门道来,继续往下看TypedValue.complexToDimension方法
public static float complexToDimension(int data, DisplayMetrics metrics) { return applyDimension( (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK, complexToFloat(data), metrics); }
继续看applyDimension方法
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; }
到此豁然开朗了吧!
获取尺寸的方法还有getDimensionPixelSize方法和getDimensionPixelOffset方法。那么它们有什么不同呢?
再一次通过查看源码我就可以得出结论.
public int getDimensionPixelOffset(int index, int defValue) { 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.complexToDimensionPixelOffset( data[index+AssetManager.STYLE_DATA], mResources.mMetrics); } throw new UnsupportedOperationException("Can't convert to dimension: type=0x" + Integer.toHexString(type)); }
public int getDimensionPixelSize(int index, int defValue) { 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.complexToDimensionPixelSize( data[index+AssetManager.STYLE_DATA], mResources.mMetrics); } throw new UnsupportedOperationException("Can't convert to dimension: type=0x" + Integer.toHexString(type)); }
通过源码知道2个方法分别都调用了TypedValue.complexToDimensionPixelOffset,TypedValue.complexToDimensionPixelSize,继续看源码:
public static int complexToDimensionPixelOffset(int data, DisplayMetrics metrics) { return (int)applyDimension( (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK, complexToFloat(data), metrics); }
public static int complexToDimensionPixelSize(int data, DisplayMetrics metrics) { final float value = complexToFloat(data); final float f = applyDimension( (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK, value, metrics); final int res = (int)(f+0.5f); if (res != 0) return res; if (value == 0) return 0; if (value > 0) return 1; return -1; }
最终2个方法也都调用了applyDimension方法,只不过两者调用了applyDimension方法强制转换int,complexToDimensionPixelSize方法得到值之后又做了简单处理。
那么现在我们可以知道getDimension、getDimensionPixelSize、getDimensionPixelOffset三者区别:
相同点:不同单位尺寸设置得到不同结果。都会调用applyDimension方法。
不同点:getDimension返回float类型,getDimensionPixelSize、getDimensionPixelOffset都是返回int类型。
就写这些吧!
- View自定义属性步骤与分析
- Android实现自定义View的自定义属性的一般步骤
- Android-自定义view里实现自定义属性步骤
- Android自定义View的基本步骤和使用自定义属性
- 自定义View自定义属性
- 自定义View自定义属性
- 自定义View自定义属性
- 自定义View自定义属性
- 自定义View自定义属性
- 自定义View-自定义属性
- Android 自定义View步骤
- Android 自定义View步骤
- 自定义view步骤详解
- 自定义View步骤
- 自定义View步骤
- 自定义View的步骤
- 自定义View步骤
- Android 自定义view步骤
- poj 2996 Help Me with the Game
- Hibernate-validator校验框架
- new运算符 和 operator new
- UVa 156 map小用
- 按位运算符讲解和运用
- View自定义属性步骤与分析
- Application 基础
- 在cmd中编译执行java文件
- python kazoo 监视zookeeper节点数据发生变化
- STL deque
- Web服务基础一之Apache源码和YUM安装
- HDU5761 Rower Bo
- Swift基础(二十六)UIWebView
- 一个老鸟发的公司内部整理的 Android 学习路线图 Markdown 版本