侧滑菜单
创建一个类继承ViewGroup,并实现构造器
实现onMeasure onLayout 方法
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
measureChildren(widthMeasureSpec, heightMeasureSpec);
mMenuView = getChildAt(0);
mMainView = getChildAt(1);
int widthSize =MeasureSpec.getSize(widthMeasureSpec);
int heightSize =MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(widthSize, heightSize);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
mMenuView.layout(-mMenuView.getMeasuredWidth(), 0, 0,
mMenuView.getMeasuredHeight());
mMainView.layout(0, 0,mMainView.getMeasuredWidth(),
mMainView.getMeasuredHeight());
}
实现onTouchEvent() 并试验按下的scrollTo()/scrollBy()
我们在自定义控件的时候常常需要控件滚动,android提供了三个api来进行滚动控件的内容
1. ScrollTo(x,y)快速滚动到(x,y)注意方向平常的坐标系是相反的
2. ScrollBy(x,y)移动x,y的偏移量
3. Scroller Scroller本身不能使View移动,要配合computeScroll才能实现滑动,原理也是不停让控件重绘
@Override
public boolean onTouchEvent(MotionEventevent) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 下⾯面两个⽅方法 偏移量都是坐标系的反向
// 跳到某个位置 多次点击还在该位置
// scrollTo(-mMenuView.getWidth(),0);
// 每次在原来的位置进⾏行偏移
scrollBy(100, 0);
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
实现手指拖动时 界面跟着移动
//当前按下的那个点 可以认为是起始点private float touchX;
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchX=event.getX();
break;
case MotionEvent.ACTION_MOVE:
//移动某个瞬间的点 可以认为是瞬间的结束点
float currenX=event.getX();
//计算瞬时两个点的距离
float deltaX=currenX-touchX;
//因为scrollBy的坐标系的反的 所有这 应该为负
scrollBy((int) -deltaX, 0);
//下 瞬间的起点就是此刻的结束点
touchX=currenX;
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
处理拖动越界的问题
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchX=event.getX();
break;
case MotionEvent.ACTION_MOVE:
float currenX=event.getX();
float deltaX=currenX-touchX;
//这 可能出现越界的问题 可以先计算下 如果下 瞬间移动到位置越界就需要处理
//1.计算将要移动的位置
int destinationX=(int) (getScrollX()+(-deltaX));
if (destinationX<-mMenuView.getWidth()) {//往左拖
scrollTo(-mMenuView.getWidth(), 0);
}else {
scrollTo(0, 0);
}else if (destinationX>0) {//往右拖
scrollBy((int) -deltaX, 0);
}
touchX=currenX;
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
手指抬起的时候 如果没有滑动到位 需要计算到底要隐藏菜单还是显示菜单
case MotionEvent.ACTION_UP:
//1.计算菜单的中 点位置
float menuHalfe=-mMenuView.getWidth()/2;
//2.如果菜单左边超过菜单的 半则显 如果没超过则隐藏
if (getScrollX()>menuHalfe) {
scrollTo(0, 0);
}else {
scrollTo(-mMenuView.getWidth(), 0);
}
break;
上面的做法中 我们发现显示/隐藏动画没有动画效果
case MotionEvent.ACTION_UP:
//1.计算菜单的中 点位置
float menuHalfe=-mMenuView.getWidth()/2;
//2.如果菜单左边超过菜单的 半则显 如果没超过则隐藏
if (getScrollX()>menuHalfe) {
// scrollTo(0, 0);
mScroller.startScroll(getScrollX(), 0, 0-getScrollX(), 0, 400);
invalidate();
}else {
// scrollTo(-mMenuView.getWidth(), 0);
mScroller.startScroll(getScrollX(), 0,
-mMenuView.getWidth()-getScrollX(), 0, 400);
invalidate();
}
break;
@Override
public void computeScroll() {
//computeScrollOffset()返回true说明还需要滚动
if (mScroller.computeScrollOffset()) {
//mScroller.getCurrX() 当前计算滚动到哪
scrollTo(mScroller.getCurrX(), 0);
invalidate();
}
}
如果是点击左边的列表左右滑动发现没有效果 先判断 如果发现是左右滑动 则拦截事件 不要列
表再去处理了
float tabX;
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
tabX=ev.getX();
break;
case MotionEvent.ACTION_MOVE:
//上下滑动说明需要拦截事件
Log.v("520it", Math.abs(ev.getX()-tabX)+" velp");
if (Math.abs(ev.getX()-tabX)>8) {
return true;
}
tabX=ev.getX();
break;
case MotionEvent.ACTION_UP:
break;
}
return super.onInterceptTouchEvent(ev);
}