slidingMenu 详解,快速实现左右滑动

先上效果图:(宽度是自适应的)


一步一步来啦!

工程的结构:


(1)布局文件,这里需要四个layout布局文件,left.xml,right.xml,center.xml和启动用的activity_main.xml

启动layout布局文件 activity_main.xml 代码如下,

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    tools:context=".MainActivity" >
    
    <com.zhong.haolin_my_view.ui.MySlidingMenu
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:id="@+id/MySlidingMenu">
    </com.zhong.haolin_my_view.ui.MySlidingMenu>

</FrameLayout>
主界面布局文件 center.xml 代码如下:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@+id/center_fragment" 
    android:background="@color/bg">
    
    <TextView 
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:text="中间center"/>

    <Button
        android:id="@+id/button1"
        android:layout_width="130dip"
        android:layout_height="wrap_content"
        android:layout_marginTop="220dip"
        android:text="Button" />

    <Button
        android:id="@+id/button2"
        android:layout_width="130dip"
        android:layout_height="wrap_content"
        android:text="Button"
         android:layout_marginTop="120dip"
          android:layout_marginLeft="80dip" />

</FrameLayout>
左侧菜单布局文件 left.xml 代码如下:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" 
    android:id="@+id/left_fragment"
    android:background="@color/bg_left">
    
  <TextView 
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:text="左边菜单left"/>
</FrameLayout>
右侧菜单布局文件 right.xml 代码如下:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" 
    android:id="@+id/right_fragment"
    android:background="@color/bg_right">
    
<TextView 
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:text="右边菜单right"/>
</FrameLayout>
(2)启动类MainActivity.java 代码如下:

public class MainActivity extends FragmentActivity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		final MySlidingMenu slidingMenu = (MySlidingMenu)findViewById(R.id.MySlidingMenu);
		slidingMenu.setView(
				getLayoutInflater().inflate(R.layout.left, null),
				getLayoutInflater().inflate(R.layout.right, null),
				getLayoutInflater().inflate(R.layout.center, null));

		
		Button button = (Button)findViewById(R.id.button1);
		button.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				slidingMenu.showLeft();
			}
		});
		Button button2 = (Button)findViewById(R.id.button2);
		button2.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				slidingMenu.showRight();
			}
		});
		
	}
}

(3)MySlidingMenu滑动类,继承自RelativeLayout,有两层布局,第一层是LeftLayout和RightLayout,第二层是MySlidingView,其实也就是一个FramLayout,代码如下:

public class MySlidingMenu extends RelativeLayout {
	/**
	 * 左边菜单
	 */
	private View LeftLayout;
	/**
	 * 右边菜单
	 */
	private View rightLayout;
	/*
	 * 主界面
	 */
	private MySlidingView contenerlayout;

	public MySlidingMenu(Context context) {
		super(context);
	}

	public MySlidingMenu(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public MySlidingMenu(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}
	// 添加左菜单
	private void setLeftLatout(View view){
		LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.FILL_PARENT);
		layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
		super.addView(view, layoutParams);
		LeftLayout = view;
	}
	// 添加右菜单
	private void setRightLayout(View view){
		LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.FILL_PARENT);
		layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
		super.addView(view, layoutParams);
		rightLayout = view;
	}
	// 添加主界面
	private void setContenerLayout(View view){
		LayoutParams layoutParams = new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT);
		contenerlayout = new MySlidingView(getContext());
		super.addView(contenerlayout, layoutParams);
		contenerlayout.setView(view);
		contenerlayout.setLeftLayout(LeftLayout);
		contenerlayout.setRightlayout(rightLayout);
		contenerlayout.invalidate();
	}
	// 添加左菜单,右菜单,主界面
	public void setView(View leftView, View rightView, View mainView){
		setLeftLatout(leftView);
		setRightLayout(rightView);
		setContenerLayout(mainView);
	}
	// 显示左菜单
	public void showLeft(){
		contenerlayout.showLeftView();
	}
	// 显示右菜单
	public void showRight(){
		contenerlayout.showRightView();
	}

}
上面的代码还是比较简单,接下来才是重头菜,真正实现滑动的MySlidingView
(4)MySlidingView.java 代码如下:

