为 android, ipad, surface 写的swipe旋转菜单效果 没有整理, 将就着看

7 篇文章 0 订阅

为 android, ipad, surface 写的swipe旋转菜单效果, 代码很乱, 没有整理, 将就着看.

复制成html直接运行就可以.


<!DOCTYPE HTML>
<html>
 <head>
  <title> New Document </title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
  <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>

  <script>
jQuery(function(){
	"use strict";
	var c = {
		stylePosition: $("#navSliderBlockStyle"),
		radius: window.screen.width / 10,
		pathCount: 20,		// 动画路径数量
		pathArray: null,		// 路径座标
		items: $("#navSliderBlock > div"),
		itemCount: 0};		// 图标链接数量
		c.itemCount = c.items.length;

	var CP="-webkit-",	// css transform name
		screen = [window.screen.width, window.screen.height],	// 屏幕大小
		superSwipe = window.screen.width*0.6,	// 长距离判断
		duration = 350;

	if (window.MSCSSMatrix != null){CP="-ms-";}

	c.transform = function(x,y,lite){
		if(lite===true){
			return "translate("+x+"px,"+y+"px)";
		}else{
			return CP+"transform:translate("+x+"px,"+y+"px)";
		}

	};

	/**
	* 按点阵索引获取需要的百分比, 索引圆从下方,逆时针计算
	* hor 没有设置的时候, 按 0 <- 1/2 -> 1,一半的时候是最低地, 索引 0 位置的达到100, 即圆的下方
	* hor == true 设置为真的时候,按 0 -> 1/4 <- 1/2 -> 3/4 <- 1 排列, 索引 1/4, 3/4 为最高100, 即圆的左右两边最高
	*/
	c.getLevel = function(pointIndex, hor){
		var oriIndex = pointIndex;
		var half = c.pathCount / 2;
		if (hor == undefined){
			pointIndex -= half;
			pointIndex = Math.abs(pointIndex);
			return Math.ceil(pointIndex / half * 100);
		}else{
			var halfAgain = half / 2;
			pointIndex -= half;
			pointIndex = Math.abs(pointIndex);
			pointIndex -= halfAgain;
			pointIndex = Math.abs(pointIndex);
			pointIndex = halfAgain - pointIndex;
			pointIndex *= half < oriIndex ? -1 : 1;
			return pointIndex / halfAgain * 100;
		}
	};

	c.getIndex = function(pointIndex){
		return c.getLevel(pointIndex);
	};

	c.getAlpha = function(pointIndex){
		return c.getLevel(pointIndex) / 100 * 0.5 + 0.5;
	};

	c.getSkewX = function(pointIndex){
		return Math.ceil(c.getLevel(pointIndex, true) / -10);
	};

	// 查找当前元素translate偏移座标最近的关键帧
	c.currentElePoint = function(element){
		var curTransform = null;
		if (window.MSCSSMatrix){
			curTransform = new MSCSSMatrix(window.getComputedStyle(element).msTransform);
		}else if(window.WebKitCSSMatrix){
			curTransform = new WebKitCSSMatrix(window.getComputedStyle(element).webkitTransform);
		}
		var xy = [curTransform.m41,curTransform.m42];
		var pathPoint = 0, last = Math.abs(c.pathArray[0][0] - xy[0]) + Math.abs(c.pathArray[0][1] - xy[1]), temp;
		for(var i = 1 ;i < c.pathArray.length; i++){
			temp = Math.abs(c.pathArray[i][0] - xy[0]) + Math.abs(c.pathArray[i][1] - xy[1]);
			if (last > temp){
				last = temp;
				pathPoint = i;
			}
		}
		return pathPoint;
	};

	// 查找最近的链接点
	c.keyPath = function(pathPoint){
		pathPoint = pathPoint % c.pathCount;
		pathPoint = Math.round(pathPoint / (c.pathCount / c.itemCount));
		if (pathPoint == c.itemCount){pathPoint = 0;}
		pathPoint *= (c.pathCount / c.itemCount);
		if (pathPoint == c.pathCount){pathPoint = 0;}
		return pathPoint;
	};

	c.keyPathDistance = function(start, away){
		var space = Math.ceil(c.pathCount / c.itemCount);
		var offset = ( start + Math.abs(away) ) % space;
		if (away < 0){
			away -= offset;
		}else{
			away += offset;
		}
		/*
		var offset = ( start + away ) % space;
		if (offset > space / 2){
			offset = space - offset;
		}
		away += offset;
		*/
		return away;
	};

	c.addStyle = function(style){
		c.stylePosition.append(style);
	};

	c.clearStyle = function(){
		c.stylePosition.empty();
	}

	// strength 单位是 数组pathArray长度之一
	c.animateSet = function(jq, duration, strength, release){
		var name = "animate_"+jq.index()+"_"+ +new Date()	// keyframe 名
		, code = "@"+CP+"keyframes " + name + "{"	// keyframe style
		, currentPoint = c.currentElePoint(jq[0])	// 当前对象所在位置
		, direction = strength > 0 ? 1 : -1;

		strength = Math.abs(strength);

		// t_b 开始值,t_c 结束值, t_d 目标时间, t_t 不断递增的当前时间
		var t_b=0,t_c=100,t_d=strength,t_t=0, nextPoint = currentPoint, lastPoint = 0, percent = null;
		//debug("<br />"+jq.index()+"开始:", false);
		while(t_t <= t_d){
			//debug(nextPoint, false);
			percent = ease(t_t,t_b,t_c,t_d);
			percent = Math.ceil(percent * 100);
			percent = percent / 100;
			lastPoint = nextPoint;

			code += percent + "%{"+CP+"transform:"+
				c.transform(c.pathArray[nextPoint][0], c.pathArray[nextPoint][1], true)
				+" skew("+c.getSkewX(nextPoint)+"deg)"+
				"; z-index:"+c.getIndex(nextPoint)+
				"; skewX:("+c.getSkewX(nextPoint)+"deg)"+
				"; opacity:"+c.getAlpha(nextPoint)+";}\n";

			t_t++;
			nextPoint += direction;
			if (nextPoint < 0){
				nextPoint = c.pathArray.length - 1;
			}else if(nextPoint >= c.pathArray.length){
				nextPoint = 0;
			}
		}

		 function ease(t,b,c,d){
			 //return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
			 return c*(t/=d)*t*t + b;
			//return c*((t=t/d-1)*t*t + 1) + b;
		 }
		c.addStyle(code + "}");
		jq.css(CP+"animation", name + " " + duration +"ms linear")
		.css(CP+"transform", c.transform(c.pathArray[lastPoint][0], c.pathArray[lastPoint][1], true)
			+" skew("+c.getSkewX(lastPoint)+"deg)")
		.css("z-index",c.getIndex(lastPoint))
		.css("opacity",c.getAlpha(lastPoint));
	};


	c.resetAll = function(){
		if (c.itemCount % c.pathCount != 0){
			var d = Math.floor(c.pathCount / c.itemCount);
			c.pathCount = c.itemCount * (d+1);
		}
		c.pathArray = c.circlePath(c.pathCount, c.radius);
		var per = c.pathCount / c.itemCount;
		$.each(c.items, function(i,v){
			var point = per*i;
			$(v)
			.css( CP+"transform", c.transform( c.pathArray[point][0], c.pathArray[point][1], true )
				+" skew("+c.getSkewX(point)+"deg)" )
			.css("z-index",c.getIndex(point))
			.css("opacity",c.getAlpha(point));

		});
	};
	
	c.animateAllByLevel = function(x){
		c.clearStyle();
		var addPoint = c.pathCount / c.itemCount;
		var direction = x > 0 ? 1 : -1;
		var firstPoint = c.currentElePoint(c.items[0]);
		var walkPoint = firstPoint;
		walkPoint+=direction;
		while(walkPoint % addPoint != 0){
			walkPoint+=direction;
		}
		if (Math.abs(x) >= superSwipe){
			walkPoint+=direction;
			while(walkPoint % addPoint != 0){
				walkPoint+=direction;
			}
		}
		walkPoint = walkPoint - firstPoint
		$.each(c.items,function(i,v){
			//var currentPoint = c.currentElePoint(v);
			//addPoint = c.keyPathDistance(currentPoint, addPoint);
			//debug(currentPoint + "; " + addPoint);
			c.animateSet($(v), duration, walkPoint);
		});
	};

	c.animateAll = function(strength){
		$.each(c.items,function(i,v){
			c.animateSet($(v), 500, strength);
		});
	};


	// 从180度开始,逆时针
	c.circlePath = function(points, radius){
		var xys = [], r = 1, numDeg = 0, style = '';
		var perDeg = 360 / points;
		for(var i = 0; i < points; i++){
			numDeg = perDeg*i*Math.PI/180;
			xys[i] = [Math.round(Math.sin(numDeg) * radius), Math.round(Math.cos(numDeg) * radius * 0.2)];
		}
		return xys;
	};

	//------------------------------------------
	// 事件
	//------------------------------------------
	var eventTime = {
		lock: 0,		// 0 无, 1 按下或移动, 2 动画
		startTime: null,
		lastTime: null,			// 最近记录的时间
		startX:null,			// 开始的位置
		currentX:0,				// 最近记录的鼠标位置
		px:30,				// 确认滚动需要的距离
		timeCheck: 200,		// 最小侦察移动事件时间段
		clear: function(){
			eventTime.currentX = null;
			eventTime.startX = null;
			eventTime.startTime = null;
			eventTime.lastTime = null;
		},
		touch: function(x){
			//if (eventTime.lock == 2){return;}
			if (eventTime.startTime == null){
				eventTime.startTime = +new Date();
				eventTime.startX = x;
			}
			eventTime.currentX = x;
			eventTime.lastTime = +new Date();
		},
		move: function(x){		// 判断是不是可以发生移动,返回强度(单位:1/c.pathCount)
			if (eventTime.isMoving() == false){ return;	}
			var currentTime = +new Date();
			var deltaX = x - eventTime.currentX;
			var deltaTime = currentTime - eventTime.lastTime
			//if (eventTime.timeCheck < deltaTime || Math.abs(deltaX) > eventTime.px){
			if (Math.abs(deltaX) > eventTime.px){
				var strength = 0;
				strength = ( (deltaX / screen[0]) * c.itemCount ) * c.pathCount;
				eventTime.touch(x);
				c.animateAll(strength);
			}
			return 0;
		},
		moveDirect: function(x){
			if ( eventTime.lock == 2 || eventTime.lock == 0 ){ return; }
			//if ( eventTime.startX == null ){ eventTime.startX = x; }
			var deltaX = x - eventTime.startX;
			//debug("startX:" + eventTime.startX + "; x = " + x);
			if (Math.abs(deltaX) >= eventTime.px){
				eventTime.lock = 2;
				c.animateAllByLevel(deltaX);
				eventTime.clear();
				window.setTimeout( function(){
					if (eventTime.lock == 2){
						eventTime.lock = 1;
						eventTime.startX = x;
					}
				 }, duration );
			}
		}
	};


	function touchstart(e){
		if ( e.touches && e.touches.length > 1 || e.scale && e.scale !== 1) return;
		e = eventReset(e);
		eventTime.lock = 1;
		eventTime.touch( e.reset.pageX );
	}
	function touchend(e){
		eventTime.moveDirect(eventTime.currentX);
		eventTime.clear();
		eventTime.lock = 0;
	}
	function touchmove(e){
		e.preventDefault();
		if ( e.touches && e.touches.length > 1 || e.scale && e.scale !== 1) return;
		e = eventReset(e);
		eventTime.currentX = e.reset.pageX;
		eventTime.moveDirect(eventTime.currentX);
		//c.currentTouchX = e.pageX;
	}

	function eventReset(event){
		event.reset = {};
		if (event.touches && event.touches.length > 0){
			event.reset.pageX = event.touches[0].pageX;
			event.reset.pageY = event.touches[0].pageY;
		}else{
			event.reset.pageX = event.pageX;
			event.reset.pageY = event.pageY;
		}
		return event;
	}

	//window.setInterval(function(){eventTime.move(c.currentTouchX);}, 50); 


	c.initEvent = function(){
		$.each(["touchstart","MSPointerDown"],function(i,v){
			document.addEventListener(v, touchstart, false);
		});
		
		$.each(["touchend","MSPointerUp"],function(i,v){
			document.addEventListener(v, touchend, false);
		});
		$.each(["touchmove","MSPointerMove"],function(i,v){
			document.addEventListener(v, touchmove, false);
		});

		$.each(["selectstart", "dragstart"], function(i,v){
				document.body.addEventListener(v, function(e) { e.preventDefault(); }, false);
			}
		);

		/* debug */
		if (navigator.appVersion.indexOf("Windows NT")> -1){	
			document.addEventListener("mousedown", touchstart, false);
			document.addEventListener("mouseup", touchend, false);
			document.addEventListener("mousemove", touchmove, false);
		}
		/**/
	};
	
	window.controller = c;
	c.resetAll();
	c.initEvent();
});

