上篇博客咱们用动画实现了侧滑菜单,如果感兴趣可以通过传送门去看一下。今天咱们通过另一种方式实现侧滑菜单
一、布局
总布局
<?xml version="1.0" encoding="utf-8"?>
<com.yushan.slidemenu.SlideMenu xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/slideMenu"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="@+id/dl_secondary"
layout="@layout/layout_secondary" />
<include
android:id="@+id/dl_main"
layout="@layout/layout_main" />
</com.yushan.slidemenu.SlideMenu>
这里的布局和动画实现的基本上没有区别,但是由于动画实现的SlidingMenu继承的是FrameLayout,而这次的SlidingMenu继承的是ViewGroup。所以样式如下:
二、SlidingMenu实现
- 重写构造方法
public SlideMenu(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
public SlideMenu(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public SlideMenu(Context context) {
super(context);
init(context);
}
private void init(Context context) {
scroller = new Scroller(context);
}
- 测量放置子控件
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
menuView = getChildAt(0);
menuViewWidth = menuView.getLayoutParams().width;
menuView.measure(menuViewWidth, heightMeasureSpec);
mainView = getChildAt(1);
mainView.measure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean bl, int l, int t, int r, int b) {
menuView.layout(l - menuViewWidth, t, l, b);
mainView.layout(l, t, r, b);
}
- 重写onTouchEvent方法
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = event.getX();
break;
case MotionEvent.ACTION_MOVE:
distanceY = event.getX() - downX;
if (distanceY > 10) {
hasMove = true;
} else {
hasMove = false;
}
if (distanceY < 0) {
distanceY = 0;
} else if (distanceY > menuViewWidth) {
distanceY = menuViewWidth;
}
scrollTo((int) distanceY);
break;
case MotionEvent.ACTION_UP:
if (hasMove) {
if (distanceY > menuViewWidth / 2) {
oldDistanceY = menuViewWidth;
mState = DragState.Open;
} else {
oldDistanceY = 0;
mState = DragState.Close;
}
int startX = (int) distanceY;
int destX = (int) oldDistanceY;
animationScroll(startX, destX);
} else {
if (mState != DragState.Close) {
showMenu();
}
}
hasMove = false;
break;
}
return true;
}
- 点击按钮显示/隐藏侧滑菜单
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.iv_menu:
slideMenu.showMenu();
break;
}
}
SlidingMenu中代码:
/**
* 方法功能:侧拉菜单的显示与隐藏
*/
public void showMenu() {
int startX;
int destX;
if (oldDistanceY > 0) {
startX = menuViewWidth;
destX = 0;
mState = DragState.Close;
} else {
startX = 0;
destX = menuViewWidth;
mState = DragState.Open;
}
oldDistanceY = destX;
animationScroll(startX, destX);
}
- 侧滑菜单的自动归位
/**
* 方法功能:自动归位
*
* @param startX
* @param destX
*/
private void animationScroll(int startX, int destX) {
int distanceX = destX - startX;
int startY = 0;
int distanceY = 0;
float maxDuration = 1000f;
float maxMoveDistance = menuViewWidth;
float scale = maxDuration / maxMoveDistance;
int duration = (int) (Math.abs(distanceX) - scale);
scroller.startScroll(startX, startY, distanceX, distanceY, duration);
invalidate();
}
这里道长用到了invalidate()这个方法重新绘制界面。但是需要注意的是:invalidate()方法不能直接在子线程中调用。Android UI操作并不是线程安全的,并且这些操作必须在UI线程中调用。子线程中刷新界面可以通过Handler来通知UI线程调用invalidate()来进行界面更新。当然API提供了另一个方法来实现子线程中刷新界面的方法postInvalidate()。使用postInvalidate()刷新界面可以直接在子线程中调用postInvalidate()。
到这里侧滑菜单就实现了,这种实现方式与侧滑菜单实现的最大的区别在于事件拦截操作方式,希望这篇博客可以给你提供一些帮助。下面是Demo的链接,如果需要可以去github下载