public class MySlidingView extends ViewGroup {
    /**
     * 主布局
     */
    private FrameLayout mContainer;
    /**
     * 超过此距离,控件才允许滑动
     */
    private int mTouchSlop;
     /**
      * 记录是否能滑动布局
      */
    private boolean mIsBeingDragged ;
    /**
     * 记录最后的一次触屏
     */
    private float mLastMotionX ;
    private float mLastMotionY ;
    /**
     * 平滑组件
     */
    private Scroller mScroller;
    /**
     * 左侧菜单
     */
    private View leftLayout;
    /**
     * 右侧菜单
     */
    private View rightlayout;
    /**
     * 速度
     */
	private static final int SNAP_VELOCITY = 100;

	public MySlidingView(Context context) {
		super(context);
		init();
	}

	public MySlidingView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}

	public MySlidingView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init();
	}
	// 同时绘制mContainer
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		// L.i(getClass(), "onMeasure[widthMeasureSpec:"+widthMeasureSpec+",heightMeasureSpec:"+heightMeasureSpec+"]");
		mContainer.measure(widthMeasureSpec, heightMeasureSpec);
	}

	@Override
	protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
		// L.i(getClass(), "onLayout[changed:"+changed+",left:"+left+",top:"+top+",right:"+right+",bottom:"+bottom+"]");
		int width = right - left;
		int height = bottom - top;
		mContainer.layout(0, 0, width, height);
	}
	
	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
	}
	// end
	
	private void init(){
		mContainer = new FrameLayout(getContext());
		mScroller = new Scroller(getContext());
		mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
		super.addView(mContainer);
	}
	
	public void setView(View view) {
		if(mContainer.getChildCount() > 0)
			mContainer.removeAllViews();
		mContainer.addView(view);
	}
	
	@Override
	public void scrollTo(int x, int y) {
		super.scrollTo(x, y);
		postInvalidate();// 刷新UI可以在UI中刷新
	}
	// 整个viewgroup一起滑动
	@Override
	public void computeScroll() {
		if (!mScroller.isFinished()) {
			if (mScroller.computeScrollOffset()) {
				int oldX = getScrollX();
				int oldY = getScrollY();
				int x = mScroller.getCurrX();
				int y = mScroller.getCurrY();
				if (oldX != x || oldY != y) {
					scrollTo(x, y);
				}
				// Keep on drawing until the animation has finished.
				invalidate();
			} else {
				clearChildrenCache();
			}
		} else {
			clearChildrenCache();
		}
	}
	
    // 手指滑动检测,来决定viewgroup是否能滑动
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		final int action = ev.getAction();
		final float x = ev.getX();
		final float y = ev.getY();
		switch (action) {
		case MotionEvent.ACTION_DOWN:
			// 记录触摸位置
			mLastMotionX = x;
			mLastMotionY = y;
			mIsBeingDragged = false;
			break;
		case MotionEvent.ACTION_MOVE:
			final float dx = x - mLastMotionX;
			final float xDiff = Math.abs(dx);
			final float yDiff = Math.abs(y - mLastMotionY);
			// xDiff 要大于系统设置的这个距离,控件才能移动
			// xDiff > yDiff 手指是否滑动
			if (xDiff > mTouchSlop && xDiff > yDiff) {
				mIsBeingDragged = true;
				mLastMotionX = x;
			}
			break;
		}
		return mIsBeingDragged;
	}

	// 滑动
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// 添加速度组件跟踪速度变化,计算出event的瞬时伪速度.再此不使用
//		if(mVelocityTracker == null)
//			mVelocityTracker = VelocityTracker.obtain();
//		mVelocityTracker.addMovement(event);
		
		final float x = event.getX();
		final float y = event.getY();
		
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			// 正在滑动时,强制停止滑动
			if(!mScroller.isFinished())
				mScroller.abortAnimation();
			mLastMotionX = x;
			mLastMotionY = y;
			break;
		case MotionEvent.ACTION_CANCEL:
		case MotionEvent.ACTION_MOVE:
			if(mIsBeingDragged){
				final float disX = mLastMotionX - x;//手指滑动的距离
				mLastMotionX = x;
				float oldScroll = getScrollX();     //现有的位置坐标
				float scrollX = oldScroll + disX;   //要滑动到的坐标
				// 向右滑,显示左界面
				if(disX<0 && scrollX<0){
					// L.i(getClass(), "[ 向右滑,显示左界面  ]");
					float leftBound  = -leftLayout.getWidth();
					float rightBound = 0;
					if(scrollX > rightBound) scrollX = rightBound;
					if(scrollX < leftBound) scrollX = leftBound;
				}
				// 想左滑,显示右界面
				else if(disX>0 && scrollX>0){
					// L.i(getClass(), "[ 向左滑,显示右界面  ]");
					float leftBound  = 0;
					float rightBound = rightlayout.getWidth();
					if(scrollX<leftBound) scrollX = leftBound;
					if(scrollX>rightBound) scrollX = rightBound; 
				}
				// L.i(getClass(), "scrollTo[scrollX:"+scrollX+"]");
				// 主要用于滑动和绝对固定,否则会超出左右菜单的边界
				scrollTo((int) scrollX, getScrollY());
			}
			break;
		case MotionEvent.ACTION_UP:
			if (mIsBeingDragged) {
				int oldScroll = getScrollX();
				int dx = 0;
//				L.i(getClass(), "ACTION_MOVE[oldScroll:"+oldScroll+",volecityX:"+volecityX+"]");
//				L.i(getClass(), "ACTION_MOVE[leftLayout.getWidth() / 2:"+leftLayout.getWidth() / 2
//						+",rightlayout.getWidth() / 2:"+rightlayout.getWidth() / 2+"]");
				 
				if(oldScroll < 0){
					// 显示左边菜单
					if(oldScroll < -leftLayout.getWidth() / 2  ){  
						dx = -leftLayout.getWidth() - oldScroll;
						// L.i(getClass(), "ACTION_MOVE[显示左边菜单]");
					}
					// 回归原位
					else if(oldScroll >= -leftLayout.getWidth() / 2  ){
						dx = - oldScroll;
						// L.i(getClass(), "ACTION_MOVE[显示左边菜单    回归原位]");
					}
				}
				// 判断往左滑
				else{
					// 显示右边菜单
					if(oldScroll > rightlayout.getWidth() / 2  ){
						 dx = rightlayout.getWidth() - oldScroll;
						 // L.i(getClass(), "ACTION_MOVE[显示右边菜单]");
					}
					 // 回归原位
					 else if(oldScroll <= rightlayout.getWidth() / 2  ){
						dx = -oldScroll;
						// L.i(getClass(), "ACTION_MOVE[显示右边菜单           回归原位]");
					}
				}
				// L.i(getClass(), "ACTION_MOVE[dx:"+dx+"]");
				// 保证只有三种状态。显示左界面、主界面、右界面中的一种,而不是只显示界面的一半
				// 移动dx距离
				smoothScrollTo(dx);
				clearChildrenCache();
			}
			break;
		}
		 
		
		return true;
		
	}

	// ViewGroup 平滑
	void smoothScrollTo(int dx) {
		int duration = 500;
		mScroller.startScroll(getScrollX(), getScrollY(), dx, getScrollY(), duration);
		invalidate();
	}
	// 显示左边菜单
	public void showLeftView(){
		// L.i(getClass(), "showLeftView()");
		int x = getScrollX();
		int leftWith = leftLayout.getWidth();
		if(x == 0){// 展开左菜单
			smoothScrollTo(-leftWith);
		}//已经展开左菜单了,收缩左菜单
		else if(x == -leftWith){
			smoothScrollTo(leftWith);
		}
	}
	// 显示右边菜单
	public void showRightView(){
		// L.i(getClass(), "showRightView()");
		int x = getScrollX();
		int rightWidth = rightlayout.getWidth();
		if(x == 0){// 展开右菜单
			smoothScrollTo(rightWidth);
		}//已经展开右菜单了,收缩右菜单
		else if(x == rightWidth){
			smoothScrollTo(-rightWidth);
		}
	}
	
	// 设置允许绘制
	void enableChildrenCache(){
		int childCount = getChildCount();
		for(int i=0;i < childCount;i++){
			final View view = getChildAt(i);
			view.setDrawingCacheEnabled(true);
		}
	}
	// 设置不允许绘制
	void clearChildrenCache(){
		int childCount = getChildCount();
		for(int i=0;i<childCount;i++){
			final View view = getChildAt(i);
			view.setDrawingCacheEnabled(false);
		}
	}
	

	public View getLeftLayout() {
		return leftLayout;
	}

	public void setLeftLayout(View leftLayout) {
		this.leftLayout = leftLayout;
	}

	public View getRightlayout() {
		return rightlayout;
	}

	public void setRightlayout(View rightlayout) {
		this.rightlayout = rightlayout;
	}
}

打完收工。see you !


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值