function debug(c, falseLine){
	if (falseLine == false)
	{
		$("#debugContainer").prepend(c + ";");
	}else{
		$("#debugContainer").prepend(c +"<br />");
	}
}

  </script>
  <style>
html body{
	overflow: hidden; /* 禁用平移 */
	-ms-content-zooming: none; /* 禁用缩放 */
	-ms-touch-action: none; /* 禁用系统touch事件 */
}
#navSliderBlock{position:absolute;left:300px;top:160px;}
#navSliderBlock > div{position:absolute;}
  </style>
  <style id="navSliderBlockStyle">
  </style>
 </head>

 <body style="background:#333;">

  <div id="navSliderBlock">
	<div><img src="http://2c.zol-img.com.cn/product/110_800x600/714/ce36KAuUVsJdY.jpg" width="200" /></div>
	<div><img src="http://2c.zol-img.com.cn/product/110_800x600/714/ce36KAuUVsJdY.jpg" width="200" /></div>
	<div><img src="http://2c.zol-img.com.cn/product/110_800x600/714/ce36KAuUVsJdY.jpg" width="200" /></div>
	<div><img src="http://2c.zol-img.com.cn/product/110_800x600/714/ce36KAuUVsJdY.jpg" width="200" /></div>
  </div>


  <div id="debugContainer" style="width:500px;height:300px;overflow:hidden;">
  </div>

 </body>
