Android自定义View

因为Android的UI 大部分都是直接通过xml文件的,但是在xml文件里我们只是写明了 一些键值对,例如 layout_height = “100dp” 一个view的显示绘制逻辑则是在类中实现。

自定义View分为几个步骤:

第一步:在valuse/arrts创建我们view的属性

1
2
3
4
5
6
<resources>
<declare-styleable name="customview">
<attr name="text" format="string" />
<attr name="testArray" format="integer" />
</declare-styleable>
</resources>

也可直接,不过在获取时略微麻烦

1
2
<attr name="text" format="string" />
<attr name="testArray" format="integer" />

第二步:在我们的自定义的view的构造方法中获取这些属性对应的值,这些值就是被我们定义在布局文件里的:例如:

1
2
3
4
5
<com.example.kevin.myapplication.MyView
android:layout_width="150dp"
android:layout_height="120dp"
spa:testArray="520"
spa:text="hello world" />

内部是通过解析xml将其封装在AttributeSet对象里,并传入view的构造参数里。因此我们在view的构造函数里是可以直接获取到定义的各个属性的值的。但是一般不推荐,因为当一些值是引用时,获取的是id,我们还需要进行转化。所以大部分是直接

TypedArray ta =context.obtainStyledAttributes(attrs,R.styleable.customview);

此时declare-styleable:

1
2
3
TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.customview);
String text = ta.getString(R.styleable.customview_text);
int testArray = ta.getInteger(R.styleable.customview_testArray,1);

没有的则需要手动得到id,存入数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class MyTextView extends View {
private static final String TAG = MyTextView.class.getSimpleName();
private static final int[] mAttr = { android.R.attr.text, R.attr.testAttr };
private static final int ATTR_ANDROID_TEXT = 0;
private static final int ATTR_TESTATTR = 1;
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
// ==>use typedarray
TypedArray ta = context.obtainStyledAttributes(attrs, mAttr);
String text = ta.getString(ATTR_ANDROID_TEXT);
int textAttr = ta.getInteger(ATTR_TESTATTR, -1);
//输出 text = Hello world! , textAttr = 520
Log.e(TAG, "text = " + text + " , textAttr = " + textAttr);
ta.recycle();
}
}

而写成declare-styleable的会自动生成如下:

1
2
3
4
5
6
7
8
9
10
public static final class attr {
public static final int testAttr=0x7f0100a9;
}
public static final class styleable {
public static final int test_android_text = 0;
public static final int test_testAttr = 1;
public static final int[] test = {
0x0101014f, 0x7f0100a9
};
}

第三步:如果我们的view需要支持wrap_content则需要重写onMeasure()来设置一个最大值。

第四步:根据得到的每个属性的值,用andorid原生的api来写绘制逻辑,重写onDraw()。