ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
转载请标明原地址:[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)