只有站在设计者的角度上,才可以更好的创建出定义View。
在自定义View时,我们通常会去重写onDraw()方法来绘制View显示的内容,如果该View还要使用wrap_content属性,那么嗨必须重写onMeasue方法。另外,通过自定义attrs属性还可以设置新的属性配置。
View中重要的回调方法:
onFinishInflate():从xml加载组建后回调。
onSizeChanged():组件大小改变的时候回调。
onMeasure():回调该方法来进行测量。
onLayout():回调该方法来确定显示的位置。
onTouchEvent():监听到触摸事件的时候回调。
创建自定一个View并不需要重写所有方法,只重写特定条件下的回调即可。
自定义View的实现方式:
1、对现有的控件进行扩展。
2、通过组合控件实现新的控件。
3、重写View来实现全新的控件。
对现有的控件进行扩展:
在构造方法中完成必要的对象的初始化工作。
@Override
protected void onDraw(Canvas canvas) {
//实现自己的逻辑
super.onDraw(canvas);
//实现自己的逻辑
}
通过组合控件实现新的控件
通常需要继承一个合适的ViewGroup,给他添加指定功能的控件。
使用自定义View与系统原生的View的区别就是在声明控件的时候,需要制定完整的包名,而在引用自定义属性的时候,需要使用自定义的xmlns名字。
重写View来实现全新的控件
实现全新的View难点在于绘制控件和实现交互。
通常需要继承View类,重写onDraw方法,onMeasure方法来实现绘图的逻辑。同时通过重写onTouchedEvent等触控事件来实现交互逻辑。
自定义ViewGroup的实现方式:
自定义ViewGroup的目的就是为了对其子View进行管理,为其子View添加显示,响应的规则。
因此,自定义ViewGroup通常需要重写onMeasure方法来对子View尽心测量,重写onLayout方法来确定子View的位置。重写onTouchEvent增加响应事件。
代码模板:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
measureChild(child, widthMeasureSpec, heightMeasureSpec);
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childCount = getChildCount();
MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();
mlp.height = childCount * mScreenHeight;
setLayoutParams(mlp);
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (child.getVisibility() != View.GONE) {
child.layout(l, i * mScreenHeight, r, (i + 1) *mScreenHeight);
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
}
postInvalidate();
return true;
}
@Override
public void computeScroll() {
super.computeScroll();
if (mScroller.computeScrollOffset()) {
scrollTo(0, mScroller.getCurrY());
postInvalidate();
}
}