我们在做android界面的时候,经常会在xml文件中写如下代码:
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:orientation="horizontal" >
<include layout="@layout/layout_menu" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/qq" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="toggleMenu"
android:text="button" />
</LinearLayout>
</LinearLayout>
可以看到这里使用了大量的属性,如android:layout_width,android:layout_height,android:background等等,这里我记录下如何自定义属性。
我们的例子是这样的,使用自定义的属性定义圆的半径和圆心坐标,然后在自定义的MyView(继承自View)中将这个圆画出来
要自定义属性,我们首先需要在xml文件中定义这些属性,在res/values/attrs.xml文件中(如果没有就创建这个文件)加入如下代码:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyView">
<attr name="radius" format="float"></attr>
<attr name="cx" format="float"></attr>
<attr name="cy" format="float"></attr>
</declare-styleable>
</resources>
上面的代码定义了三个属性,radius代表圆的半径,cx和cy代表圆心坐标,在declare-styleable标签中有一个name属性,name属性的值可以随意取,这个值将会在我们做界面时用到。
下面我们定义MyView控件,这个控件继承了View,复写了onDraw方法,在onDraw中画圆,代码如下:
package com.example.testattrs;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
public class MyView extends View {
private float radius;//半径
private float cx;//圆心横坐标
private float cy;//圆心纵坐标
private Paint paint;//画圆用到的画笔
/**构造方法,在其中获取我们在xml文件中定义的属性,并初始化一些数据*/
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
//设置画笔的属性
paint = new Paint();
paint.setStrokeWidth(5);
paint.setColor(Color.RED);
//获取xml中定义的属性
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyView);
//得到属性的总个数
final int N = a.getIndexCount();
//通过循环获取我们自定义的属性的值
for(int i = 0; i < N; i++){
int attr = a.getIndex(i);
switch(attr){
case R.styleable.MyView_radius:
radius = a.getFloat(attr, 5.0f);
break;
case R.styleable.MyView_cx:
cx = a.getFloat(attr, 10f);
break;
case R.styleable.MyView_cy:
cy = a.getFloat(attr, 10f);
break;
}
}
//TypedArray使用完毕后一定要调用recycle()方法
a.recycle();
}
public MyView(Context context, AttributeSet attrs) {
//调用了第一个构造方法
this(context, attrs, 0);
}
public MyView(Context context) {
//调用了第一个构造方法
this(context, null, 0);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//画出圆
canvas.drawCircle(cx, cy, radius, paint);
}
}
可以看到,上面的switch语句中,每一个case后都是R.styleable.MyView_+属性名,这里的MyView_就是我们在属性文件中declare-styleable标签中定义的name属性的值。
然后是Activity中布局文件的使用了,这里先上布局文件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:myview="http://schemas.android.com/apk/res/com.example.testattrs"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.testattrs.MyView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
myview:radius="80.0"
myview:cx="100.0"
myview:cy="100.0"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" />
</RelativeLayout>
在布局文件中,我们加入了一个自定义的MyView,这里最需要注意的是RelativeLayout中的xmlns:myview="http://schemas.android.com/apk/res/com.example.testattrs"
因为使用了我们自定义的属性,所以这里要加上新的命名空间,命名空间的写法为:xmlns:[名称]="http://schemas.android.com/apk/res/[控件所在包名]",布局文件中使用自定义属性的方法,就是命名空间+属性名,如myview:radius、myview:cx、myview:cy。
到这里基本上就完成所有代码了,我们运行程序,效果如下: