自定义控件:侧滑菜单

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

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);
	}
}

时间: 2024-10-12 08:28:30

自定义控件:侧滑菜单的相关文章

Android自定义控件——侧滑菜单

转载请注明出处:http://blog.csdn.net/allen315410/article/details/39397445 当我们打开某些应用的时候,总是会出现"侧滑菜单"这样的效果,至于这种侧滑菜单是谁首先创造出来的,已经不重要,但是侧滑菜单确实功能新颖,用户体验极好,以至于市面上很多很多的应用也纷纷加入侧滑菜单的效果,以下是我从应用市场上下载来的几个应用,随时截图发在这里,看看别人(大型互联网公司)都做这种效果,那么我们自己在没有很好的"创意"下,是不是

Android组件——使用DrawerLayout仿网易新闻v4.4侧滑菜单

转载请注明出处:http://blog.csdn.net/allen315410/article/details/42914501 概述 今天这篇博客将记录一些关于DrawerLayout的基本用法,我想关于DrawerLayout的用法也许有不少不够了解,这也是比较正常的事情,因为DrawerLayout作为Android组件是Google后来在android中添加的,在android.support.v4包下.那么,DrawerLayout是一个怎么的组件呢?我们知道,当我们使用Androi

Android 实现形态各异的双向侧滑菜单 自定义控件来袭

1.概述 关于自定义控件侧滑已经写了两篇了~~今天决定把之前的单向改成双向,当然了,单纯的改动之前的代码也没意思,今天不仅 会把之前的单向改为双向,还会多添加一种侧滑效果,给大家带来若干种形态各异的双向侧滑菜单,不过请放心,代码会很简单~~然后根据这若干种,只要你喜 欢,相信你可以打造任何绚(bian)丽(tai)效果的双向侧滑菜单~~ 首先回顾一下,之前写过的各种侧滑菜单,为了不占据篇幅,就不贴图片了: 1.最普通的侧滑效果,请参考:Android 自定义控件打造史上最简单的侧滑菜单 2.仿Q

Android 高仿 QQ5.0 侧滑菜单效果 自定义控件来袭【学习鸿洋_视频博客笔记总结】

学习鸿洋博客:http://blog.csdn.net/lmj623565791/article/details/39257409 学习鸿洋视频:慕课网视频 看看Android 高仿 QQ5.0 侧滑菜单效果 自定义控件实现效果: 技术上,继承HorizontalScrollView 加上自定义ViewGroup来实现: 1.onMeasure:决定内部View(子View)的宽和高,以及自己的宽和高 2.onLayout:决定子View的放置位置 3.onTouchEvent[监听动作] 自定

Android 实现形态各异的双向侧滑菜单 自定义控件来袭(转载)

1.概述 关于自定义控件侧滑已经写了两篇了~~今天决定把之前的单向改成双向,当然了,单纯的改动之前的代码也没意思,今天不仅会把之前的单向改为双向,还会多添加一种侧滑效果,给大家带来若干种形态各异的双向侧滑菜单,不过请放心,代码会很简单~~然后根据这若干种,只要你喜欢,相信你可以打造任何绚(bian)丽(tai)效果的双向侧滑菜单~~ 2.目标效果 1.最普通的双向侧滑 是不是很模糊,嗯,没办法,电脑显卡弱.... 2.抽屉式双向侧滑 3.菜单在内容之下的双向侧滑 凑合看下,文章最后会提供源码下载

Android 高仿 QQ5.0 侧滑菜单效果 自定义控件来袭

1.原理分析 首先对比一下我们上篇的实现距离QQ的效果还有多远: 差距还是蛮大的 区别1.QQ的内容区域会伴随菜单的出现而缩小 区别2.QQ的侧滑菜单给人的感觉是隐藏在内容的后面,而不是拖出来的感觉 区别3.QQ的侧滑菜单有一个缩放以及透明度的效果~ 那么我们如何能做到呢: 对于区别1:这个好办,我们可以在滑动的时候,不断的改变内容区域的大小:如何改变呢?我们在菜单出现的整个过程中,不断记录菜单显示的宽度与其总宽度的比值,是个从0到1的过程,然后把0~1转化为1~0.7(假设内容区域缩小至0.7

彷QQ5.0侧滑菜单(自定义控件--SlideMenu的实现)

一般的侧滑的实现 ViewGroup  Menu + Content onTouchEvent MOVE:ViewGroup的leftMargin UP:根据显示菜单的高度,决定将其隐藏或者显示 1.Scroller 2.LeftMargin + Thread 彷QQ5.0侧滑菜单的实现,使用另外的一种方法,继承HorizontalScrollView 一.自定义ViewGroup 1.构造方法的选择,获得一些需要用到的值 2.onMeasure 计算子View的宽和高,以及设置自己的宽和高 3

Android 自定义控件打造史上最简单的侧滑菜单

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/39185641 ,本文出自[张鸿洋的博客] 侧滑菜单在很多应用中都会见到,最近QQ5.0侧滑还玩了点花样~~对于侧滑菜单,一般大家都会自定义ViewGroup,然后隐藏菜单栏,当手指滑动时,通过Scroller或者不断的改变leftMargin等实现:多少都有点复杂,完成以后还需要对滑动冲突等进行处理~~今天给大家带来一个简单的实现,史上最简单有点夸张,但是的确是我目前遇到过的最

Android侧滑菜单完整详细示例(改进版)

MainActivity如下: package cc.cd; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter;

Android DrawerLayout 高仿QQ5.2双向侧滑菜单

1.概述 之前写了一个Android 高仿 QQ5.0 侧滑菜单效果 自定义控件来袭 ,恰逢QQ5.2又加了一个右侧菜单,刚好看了下DrawerLayout,一方面官方的东西,我都比较感兴趣:另一方面,这玩意用起来的确方便,于是简单写了个demo,高仿QQ5.2双向侧滑,分享给大家. 首先看看效果图: DrawerLayout用起来真的很方便,下面一起看看用法~ 2.DrawerLayout的使用 直接将DrawerLayout作为根布局,然后其内部第一个View为内容区域,第二个View为左侧