自定义控件的三个方法
- onMeasure() 测量控件的宽和高
- onLayout() 摆放控件的位置
- onDraw() 绘制布局
下面看一点下代码:
public class SlideMenu extends ViewGroup {
private float downX;
private float moveX;
private Scroller scroller;
public SlideMenu(Context context) {
this(context,null);
}
public SlideMenu(Context context, AttributeSet attrs) {
this(context, null,0);
}
public SlideMenu(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
scroller = new Scroller(getContext());
}
/**
* 设置子View的宽高
* @param widthMeasureSpec 当前控件的宽度(测量规则)
* @param heightMeasureSpec 当前控件的高度(测量规则)
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
/*
leftMenu的宽是指定的450dp,高是matchparent
*/
//指定SlideMenu的宽高
View leftMenu = getChildAt(0);
//宽是子空间指定的宽,高直接是父控件的高
Log.i(getClass().getSimpleName(),"width : "+leftMenu.getMeasuredWidth());
leftMenu.measure(leftMenu.getLayoutParams().width,heightMeasureSpec);
/*
mainContent的宽和高都是match_parent
*/
//指定content的宽高
View mainContent = getChildAt(1);
mainContent.measure(widthMeasureSpec,heightMeasureSpec);
super.onMeasure(widthMeasureSpec,heightMeasureSpec);
}
/**
* 摆放控件的位置
* @param changed 当前控件的尺寸大小和位置是否发生了改变
* @param l left 当前控件的右边距
* @param t top 当前控件的顶边距
* @param r right 当前控件的右边界
* @param b bottom当前控件的下边界
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
/*
摆放leftMenu的位置,
*/
View leftMenu = getChildAt(0);
leftMenu.layout(-leftMenu.getMeasuredWidth(),0,0,b);
/*
摆放mainContent的位置
*/
getChildAt(1).layout(l,t,r,b);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN://按下
downX = event.getX();//获取按下时的X的坐标
break;
case MotionEvent.ACTION_MOVE://滑动
moveX = event.getX();//获取滑动时的X的坐标
//将要滑动的距离
int scroll = (int) (downX - moveX);//这里是一个负值
//计算将要滚动到的位置,判断是否会超出去 getScroll()右边界相对于当前View X轴的变异量,是个带正负号的值。
int newScroll = getScrollX() + scroll;
/*
scrollTo()滚动到指定的位置
scrollBy()在原来的基础上滚动
*/
//如果将要滑动的距离超过了leftMenu的宽,就直接指定X坐标的位置,将leftMenu显示出来
if (newScroll < -getChildAt(0).getMeasuredWidth()){
scrollTo(-getChildAt(0).getMeasuredWidth(),0);
}else if (newScroll>0){//如果向左滑的话,
scrollTo(0,0);
} else{
scrollBy(scroll,0);
}
downX = moveX;//必须要将moveX赋值给downX,因为滑动的过程是一小段一小段的滑动
break;
case MotionEvent.ACTION_UP://拿起
Log.i(getClass().getSimpleName(),"getScrollX: "+getScrollX());
if (getScrollX() <= -(getChildAt(0).getMeasuredWidth())/2.0f){//当leftMenu画出来显示了一半的时候
scrollTo(-getChildAt(0).getMeasuredWidth(),0);
}else {//当没有滑出一半的时候
scrollTo(0,0);
}
break;
default:
break;
}
return true;//消费事件
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
}
注意
onMeasure()测量的时候,得到的值与你在布局文件中写的是有偏差的。