SlidingMenu实现

2019-04-15 13:41发布

SlidingMenu


原理

SlidingMenu无非就是一个包含三个View的控件,左边View中间View(默认时全屏)右边View,默认的情况下中间View会把两边的View覆盖住,在手指滑动的时候,会根据手指的滑动方向以及滑动距离去移动中间的那个View,从而能让两边View完全可见。
在定义该View的时候,首先会想到继承RelativeLayout,能简单的实现这种左、中、右三个View的布局。
  1. 继承RelativeLayout
    1.  public class SlidingMenu extends RelativeLayout { 
    2.  
    3.      public SlidingMenu(Context context, AttributeSet attrs, int defStyle) { 
    4.          super(context, attrs, defStyle); 
    5.          init(context); 
    6.      } 
    7.  
    8.      public SlidingMenu(Context context, AttributeSet attrs) { 
    9.          super(context, attrs); 
    10.          init(context); 
    11.      } 
    12.  
    13.      public SlidingMenu(Context context) { 
    14.          super(context); 
    15.          init(context); 
    16.      } 
    17.  
    18.      private void init(Context context) { 
    19.          mContext = context; 
    20.          mScroller = new Scroller(context); 
    21.          mWindowWidth = getWindowWidth(context); 
    22.      } 
    23.  }
  2. 具体的三个View需要暴露给外界调用,所以我们要提供一个setView()的方法。
    1.  public void setView(View leftView, View rightView, View centerView, 
    2.          int leftViewWidth, int rightViewWidth) { 
    3.      //添加左边View 
    4.      RelativeLayout.LayoutParams leftParams = new LayoutParams( 
    5.              (int) convertDpToPixel(leftViewWidth, mContext), 
    6.              LayoutParams.MATCH_PARENT); 
    7.      leftParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT); 
    8.      addView(leftView, leftParams); 
    9.  
    10.      //右边的View 
    11.      RelativeLayout.LayoutParams rightParams = new LayoutParams( 
    12.              (int) convertDpToPixel(rightViewWidth, mContext), 
    13.              LayoutParams.MATCH_PARENT); 
    14.      rightParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); 
    15.      addView(rightView, rightParams); 
    16.  
    17.      //添加中间的View 
    18.      RelativeLayout.LayoutParams centerParams = new LayoutParams( 
    19.              LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); 
    20.      addView(centerView, centerParams); 
    21.  
    22.      mLeftView = leftView; 
    23.      mRightView = rightView; 
    24.      mCenterView = centerView; 
    25.  }
    外界使用SlidingMenu类的时候需要首先调用该方法去设置相应的View,一旦调用该方法后,我们就将布局设置完了,下一步就是对touch事件进行处理,然后去移动中间的View。
  3. 处理Touch事件 在手指按下的时候,我们去控制两边View的显示与隐藏
    1.  public boolean onInterceptTouchEvent(MotionEvent ev) { 
    2.      int x = (int) ev.getRawX(); 
    3.      int y = (int) ev.getRawY(); 
    4.  
    5.      int action = ev.getAction(); 
    6.  
    7.      switch (action) { 
    8.      case MotionEvent.ACTION_DOWN: 
    9.          mLastPostionX = x; 
    10.          mLastPostionY = y; 
    11.          //通过变量记录当前可以显示左边的View还是可以显示右边的View 
    12.          if (mCanLeftViewShow) { 
    13.              //如果当前,中间的View往右滑,那么这时候左边的View就要能显示了 
    14.              mLeftView.setVisibility(View.VISIBLE); 
    15.              mRightView.setVisibility(View.GONE); 
    16.          } else if (mCanRightViewShow) { 
    17.              mLeftView.setVisibility(View.GONE); 
    18.              mRightView.setVisibility(View.VISIBLE); 
    19.          } 
    20.  
    21.          break
    22.      case MotionEvent.ACTION_MOVE: 
    23.  
    24.          break
    25.      case MotionEvent.ACTION_UP: 
    26.  
    27.          break
    28.  
    29.      default
    30.          break
    31.      } 
    32.  
    33.      return false
    34.  }
