码迷,mamicode.com
首页 > 其他好文 > 详细

自定义控件:侧滑菜单

时间:2015-06-05 22:39:11      阅读:180      评论:0      收藏:0      [点我收藏+]

标签:


侧滑面板很其实现在容易找到成熟的第三方框架了,但是我们自己做一下,写一些核心代码,有助于我们的理解


1,简单介绍

写一个类继承ViewGroup

复写以下三个方法

onMeasure -> onLayout -> onDraw

1,测量左面板和主面板

左面板宽是指定的值240, 高度是屏幕高度

主面板宽高就是屏幕的宽高

2,摆放两个子控件


左面板的位置: 当前屏幕左边界0, 往左-240

主面板位置 : 当前控件的位置

3,处理触摸事件 (左右移动两个控件)


按下时, 获取按下的坐标downX = 20

移动时,
获取当前最新x坐标 moveX = 30
计算要执行的偏移量 - (30 - 20) = -10
让偏移生效scrollBy(-10, 0)
moveX 赋值给 downX, 作为新的按下点
抬起时, 根据当前偏移位置, 执行动画 (执行平滑动画)


二,核心代码


/**
 * 侧滑面板
 * @author poplar
 *
 */
public class SlideMenu extends ViewGroup {

	
	private final int MAIN_CONTENT = 0; // 主面板状态
	private final int MENU_CONTENT = 1; // 左菜单状态
	
	int currentState = MAIN_CONTENT; // 当前状态

	private Scroller scroller;

	private int downX; // 按下的X值坐标
	private int downY; // 按下的Y值坐标

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

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

	public SlideMenu(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init();
	}
	

	private void init() {
		// 滚动模拟器
		
		scroller = new Scroller(getContext());
		
		// startX, x轴从什么位置开始滚动   -100
		// startY, y轴从什么位置开始滚动
		// dx, 	   从开始位置 到 目标位置的 偏移量 -100 -> 50  
				// 偏移量  150  = (50 - (-100))
				// 偏移量  = (目标位置 x) - (开始位置x)
		// dy,  
		// duration , 动画执行时长 dx * 10
		
//		scroller.startScroll(startX, startY, dx, dy, duration);
	}

	/**
	 * 测量子控件
	 * widthMeasureSpec : 当前控件的宽度属性
	 * heightMeasureSpec : 当前控件的高度属性
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		
		// 获取到左面板
		View leftMenu = getChildAt(0);
		// 宽度自身宽度, 高度屏幕的高度
		leftMenu.measure(leftMenu.getLayoutParams().width, heightMeasureSpec);
		
		// 测量主面板
		View main = getChildAt(1);
		main.measure(widthMeasureSpec, heightMeasureSpec);
		
	}

	/**
	 * 摆放两个子控件
	 * 
	 * left 控件左边界位置
	 * top  控件上边界位置
	 * right 控件右边界位置
	 * bottom 控件下边界位置
	 * 
	 */
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {

		// 摆放左面板
		View leftMenu = getChildAt(0);
		leftMenu.layout(0 - leftMenu.getMeasuredWidth(), 0, 0, b);
		
		// 摆放主面板
		View main = getChildAt(1);
		main.layout(l, t, r, b);
		
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			// 按下时的x坐标
			downX = (int) event.getX();

			break;
		case MotionEvent.ACTION_MOVE:
			// 移动后的x坐标
			int moveX = (int) event.getX();
			
			// 变化量
			int scrollX = - (moveX - downX);
			
			// ------------------------------------------------- 重点 ↓  
			
			// 计算变化后的位置
			int newScrollX = getScrollX() + scrollX;
			int leftLimit = -getChildAt(0).getMeasuredWidth();
			if(newScrollX < leftLimit){
				// < -240
				scrollTo(leftLimit, 0);
			} else if (newScrollX > 0) {
				// >0 限定右边界
				scrollTo(0, 0);
			} else {
				// 让变化量生效
				scrollBy(scrollX, 0);
			}
			
			// ------------------------------------------------- 以上 ↑
			
			//把上一个moveX赋值给downX
			downX = moveX;
			
			break;
		case MotionEvent.ACTION_UP:
			// 抬起时, 根据当前偏移位置, 执行动画
			int leftMenuCenter = - getChildAt(0).getMeasuredWidth() / 2;
			
			int currentScrollX = getScrollX();
			System.out.println("currentScrollX: " + currentScrollX);
			System.out.println("leftMenuCenter: " + leftMenuCenter);
			
			
			if(currentScrollX > leftMenuCenter){
				// 如果当前滚动的位置在一半的右边 , 显示主面板 , scrollX > leftMenuCenter
				currentState = MAIN_CONTENT;
				System.out.println("执行显示主面板动画");
				updateCurrentContent();
			}else {
				// 如果当前滚动的位置在一半的左边 , 显示左菜单 , scrollX <= leftMenuCenter
				currentState = MENU_CONTENT;
				System.out.println("执行显示左菜单动画");
				updateCurrentContent();
			}
			break;

		default:
			break;
		}
		
		
		return true;
	}

	private void updateCurrentContent() {
		int scrollX = getScrollX();
		
		int dx = 0;
		if(currentState == MAIN_CONTENT){
			// 执行动画,显示主面板
//			scrollTo(0, 0);
			
			// 目标值 - 当前值
			dx = 0 - scrollX;
			
		} else if(currentState == MENU_CONTENT){
			// 执行动画,显示左菜单
//			scrollTo(- getChildAt(0).getMeasuredWidth(), 0);
			
			// 目标值 - 当前值
			// - 240 - 
			dx = -getChildAt(0).getMeasuredWidth() - scrollX;
			System.out.println("dx: " + dx + " scrollX: " + scrollX);
		}
		
		// ------------------------------------------------- 重点 ↓  

		// 开始模拟数据
		scroller.startScroll(scrollX, 0, dx, 0, Math.abs(dx * 10));
		// -100 -> -240   >>  -150
		
		// 使scroller模拟的数据生效
		invalidate(); // drawChild -> child.draw( ->  computeScroll

		// ------------------------------------------------- 以上 ↑
		
	}
	// ------------------------------------------------- 重点 ↓  

	@Override
	public void computeScroll() {
		
		if(scroller.computeScrollOffset()){
			// 动画还没执行完
			
			// 得到当前模拟的数值
			int currX = scroller.getCurrX();
			scrollTo(currX, 0);
//			System.out.println("currX: " + currX);
			
			// 重绘界面, 递归调用
			invalidate();
		}
	}

	// ------------------------------------------------- 以上 ↑
	
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		// 只有在用户水平滑动的时候才拦截
		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();
				
				int diffX = Math.abs(moveX - downX);
				int diffY = Math.abs(moveY - downY);
				
				if(diffX > diffY && diffX > 10){
					return true;
				}
				break;
			case MotionEvent.ACTION_UP:
				
				break;
	
			default:
				break;
		}
		
		return super.onInterceptTouchEvent(ev);
	}
}





自定义控件:侧滑菜单

标签:

原文地址:http://blog.csdn.net/jinfulin/article/details/46382295

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!