实现原理
通过自定义ViewGroup重写onLayout方法监听
onTouchEvent方法当手指在屏幕滑动时重新对contentView、menuView进行layout。
实现过程
1、重写onMeasure
注意:在OnMeasure方法中调用measureChildren(widthMeasureSpec, heightMeasureSpec),否则子View 尺寸将不被计算.
onMeasure方法中自定义的ViewGroup需要显示的调用
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec)设置容器的宽高
MeasureSpec注解:
{
由一个32位int值表示,前两位表示mode,后两位表示size。
Mode值:
1.精确模式(MeasureSpec.EXACTLY)
在这种模式下,尺寸的值是多少,那么这个组件的长或宽就是多少。
2.最大模式(MeasureSpec.AT_MOST)
这个也就是父组件,能够给出的最大的空间,当前组件的长或宽最大只能为这么大,当然也可以比这个小。
3.未指定模式(MeasureSpec.UNSPECIFIED)
这个就是说,当前组件,可以随便用空间,不受限制。
示例:
//MeasureSpec.AT_MOST表示此模式下最大允许的数量值
int heightMode = MeasureSpec.AT_MOST;
int heightSize = maxHeight;
//根据mode和size计算出spec值
heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode);
//设置容器的宽高
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
}
/**
*
* @param dis 手指移动的距离
*/
private void layoutChildViewsBySwipeDistance(int dis) {
log("swipe " + dis);
int menusWidth = getMenusWidth();
if (dis > menusWidth) {
dis = menusWidth;
}
if (dis < 0) {
dis = 0;
}
// 将ContentView居中布局,左起始位置是滑动的距离
contentView.layout(-dis, (getMeasuredHeight() - contentView.getMeasuredHeight()) / 2,
contentView.getMeasuredWidth() - dis, (getMeasuredHeight() + contentView.getMeasuredHeight()) / 2);
// 将menuView居中布局,左起始位置是滑动的距离加上ContentView的宽度
for (int i = 0; i < menuViews.size(); i++) {
View menuView = menuViews.get(i);
int leftPosition = 0;
if (i == 0) {
leftPosition = contentView.getMeasuredWidth() - dis;
} else {
leftPosition = contentView.getMeasuredWidth() - dis;
for (int j = 0; j < i; j++) {
leftPosition += menuViews.get(j).getMeasuredWidth();
}
}
int rightPosition = leftPosition + menuView.getMeasuredWidth();
menuView.layout(leftPosition, (getMeasuredHeight() - menuView.getMeasuredHeight()) / 2, rightPosition,
(getMeasuredHeight() + menuView.getMeasuredHeight()) / 2);
log(i + " leftPosition = " + leftPosition + " rightPosition = " + rightPosition);
}
}
3、对
onTouchEvent的监听
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = (int) event.getX();
if (STATE == 0) {
if (swipeLayoutContainer != null) {
swipeLayoutContainer.closeAllSwipeLayout();
}
}
break;
case MotionEvent.ACTION_MOVE:
int dis = (int) (downX - event.getX());
if (STATE == 1) {
// 打开状态滑动距离初始值为Menu的Width
dis += getMenusWidth();
}
layoutChildViewsBySwipeDistance(dis);
if (Math.abs(dis) >= MIN_SWIPE_INTERREPT_DISTANCE) {
getParent().requestDisallowInterceptTouchEvent(true); //告诉父ViewGroup这个事件不再被中断
}
break;
case MotionEvent.ACTION_UP:
if ((int) (downX - event.getX()) > getMenusWidth() / 2) {
openMenu();
} else {
closeMenu();
}
break;
}
return true;
}
源码见:
https://github.com/mars-ma/AndroidSwipeLayout