onTouch()中,我们去获取手指移动的距离
  1.         public boolean onTouchEvent(MotionEvent event) { 
  2.         int x = (int) event.getRawX(); 
  3.         int y = (int) event.getRawY(); 
  4.  
  5.         int action = event.getAction(); 
  6.         switch (action) { 
  7.         case MotionEvent.ACTION_DOWN: 
  8.             mLastPostionX = x; 
  9.             mLastPostionY = y; 
  10.  
  11.             if (!mScroller.isFinished()) { 
  12.                 mScroller.abortAnimation(); 
  13.             } 
  14.  
  15.             break
  16.         case MotionEvent.ACTION_MOVE: 
  17.             int distance = x - mLastPostionX; 
  18.             int targetPositon = mCenterView.getScrollX() - distance; 
  19.             mLastPostionX = x; 
  20.  
  21.             if (mCanLeftViewShow) { 
  22.                 if (targetPositon > 0) { 
  23.                     targetPositon = 0
  24.                 } 
  25.  
  26.                 if (targetPositon < -mLeftViewWidth) { 
  27.                     targetPositon = -mLeftViewWidth; 
  28.                 } 
  29.             } 
  30.  
  31.             if (mCanRightViewShow) { 
  32.                 if (targetPositon < 0) { 
  33.                     targetPositon = 0
  34.                 } 
  35.  
  36.                 if (targetPositon > mRightViewWidth) { 
  37.                     targetPositon = mRightViewWidth; 
  38.                 } 
  39.             } 
  40.  
  41.             mClicked = false
  42.             //让中间的View随着手指的移动而移动 
  43.             mCenterView.scrollTo(targetPositon, 0); 
  44.  
  45.             break
  46.         case MotionEvent.ACTION_UP: 
  47.             //你手指移动后抬起的时候需要注意,如果现在左边的View已经超过一半可见了,这时候就算你抬起手指了,SlidingMenu也要滑动到右边让左边View完全可见。当然还有就是你滑动的飞快,然后突然抬起了手指,这时候就要进行速率的计算了,我们先不说速率 
  48.             int dx = 0
  49.             if (mCanLeftViewShow) { 
  50.                 if (mCenterView.getScrollX() <= -mLeftViewWidth / 2) { 
  51.                     //已经超过左边View的一般了,应该让中间View继续移动,移动到左边View完全可见 
  52.                     dx = -mLeftViewWidth - mCenterView.getScrollX(); 
  53.                 } else { 
  54.                     // 滚回原来的位置 
  55.                     dx = -mCenterView.getScrollX(); 
  56.                     resumeLeftViewClickState(); 
  57.                 } 
  58.  
  59.             } else if (mCanRightViewShow) { 
  60.                 if (mCenterView.getScrollX() >= mRightViewWidth / 2) { 
  61.                     dx = mRightViewWidth - mCenterView.getScrollX(); 
  62.                 } else { 
  63.                     dx = -mCenterView.getScrollX(); 
  64.                     resumeRightViewClickState(); 
  65.                 } 
  66.             } 
  67.             //手指抬起后,要让中间View有过程的滑过去,所以要用到Scroller类 
  68.             smoothScrollTo(dx); 
  69.             break
  70.  
  71.         default
  72.             break
  73.         } 
  74.  
  75.         return true
  76.     }
Scroller的实现
  1.  
  2.     private void smoothScrollTo(int distance) { 
  3.         mScroller.startScroll(mCenterView.getScrollX(), 0, distance, 0
  4.                 sDuration); 
  5.         invalidate(); 
  6.     } 
  7.  
  8.     @Override 
  9.     public void computeScroll() { 
  10.         if (mScroller.computeScrollOffset()) { 
  11.             mCenterView.scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); 
  12.             postInvalidate(); 
  13.         } 
  14.     }

  1. 到这里SlidingMenu的大体实现已经完成了剩下的就是对速率的计算,已经添加显示左边与显示右边的View的按钮。当左边View完全显示的时候,点击中间View可见部分时需要让中间View全屏。至于这些细节的东西就不再仔细说了,大家自己看源码吧。

源码:点击打开链接