Android自定义组件系列【四】——自定义ViewGroup实现双侧滑动

Android自定义组件系列【4】——自定义ViewGroup实现双侧滑动

在上一篇文章《Android自定义组件系列【3】——自定义ViewGroup实现侧滑》中实现了仿Facebook和人人网的侧滑效果,这一篇我们将接着上一篇来实现双面滑动的效果。

1、布局示意图:

Android自定义组件系列【四】——自定义ViewGroup实现双侧滑动

2、核心代码

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		mWidth = MeasureSpec.getSize(widthMeasureSpec);  //获取MyScrollView的宽度
		mHeight = MeasureSpec.getSize(heightMeasureSpec); //获取MyScrollView的高度
		if(!isLocked){
			initX = getScrollX();
			isLocked = true;
		}
	}
在该方法中获取到初始的视图坐标偏移量getScrollX()

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		float x = event.getX();
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			System.out.println("ACTION_DOWN");
			mDownX = x;          //记录按下时的x坐标
			break;
		case MotionEvent.ACTION_UP:
			System.out.println("ACTION_UP");
			int dis = (int) (x - mDownX);   //滑动的距离
			if(Math.abs(dis) > (mWidth * mMenuWeight / 2)){
				if(dis > 0){          //如果>0则是向右滑动
					toRightMove();
				}else{				  //如果<0则是向左滑动
					toLeftMove();
				}
			}
			break;
		default:
			break;
		}
		
		return true;
	}
监听函数记录下按下和移动的屏幕坐标,求差计算出移动距离,如果这个距离大于阀值 (mWidth * mMenuWeight / 2)则滑动
	public void toRightMove(){
		 System.out.println("maxRight = " + maxRight);
		 System.out.println("X = "  + getScrollX());
		 if(getScrollX() >= initX){
			 int dx = (int)(mWidth * mMenuWeight);
			 mScroller.startScroll(getScrollX(), 0, -dx, 0, 500);
			 if(mListener != null){
				 mListener.onChanged();
			 }
			 invalidate();
		 }
	}
如果是向右滑动则,如果当前是初始位置(centerView在中间)则可以向右滑动(getScrollX == initX),或者当前左边View可以看见,则可以向右滑动将centerView移动到中间(getScrollX > initX).同理有向左滑动的方法。
	public void toLeftMove(){
		System.out.println("maxLeft = " + maxLeft);
		 System.out.println("X = "  + getScrollX());
		if(getScrollX() <= initX){
			int dx = (int)(mWidth * mMenuWeight);
			mScroller.startScroll(getScrollX(), 0, dx, 0, 500);
			if(mListener != null){
				mListener.onChanged();
			}
			invalidate();
		}
	}
3、全部代码

MyScrollView.java

package com.example.testscrollto;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.Scroller;

public class MyScrollView extends LinearLayout{
	
	private Context mContext;
	private int mWidth;
	private int mHeight;
	
	private float mMenuWeight = 3.0f / 5; //菜单界面比例
	
	private View mMenuView;   //菜单界面
	private View mPriView;	  //内容界面
	private View mRightView;  //右边界面
	
	private int maxLeft;
	private int maxRight;
	private int initX;
	
	private boolean isLocked = false;
	
	private Scroller mScroller;
	
	private OnMenuChangedListener mListener;
	
	public MyScrollView(Context context, AttributeSet attrs) {
		super(context, attrs);
		mContext = context;
		mScroller = new Scroller(mContext);
		
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		super.onLayout(changed, l, t, r, b);
		mMenuView.layout(-(int)(mWidth * mMenuWeight), 0, 0, mHeight);
		mPriView.layout(0, 0, mWidth, mHeight);
		mRightView.layout(mWidth, 0, mWidth + (int)(mWidth * mMenuWeight), mHeight);
	}
	
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		mWidth = MeasureSpec.getSize(widthMeasureSpec);  //获取MyScrollView的宽度
		mHeight = MeasureSpec.getSize(heightMeasureSpec); //获取MyScrollView的高度
		if(!isLocked){
			initX = getScrollX();
			isLocked = true;
		}
	}
	
	/**设置右滑的菜单View*/
	public void setMenu(View menu){
		mMenuView = menu;
		addView(mMenuView);
	}
	
	/**
	 * 设置主界面View
	 */
	public void setPrimary(View primary){
		mPriView = primary;
		addView(mPriView);
	}
	
	public void setRightView(View rightview){
		mRightView = rightview;
		addView(mRightView);
	}
	
	private float mDownX;
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		float x = event.getX();
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			System.out.println("ACTION_DOWN");
			mDownX = x;          //记录按下时的x坐标
			break;
		case MotionEvent.ACTION_UP:
			System.out.println("ACTION_UP");
			int dis = (int) (x - mDownX);   //滑动的距离
			if(Math.abs(dis) > (mWidth * mMenuWeight / 2)){
				if(dis > 0){          //如果>0则是向右滑动
					toRightMove();
				}else{				  //如果<0则是向左滑动
					toLeftMove();
				}
			}
			break;
		default:
			break;
		}
		
		return true;
	}
	
	@Override
	public void computeScroll() {
		super.computeScroll();
		if(mScroller.computeScrollOffset()){
			scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
			postInvalidate();
		}
	}
	
	
	public void toRightMove(){
		 System.out.println("maxRight = " + maxRight);
		 System.out.println("X = "  + getScrollX());
		 if(getScrollX() >= initX){
			 int dx = (int)(mWidth * mMenuWeight);
			 mScroller.startScroll(getScrollX(), 0, -dx, 0, 500);
			 if(mListener != null){
				 mListener.onChanged();
			 }
			 invalidate();
		 }
	}
	
	
	public void toLeftMove(){
		System.out.println("maxLeft = " + maxLeft);
		 System.out.println("X = "  + getScrollX());
		if(getScrollX() <= initX){
			int dx = (int)(mWidth * mMenuWeight);
			mScroller.startScroll(getScrollX(), 0, dx, 0, 500);
			if(mListener != null){
				mListener.onChanged();
			}
			invalidate();
		}
	}
	

	 
	public interface OnMenuChangedListener{
		 public void onChanged();
	}	
	
	public void setOnMenuChangedListener(OnMenuChangedListener listener){
		mListener = listener;
	}
}
MainActivity.java
package com.example.testscrollto;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;

import com.example.testscrollto.MyScrollView.OnMenuChangedListener;

public class MainActivity extends Activity {
	
	private MyScrollView mScrollView;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		mScrollView = (MyScrollView)findViewById(R.id.rightscrollview);
		final View menu = getLayoutInflater().inflate(R.layout.rightscrollview_menu, null);
		final View primary = getLayoutInflater().inflate(R.layout.rightscrollview_primary, null);
		final View rightview = getLayoutInflater().inflate(R.layout.rightscrollview_right_menu, null);
		mScrollView.setMenu(menu);
		mScrollView.setPrimary(primary);
		mScrollView.setRightView(rightview);
		mScrollView.setOnMenuChangedListener(new OnMenuChangedListener() {
			
			@Override
			public void onChanged() {
				System.out.println("窗口切换了一次");
			}
		});
	}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    
    <com.example.testscrollto.MyScrollView
        android:id="@+id/rightscrollview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>
其余三个视图界面无限制,可以*定义,这里就不贴出来了。

4、运行效果:

Android自定义组件系列【四】——自定义ViewGroup实现双侧滑动


源代码下载:http://download.csdn.net/detail/lxq_xsyu/7232701