自定义一个Menu。
由3个组成基本视图。
private FrameLayout middleMenu;
private FrameLayout leftMenu;
private FrameLayout rightMenu;
再自定义滑动手势。
public boolean dispatchTouchEvent(MotionEvent ev)。
一。静态布局。
public class MainUI extends RelativeLayout {
private Context context;
private FrameLayout middleMenu;
private FrameLayout leftMenu;
private FrameLayout rightMenu;
private Scroller mScroller;
public static final int ID = 0xaabbcc;
public MainUI(Context context) {
super(context);
initView(context);
}
public MainUI(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
private void initView(Context context) {
//初始化 布局。
this.context = context;
mScroller = new Scroller(context,new DecelerateInterpolator());
leftMenu = new FrameLayout(context);
rightMenu = new FrameLayout(context);
middleMenu = new FrameLayout(context);
middleMenu.setBackgroundColor(0xff547093);
rightMenu.setBackgroundColor(0xff673ab7);
leftMenu.setBackgroundColor(0xffe51c23);
rightMenu.setId(ID);
addView(leftMenu);
addView(middleMenu);
addView(rightMenu);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 三个布局的高宽。
middleMenu.measure(widthMeasureSpec, heightMeasureSpec);// 中间布局是屏幕的高宽。
// 左右菜单布局是0。8宽的屏幕, 高也是屏幕的高。
int realWith = MeasureSpec.getSize(widthMeasureSpec); // 获取屏幕宽
int tempWidth = MeasureSpec.makeMeasureSpec((int) (realWith * 0.8),
MeasureSpec.EXACTLY); // 屏幕宽*0.8
leftMenu.measure(tempWidth, heightMeasureSpec);
rightMenu.measure(tempWidth, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
// 三个布局的定位。 l=left t=top r=right b=button 都是屏幕的上下左右。
middleMenu.layout(l, t, r, b);
leftMenu.layout(l - leftMenu.getMeasuredWidth(), t, l, b);
rightMenu.layout(r, t, r + rightMenu.getMeasuredWidth(), b);
}
二。滑动操作。
private boolean isTestCompete; //是否有屏幕操作 默认false
private boolean isleftrightEvent; //是否是左右滑动事件 默认false
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (!isTestCompete) {
getEventType(ev); // 判断滑动的具体方向
return true;
}
if (isleftrightEvent) {
// 如果是左右滑动,屏幕会做如下滚动(scroll)
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_MOVE:
super.dispatchTouchEvent(ev);
int curScrollX = getScrollX(); // 屏幕滑动的距离
int dis_x = (int) ev.getX() - point.x; // 手滑动的距离
int expectX = -dis_x + curScrollX;
int finalX = 0;
if (expectX < 0) {
finalX = Math.max(expectX, -leftMenu.getMeasuredWidth());
} else {
finalX = Math.min(expectX, rightMenu.getMeasuredWidth());
}
scrollTo(finalX, 0);
point.x = (int) ev.getX();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
curScrollX = getScrollX();
super.dispatchTouchEvent(ev);
// 如果滑动超过左右菜单的 一半,则自动滑出左右菜单,否则退回。
if (Math.abs(curScrollX)>(leftMenu.getMeasuredWidth()/2)) {
if (curScrollX<0) {
mScroller.startScroll(curScrollX, 0, -leftMenu.getMeasuredWidth()-curScrollX, 0);
}else {
mScroller.startScroll(curScrollX, 0, leftMenu.getMeasuredWidth()-curScrollX, 0);
}
}else {
mScroller.startScroll(curScrollX, 0, -curScrollX, 0);
}
invalidate(); // 重绘view
isleftrightEvent = false;
isTestCompete = false;
break;
}
}else {
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_UP:
super.dispatchTouchEvent(ev);
isleftrightEvent = false;
isTestCompete = false;
break;
default:
break;
}
}
return super.dispatchTouchEvent(ev);
}
@Override
public void computeScroll() {
// 滑动的回调方法。实现滑动所必须的方法。
super.computeScroll();
if (!mScroller.computeScrollOffset() ) {
return ;
}
int tempX =mScroller.getCurrX();
scrollTo(tempX, 0);
}
private Point point = new Point();
private static final int TEST_DIS = 20; //最小滑动距离
private void getEventType(MotionEvent ev) {
//判断手势。
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN: // 按下时获取点
point.x = (int) ev.getX();
point.y = (int) ev.getY();
super.dispatchTouchEvent(ev);
break;
case MotionEvent.ACTION_MOVE: // 移动时,判断方向
int dx = Math.abs((int) ev.getX() - point.x);
int dy = Math.abs((int) ev.getY() - point.y);
super.dispatchTouchEvent(ev);
if (dx >= TEST_DIS && dx > dy) { // 左右滑动。(水平位移大于20dp,且水平滑动大于垂直滑动。)
isleftrightEvent = true;
isTestCompete = true;
point.x = (int) ev.getX();
point.y = (int) ev.getY();
} else if (dy >= TEST_DIS && dy > dx) { // 垂直滑动。(垂直位移大于20dp,且垂直滑动大于水平滑动)
isleftrightEvent = false;
isTestCompete = true;
point.x = (int) ev.getX();
point.y = (int) ev.getY();
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: // 抬起,或者滑到屏幕边缘是,初始化isleftrightEvent isTestCompete
super.dispatchTouchEvent(ev);
isleftrightEvent = false;
isTestCompete = false;
break;
default:
break;
}
}
}