</html>




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android侧滑菜单是一种常见的交互方式,可以让用户通过滑动屏幕打开或关闭菜单。实现侧滑菜单需要掌握自定义View、属性动画、事件分发等知识点。以下是一种常见的实现思路和一个不错的开源库: 1. 实现思路: - 创建一个自定义View,继承自ViewGroup或其子类,例如FrameLayout。 - 在该View中添加两个子View,一个是主界面,一个是菜单界面。 - 通过属性动画实现菜单的滑动效果。 - 通过事件分发机制,处理用户的手势操作,实现菜单的打开和关闭。 2. 开源库: SwipeRevealLayout是一个不错的开源库,它使用简单、代码入侵低,支持左右侧滑菜单和上下滑出菜单,可以配合各种布局使用,包括RecyclerView、ListView、ScrollView等。你可以通过以下步骤在你的项目中使用SwipeRevealLayout: - 在build.gradle文件中添加以下依赖: ``` implementation 'com.chauthai.swipereveallayout:swipe-reveal-layout:1.4.1' ``` - 在布局文件中添加SwipeRevealLayout和两个子View,例如: ```xml <com.chauthai.swipereveallayout.SwipeRevealLayout android:id="@+id/swipe_layout" android:layout_width="match_parent" android:layout_height="wrap_content" app:dragEdge="right"> <TextView android:id="@+id/main_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Main View" /> <TextView android:id="@+id/menu_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Menu View" /> </com.chauthai.swipereveallayout.SwipeRevealLayout> ``` - 在代码中设置菜单的滑动效果和手势操作,例如: ```java SwipeRevealLayout swipeLayout = findViewById(R.id.swipe_layout); swipeLayout.setDragEdge(SwipeRevealLayout.DRAG_EDGE_RIGHT); TextView mainView = findViewById(R.id.main_view); TextView menuView = findViewById(R.id.menu_view); swipeLayout.setSwipeListener(new SwipeRevealLayout.SwipeListener() { @Override public void onClosed(SwipeRevealLayout view) { // 菜单关闭时的操作 } @Override public void onOpened(SwipeRevealLayout view) { // 菜单打开时的操作 } @Override public void onSlide(SwipeRevealLayout view, float slideOffset) { // 菜单滑动时的操作 } }); mainView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 主界面的点击事件 } }); menuView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 菜单界面的点击事件 } }); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值