转载请标明原地址:[http://blog.csdn.net/gaolei1201/article/details/50404941](http://blog.csdn.net/gaolei1201/article/details/50404941)
首先介绍本篇文章的重点:
1.视觉差侧滑菜单,即菜单和主界面都滑动,其实也比较常见。有开源项目SlidingMenu,但太复杂了,且在我使用过程中无法完美实现透明状态栏,中间会有一条分割线。看我简单实现
2.Activity视觉差动画
3.支持侧滑销毁Activity,且不用担心被子控件消耗手势监听事件
其实我也是借鉴别人的,自己发明创造毕竟毕竟困难。正所谓天下文章一大抄,看你会抄不会抄,呵呵。
这里侧滑菜单SlidingMenu继承HorizontalScrollView,手势滑动。还有一种方法时继承ViewGroup,放入菜单和内容两个子控件,根据手势滑动。
效果图:
![](https://box.kancloud.cn/2016-02-29_56d3fcdb8148d.jpg)
下面是侧滑菜单主要代码,里面有注释:
~~~
<span style="font-size:14px;">package com.gaolei.slidingmenu;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import com.example.zhy_slidingmenu.R;
import com.nineoldandroids.view.ViewHelper;
public class SlidingMenu extends HorizontalScrollView {
/**
* 屏幕宽度
*/
private int mScreenWidth;
/**
* dp
*/
private int mMenuRightPadding;
/**
* 菜单的宽度
*/
private int mMenuWidth;
private int mHalfMenuWidth;
public static boolean isOpen;
private boolean once;
private ViewGroup mMenu;
private ViewGroup mContent;
public SlidingMenu(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SlidingMenu(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
WindowManager mWM = ((WindowManager) context
.getSystemService(Context.WINDOW_SERVICE));
DisplayMetrics mDisplayMetrics = new DisplayMetrics();
mWM.getDefaultDisplay().getMetrics(mDisplayMetrics);
mScreenWidth = mDisplayMetrics.widthPixels;
TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
R.styleable.SlidingMenu, defStyle, 0);
int n = a.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = a.getIndex(i);
switch (attr) {
case R.styleable.SlidingMenu_rightPadding:
// 默认50
mMenuRightPadding = a.getDimensionPixelSize(attr,
(int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 50f,
getResources().getDisplayMetrics()));// 默认为10DP
// Log.d("gaolei","mMenuRightPadding-------------"+mMenuRightPadding);
break;
}
}
a.recycle();
}
public SlidingMenu(Context context) {
this(context, null, 0);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
/**
* 显示的设置一个宽度
*/
if (!once) {
LinearLayout wrapper = (LinearLayout) getChildAt(0);
mMenu = (ViewGroup) wrapper.getChildAt(0);
mContent = (ViewGroup) wrapper.getChildAt(1);
mMenuWidth = mScreenWidth - mMenuRightPadding;
mHalfMenuWidth = mMenuWidth / 2;
mMenu.getLayoutParams().width = mMenuWidth;
mContent.getLayoutParams().width = mScreenWidth;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (changed) {
// 将菜单隐藏
this.scrollTo(mMenuWidth, 0);
once = true;
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
// Up时,进行判断,如果显示区域大于菜单宽度一半则完全显示,否则隐藏
case MotionEvent.ACTION_UP:
int scrollX = getScrollX();
if (scrollX > mHalfMenuWidth) {
this.smoothScrollTo(mMenuWidth, 0);
isOpen = false;
MainActivity.shadow_layout.setVisibility(View.GONE);
} else {
this.smoothScrollTo(0, 0);
isOpen = true;
MainActivity.shadow_layout.setVisibility(View.VISIBLE);
}
return true;
case MotionEvent.ACTION_MOVE:
break;
}
return super.onTouchEvent(ev);
}
// 这里是拦截菜单布局滑动
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_MOVE:
final float curX = ev.getX();
final float curY = ev.getY();
if (curY > 0 && curY < 500) {
return false;
}
if (isOpen && curX < mMenuWidth) {
return false;
}
}
return super.onInterceptTouchEvent(ev);
}
/**
* 打开菜单
*/
public void openMenu() {
if (isOpen)
return;
this.smoothScrollTo(0, 0);
isOpen = true;
MainActivity.shadow_layout.setVisibility(View.VISIBLE);
}
/**
* 关闭菜单
*/
public void closeMenu() {
if (isOpen) {
this.smoothScrollTo(mMenuWidth, 0);
isOpen = false;
MainActivity.shadow_layout.setVisibility(View.GONE);
}
}
/**
* 切换菜单状态
*/
public void toggle() {
if (isOpen) {
closeMenu();
} else {
openMenu();
}
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
float scale = l * 1.0f / mMenuWidth;
~~~
~~~
//这段代码是最重要的调用nineoldandroids。jar 来实现菜单视觉差效果,自己可改动 0.7f 试试
ViewHelper.setTranslationX(mMenu, mMenuWidth * scale * 0.7f);
}
}
</span>
~~~
下面要讲一下,手势滑动Activity边缘销毁Activity,主要难点是:里面子控件会拦截手势事件使你监听不到,那么你也就不能触发销毁Activity,看看哥是咋弄的
~~~
<span style="font-size:14px;">/**
* 自定义RelativeLayout 拦截ListView监听事件
*/
public class CustomRelativeLayout extends RelativeLayout {
private FinishActivityListener finishActivityListener;
private int downX;
public void setFinishActivityListener(FinishActivityListener finishActivityListener) {
this.finishActivityListener = finishActivityListener;
}
public CustomRelativeLayout(Context context) {
super(context);
}
public CustomRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
//onTouchEvent()是获取不到手势事件的,因为被ListView消耗了;只有在这判断手势监听事件 ,才能提前ListView获得
public boolean onInterceptTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
//说明将onTouch拦截在此控件,进而执行此控件的onTouchEvent
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = (int) event.getRawX();
break;
case MotionEvent.ACTION_MOVE:
int moveX = (int) event.getRawX();
Log.d("gaolei", "moveX-----------------" + moveX);
Log.d("gaolei", "downX-----------------" + downX);
//这里是判断最小滑动5,然后滑动边缘0~50彩触发销毁Activity,滑动屏幕中间不销毁
if (moveX - downX > 5 && downX < 50) {
finishActivityListener.onFinishActivity();
}
break;
}
return super.onInterceptTouchEvent(event);
}
}
</span>
~~~
[源码地址,点击下载......](https://github.com/gaoleiandroid1201/ParallaxSlidingMenu)