自定义控件一般分为以下几种:
创建一个自定义控件,并让它继承自ViewGroup,在构造方法中,通过下面的代码来获取在xml布局文件中自定义的那些属性。
TypedArray ta = context.obtainStyledAttributes(attr,R.styleable.TopBar);
通过TypedArray对象的getString()、getColor()等方法,就可以获取这些定义的属性值。
mLeftTextColor = ta.getColor(R.styleable.TopBar_leftTextColor);
当获取完所有的属性值后,需要调用TypeArray的ta.recyle();来完成资源的回收。
进行控件的组合,为创建的组件元素赋值。值就来源于我们在引用的xml文件中给对应属性的赋值。
xxx.setColor(mLeftTextColor);
定义接口(比如响应事件等)。
在引用前,需要制定引用第三方控件的名字空间。在布局文件中,可以看到如下一行代码:
xmlns:android=”http://schemas.android.com/apk/res/android“
这行代码就是指定引用的名字空间xmlns,即xml namespace。这里指定了名字空间为”android”,因此在接下来使用系统属性的时候,才可以使用”android:”来引用Android的系统属性。同样的,如果使用自定义的属性,那么就需要创建自己的名字空间,第三方的控件都使用如下代码来引入名字空间。
xmlns:custom="http://schemas.android.com/apk/res-auto"
接下来在布局中就能引用了:
custom:leftTextColor="#ffffff"
自定义ViewGroup需要重写onMeasure()方法来对子View进行测量,重写onLayout()方法来确定子View的位置,重写onTouchEvent()来增加响应事件。
@Override
protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec){
super.onMeasure(widthMeasureSpec,heightMeasureSpec);
int count = getChildCount();
for(int i = 0; i < count; i++){
View childView = getChildAt(i);
measureChild(childView,widthMeasureSpec,heightMeasureSpec);
}
}
在获取了整个ViewGroup的高度以后,就可以通过遍历来设定每个子View需要放置的位置了,直接调用子View的layout()方法,并将具体的位置作为参数传递进去即可。
@Override
protected void onLayout(boolean changed,int l,int t,int r,int b){
//...
for(int i = 0; i < childCount; i++){
View child = getChildAt(i);
child.layout(l,top,r,bottom);
}
}
对于ViewGroup(事件传递)
dispatchTouchEvent——>onInterceptTouchEvent——>onTouchEvent
对于View(事件传递)
dispatchTouchEvent——>onTouchEvent
事件传递的返回值:true 拦截,不继续;false 不拦截,继续流程;
事件处理的返回值:true 处理了,不用审核了;false给上级处理。
在事件传递中,只关心onInterceptTouchEvent()方法。而dispatchTouchEvent()方法一般不用改。