前面只是简单说了自定义View,接下来我们再来个增强版——自定义View的属性
1、自定义View的属性,首先在res/values/ 下建立一个attrs.xml , 在里面定义我们的属性。
<resources>
<declare-styleable name="CustomAttrView">
<attr name="text" format="string" />
<attr name="textColor" format="color" />
<attr name="textSize" format="dimension" />
</declare-styleable>
</resources>
这里简单介绍一下控件的常用属性
format的取值及使用
1. Reference:引用类型,参考某一资源ID
(1)属性定义:
<declare-styleable name = "名称"><attr name = "background" format = "reference"/><attr name = "src" format = "reference" /></declare-styleable>
(2)属性使用:
<ImageView android:layout_width = "42dip"android:layout_height = "42dip"android:background = "@drawable/图片ID"/>
2. color:颜色值。
(1)属性定义:
<declare-styleable name = "名称"><attr name = "textColor" format = "color"/></declare-styleable>
(2)属性使用:
<TextView android:layout_width = "42dip"android:layout_height = "42dip"android:textColor = "#00FF00"/>
3. boolean:布尔值。
(1)属性定义:
<declare-styleable name = "名称"><attr name = "focusable" format = "boolean"/></declare-styleable>
(2)属性使用:
<Button android:layout_width = "42dip"android:layout_height = "42dip"android:focusable = "true"/>
4. dimension:尺寸值。
(1)属性定义:
<declare-styleable name = "名称"><attr name = "layout_width" format = "dimension"/><attr name = "layout_height" format = "dimension"/></declare-styleable>
(2)属性使用:
<Button android:layout_width = "42dip"android:layout_height = "42dip"/>
5. float:浮点值。
(1)属性定义:
<declare-styleable name = "名称"><attr name = "fromAlpha" format = "float"/><attr name = "toAlpha" format = "float"/></declare-styleable>
(2)属性使用:
<alpha android:fromAlpha = "1.0" android:toAlpha = "0.7"/>
6. integer:整型值。
(1)属性定义:
<declare-styleable name = "名称"><attr name = "visible"/><attr name = "frameDuration" format="integer"/><attr name = "framesCount" format="integer"/><attr name = "pivotX"/><attr name = "pivotY"/><attr name = "drawable"/></declare-styleable>
(2)属性使用:
<animated-rotate xmlns:android ="http://schemas.android.com/apk/res/android"android:drawable = "@drawable/图片ID"android:pivotX = "50%"android:pivotY = "50%"android:framesCount = "12"android:frameDuration = "100"/>
7. string:字符串。
(1)属性定义:
<declare-styleable name = "名称"><attr name = "text" format = "string" /></declare-styleable>
(2)属性使用:
<TextViewandroid:layout_width = "fill_parent"android:layout_height = "fill_parent"android:text ="0jOkQ80oD1JL9C6HAja99uGXCRiS2CGjKO_bc_g"/>
8. fraction:百分数类型。
(1)属性定义:
<declare-styleable name="名称"><attr name = "visible"/><attr name = "fromDegrees" format = "float"/><attr name = "toDegrees" format = "float"/><attr name = "pivotX" format = "fraction"/><attr name = "pivotY" format = "fraction"/><attr name = "drawable"/></declare-styleable>
(2)属性使用:
<rotate xmlns:android ="http://schemas.android.com/apk/res/android"android:interpolator = "@anim/动画ID"android:fromDegrees = "0"android:toDegrees = "360"android:pivotX = "200%"android:pivotY = "300%"android:duration = "5000"android:repeatMode = "restart"android:repeatCount = "infinite"/>
9. enum:枚举值。
(1)属性定义:
<declare-styleable name="名称"><attr name="orientation"><enum name="horizontal" value="0"/><enum name="vertical" value="1"/></attr></declare-styleable>
(2)属性使用:
<LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android"android:orientation = "vertical"android:layout_width = "fill_parent"android:layout_height = "fill_parent"></LinearLayout>
10. flag:位或运算。
(1)属性定义:
<declare-styleable name="名称"><attr name="windowSoftInputMode"><flag name = "stateUnspecified" value = "0"/><flag name = "stateUnchanged" value = "1"/><flag name = "stateHidden" value = "2"/><flag name = "stateAlwaysHidden" value = "3"/><flag name = "stateVisible" value = "4"/><flag name = "stateAlwaysVisible" value = "5"/><flag name = "adjustUnspecified" value = "0x00"/><flag name = "adjustResize" value = "0x10"/><flag name = "adjustPan" value = "0x20"/><flag name = "adjustNothing" value = "0x30"/></attr></declare-styleable>
(2)属性使用:
<activity android:name = ".StyleAndThemeActivity"android:label = "@string/app_name"android:windowSoftInputMode = "stateUnspecified | stateUnchanged | stateHidden"><intent-filter><action android:name = "android.intent.action.MAIN"/><category android:name = "android.intent.category.LAUNCHER"/></intent-filter></activity>
注意:
属性定义时可以指定多种类型值。
(1)属性定义:
<declare-styleable name = "名称">
<attr name = "background" format = "reference|color"/>
</declare-styleable>
(2)属性使用:
<ImageView android:layout_width = "42dip"
android:layout_height = "42dip"
android:background = "@drawable/图片ID|#00FF00"/>
11. 多类型
<declare-styleable name = "名称">
<attr name = "background" format = "reference|color" />
</declare-styleable>
2、在布局文件中声明我们的View
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:custom="http://schemas.android.com/apk/res/com.example.activity"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.activity.view.CustomAttrView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:padding="10dp"
custom:text="9958"
custom:textColor="#ff0000"
custom:textSize="30sp" />
这里要强调的一点就是,一定要引入我们自己的名称空间(我绿色标注的部分),后面的包路径指的是项目的包名。
3、在View的构造方法中,获得我们的自定义的属性
public class CustomAttrView extends View {
private String mStrText;
private int mTextColor;
private int mTextSize;
/**
* 绘制时控制文本绘制的范围
*/
private Rect mBound;
private Paint mPaint;
public CustomAttrView(Context context) {
this(context, null);
}
public CustomAttrView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
// 获得自定义的样式属性
public CustomAttrView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
/**
* 获得自定义样式属性
*/
TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs,
R.styleable.CustomAttrView, defStyle, 0);
// int n = typedArray.getIndexCount();
// for (int i = 0; i < n; i++) {
// int attr = typedArray.getIndex(i);
// switch (attr) {
// case R.styleable.CustomAttrView_text:
// mStrText = typedArray.getString(attr);
// break;
// case R.styleable.CustomAttrView_textColor:
// // 默认颜色设置为黑色
// mTextColor = typedArray.getColor(attr, Color.BLACK);
// break;
// case R.styleable.CustomAttrView_textSize:
// // 默认设置为16sp,TypeValue也可以把sp转化为px
// mTextSize = typedArray.getDimensionPixelSize(attr,
// (int) TypedValue.applyDimension(
// TypedValue.COMPLEX_UNIT_SP, 16, getResources()
// .getDisplayMetrics()));
// break;
//
// }
//
// }
/**
* 下面三句和上面注释掉的句子的作用一样
*/
mStrText = typedArray.getString(R.styleable.CustomAttrView_text);
mTextColor = typedArray.getColor(R.styleable.CustomAttrView_textColor, Color.BLACK);
mTextSize = typedArray.getDimensionPixelSize(R.styleable.CustomAttrView_textSize,16);
typedArray.recycle();
mPaint = new Paint();
mPaint.setTextSize(mTextSize);
mPaint.setColor(mTextColor);
/**
* 获得绘制文本的宽和高
*/
mBound = new Rect();
mPaint.getTextBounds(mStrText, 0, mStrText.length(), mBound);
}
}
4、重写onDraw,调用系统提供的onMesure方法
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onDraw(Canvas canvas) {
mPaint.setColor(Color.BLUE);
canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);
mPaint.setColor(mTextColor);
canvas.drawText(mStrText, getWidth() / 2 - mBound.width() / 2,
getHeight() / 2 + mBound.height() / 2, mPaint);
}
此时效果如下:
但是此时如果我们把布局文件的宽和高写成wrap_content,会发现效果和我们想的并不一样:
这是因为系统帮我们测量的高度和宽度都是MATCH_PARNET,当我们设置明确的宽度和高度时,系统帮我们测量的结果就是我们设置的结果,当我们设置为WRAP_CONTENT或者MATCH_PARENT系统帮我们测量的结果就是MATCH_PARENT的长度。
所以,当设置了WRAP_CONTENT时,我们需要自己进行测量,即重写onMesure方法,重写之前先了解下MeasureSpec的specMode的类型:
EXACTLY:一般是设置了明确的值或者是MATCH_PARENT
AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT
UNSPECIFIED:表示子布局想要多大就多大,很少使用
下面是我们重写onMeasure代码:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = 0;
int height = 0;
/**
* 设置宽度
*/
int specMode = MeasureSpec.getMode(widthMeasureSpec);
int specSize = MeasureSpec.getSize(widthMeasureSpec);
switch (specMode) {
case MeasureSpec.EXACTLY:// 明确指定了
width = getPaddingLeft() + getPaddingRight() + specSize;
break;
case MeasureSpec.AT_MOST:// 一般为WARP_CONTENT
width = getPaddingLeft() + getPaddingRight() + mBound.width();
break;
}
/**
* 设置高度
*/
specMode = MeasureSpec.getMode(heightMeasureSpec);
specSize = MeasureSpec.getSize(heightMeasureSpec);
switch (specMode) {
case MeasureSpec.EXACTLY:// 明确指定了
height = getPaddingTop() + getPaddingBottom() + specSize;
break;
case MeasureSpec.AT_MOST:// 一般为WARP_CONTENT
height = getPaddingTop() + getPaddingBottom() + mBound.height();
break;
}
setMeasuredDimension(width, height);
}
现在我们可以对高度、宽度进行随便的设置了,基本可以满足我们的需求。
当然了我们这个自定义View与TextView相比还没什么区别,但是前面的例子已经提到,我们可以给View添加一些监听事件,代码就不写了,想看的话可以下载源码。
源代码
参考:
http://www.jb51.net/article/32172.htm