自定义控件之侧拉菜单SlidingMenu

1.定义个类继承viewGroup

public class MySlidingMenu extends ViewGroup {

	private View menuView;
	private View mainView;
	private int menuWidth;
	private int downX;
	private int distance;
	private int currentstart;
	private Scroller scroller;
	private int downY;

	public MySlidingMenu(Context context) {
		// super(context);
		this(context, null);
	}

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

	public MySlidingMenu(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		// 将移动的距离拆分成一段一段的实现对象
		scroller = new Scroller(context);
	}

	// 测量
	// 1.自定义控件
	// 2.菜单页
	// 3.首页
	// widthMeasureSpec heightMeasureSpec : 当前控件的宽高
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// 1.自定义控件
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		// 测量菜单页和首页
		// 根据布局文件中的角标获取子控件的对象
		menuView = getChildAt(0);
		mainView = getChildAt(1);
		// 2.菜单页
		menuWidth = menuView.getLayoutParams().width;
		menuView.measure(menuWidth, heightMeasureSpec);
		// 3.首页
		mainView.measure(widthMeasureSpec, heightMeasureSpec);
	}

	// 排版
	// changed : 是否有最新的位置
	// l t r b : 控件的左上右下的位置
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		// 菜单页
		menuView.layout(l - 240, t, l, b);
		// 首页
		mainView.layout(l, t, r, b);
	}

	// 绘制
	@Override
	protected void onDraw(Canvas canvas) {
		// TODO Auto-generated method stub
		super.onDraw(canvas);
	}

	/**
	 * 缓慢滑动的
	 * 
	 * @param startX
	 *            : 开始的位置 toX : 结束的位置 2016-8-14 下午4:21:25
	 */
	private void scrollToTime(int startX, int toX) {
		// 将距离拆分成一段一段
		int dx = toX - startX;

		// 根据距离设置相应的时间
		// 获取每段距离所需时间
		int scale = 1000 / menuWidth;
		// 因为移动的距离可以能会是负数,但是时间是不能为负数
		int time = scale * Math.abs(dx);
		// startX, startY : 开始移动的位置
		// dx, dy : 移动的距离
		// duration : 持续的时间
		scroller.startScroll(startX, 0, dx, 0, time);
		invalidate();
	}

	/**
	 * 获取一段移动距离的操作
	 */
	@Override
	public void computeScroll() {
		if (scroller.computeScrollOffset()) {// 判断是否已经完成距离拆分操作
			int currX = scroller.getCurrX();// 获取一小段移动的距离
			// 移动一小段距离
			myScrollTo(currX);
			// 进行下一次移动距离操作
			invalidate();
		}
		super.computeScroll();
	}

	/**
	 * 封装了系统的scrollTo方法 2016-8-14 下午4:06:46
	 */
	private void myScrollTo(int x) {
		scrollTo(-x, 0);
	}

	/**
	 * 手动打开关闭侧拉菜单 2016-8-14 下午5:02:54
	 */
	public void toggle() {
		// 关闭 -> 打开
		// 打开 -> 关闭
		// 问题:如何知道侧拉菜单是打开还是关闭
		// 可以通过移动距离判断,如果是整个菜单页的宽度,表示打开,如果是0表示关闭
		// getScrollX();//获取x轴的移动距离,也是正负相反
		if (myGetScrollX() == 0) {
			// 关闭 -> 打开
			distance = 0;
			currentstart = menuWidth;
		} else {
			// 打开 -> 关闭
			distance = menuWidth;
			currentstart = 0;
		}
		// 移动操作
		scrollToTime(distance, currentstart);

	}

	public int myGetScrollX() {
		return -getScrollX();
	}

	// 事件分发操作,主要用来将触摸事件传递给子控件
	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
		// TODO Auto-generated method stub
		return super.dispatchTouchEvent(ev);
	}

	// 事件拦截操作,主要用来判断是否拦截事件,是否传递给子控件事件
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		//判断横向滑动还是竖向滑动,如果是横向滑动,拦截事件,如果是竖向滑动,放开事件不去拦截
		//可以根据x轴和y的轴距离来判断
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			downX = (int) ev.getX();
			downY = (int) ev.getY();
			break;
		case MotionEvent.ACTION_MOVE:
			int moveX = (int) ev.getX();
			int moveY = (int) ev.getY();
			//获取x轴和y轴的距离
			int distanceX = moveX - downX;
			int distanceY = moveY - downY;
			if (Math.abs(distanceX) > Math.abs(distanceY)) {
				return true;//拦截操作
			}
			break;
		case MotionEvent.ACTION_UP:

			break;
		}
		return super.onInterceptTouchEvent(ev);
	}

	// 侧拉菜单的滑动操作
	// 1.触摸事件
	// 2.移动相应的滑动距离
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			downX = (int) event.getX();
			break;
		case MotionEvent.ACTION_MOVE:
			int moveX = (int) event.getX();
			// 计算移动的距离
			distance = currentstart + moveX - downX;
			System.out.println(distance);
			// 2.控制滑动的范围
			if (distance < 0) {
				distance = 0;
			} else if (distance > menuWidth) {
				distance = menuWidth;
			}
			// 1.让侧拉菜单移动相应的距离
			// scrollTo(-distance, 0);//移动相应的x和y的距离
			myScrollTo(distance);
			break;
		case MotionEvent.ACTION_UP:
			// 3.保存当前滑动的位置,当下一次滑动的时候,从保存的位置开始滑动相应的距离
			// currentstart = distance;
			// 4.实现自动滑动操作,根据菜单页的宽度的一半来进行计算的
			if (distance < menuWidth / 2) {
				// myScrollTo(0);
				// 因为自动滑动到了0的位置,所以下一次滑动的时候,要从0的位置开始滑动
				currentstart = 0;
			} else {
				// myScrollTo(menuWidth);
				currentstart = menuWidth;
			}
			// 6.自动滑动的时候,实现缓慢滑动
			scrollToTime(distance, currentstart);
			break;
		}
		return true;
	}

}
2.布局文件activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
     >

    <com.itheima.slidingmenu.ui.MySlidingMenu
        android:id="@+id/myslidingmenu"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >
        <!-- 添加首页和菜单页的布局 -->
        <!-- include : 将其他的布局文件嵌入到当前的布局文件中 -->
        <include layout="@layout/menu"/>
        
        <include layout="@layout/main"/>
        
    </com.itheima.slidingmenu.ui.MySlidingMenu>
    
</RelativeLayout>

3.activity显示

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);//去除标题栏,必须放在setContentView之前执行,只在当前的activity生效
        setContentView(R.layout.activity_main);
        initView();
    }
    /**
     * 初始化控件
     * 2016-8-14 下午5:01:43
     */
    private void initView() {
		ImageView mBack = (ImageView) findViewById(R.id.back);
		final MySlidingMenu mMySlidingMenu = (MySlidingMenu) findViewById(R.id.myslidingmenu);
		mBack.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				//手动打开关闭侧拉菜单
				mMySlidingMenu.toggle();
			}
		});
	}
	/**
     * 菜单页的textview的点击事件
     * @param
     * 		view : 被点击的控件的view对象
     * 2016-8-14 下午3:52:14
     */
    public void showText(View view){
    	TextView textView = (TextView)view;
    	//toast显示文本
    	Toast.makeText(this, textView.getText(), 0).show();
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值