====== 首页 ====== 在卡片上左右拖动,查看效果
代码解释:
package;
class MainApplication extends TouchSprite {
private static inline var SCREEN_WIDTH:Int=1920; //定义屏幕宽度
private static inline var SPEED_FACTOR:Int=100; //值越小,手指离开后卡片飞行的距离越远
private static inline var OFFSET_FACTOR:Int=300; //值越小,手指拖动时卡片跟手移动的距离越远
/*
一个指示器,用id的形式抽象表达了目前哪个卡片的位置处在屏幕中间
比如__current=0代表了第一个卡出于屏幕中间,__current=1代表了第一个卡出于屏幕中间,
__current=0.5代表了第一个卡和第二个卡的间隙出于屏幕中间,
__current从最小值__min也就是0,到最大值__max的过程就是卡片从一个飞行到最后一个的过程
*/
private var __current:Float;
private var __onTouch:Float; //手指按下后,临时记录一下__current
private var __min:Float; //__current最小值
private var __max:Float; //__current最大值
private var __cardsArr:Array; //保存卡片引用的数组
private var __depthsArr:Array; //卡片深度的数组
private var __offsetX:Float=0; //存储每次手指位移量,单位是px
private var __speedX:Float=0; //存储每次手指位移速度,单位是px/帧
private var __dist:Float=0; //手指放开后,__current需要变化到的值
private var __isTouch:Bool=false; //手指当前是否按在屏幕上
public function new () {
super ();
initUI();
initTouch();
initTicker();
}
private function initUI():Void
{
__max=12; //随意加入13张卡片,即最大的卡片id为12
__min=0;
__cardsArr=new Array();
__depthsArr=new Array();
var i:Int=0;
while(i<(__max+1))
{
/*
在demo中,Card对象就是一个简单的显示对象,
内部逻辑就是加载一张贴图,并将自身的缩放点调整到自身的中心,而非左上角
*/
var card:Card=new Card(i%8);
__cardsArr.push(card); //将卡片放入引用数组
__depthsArr.push(card); //将卡片放入深度数组
this.addChild(card); //将卡片放入场景显示出来
i++;
}
__current=__dist=0;
updateCards();
sortDepth();
}
private function initTicker():Void
{
this.addEventListener(Event.ENTER_FRAME, onTicker); //注册一个每帧都会执行的方法onTicker
}
/*
每一帧都会执行这个方法,当手放开时,让__current渐渐过渡到__dist,
即让卡片飞行一段距离再停下,让人有拖拽惯性的感觉
*/
private function onTicker(e:Event):Void
{
if(!__isTouch)
{
__current+=(__dist-__current)*.2;
updateCards();
sortDepth();
}
}
/*
注册触摸事件侦听器
FingerEvent.FINGER_BEGIN 是手指刚开始按在屏幕的事件,会一次性触发beginHandler
FingerEvent.FINGER_END 是手指离开屏幕的事件,会一次性触发endHandler
FingerGestureEvent.GESTURE_PAN 是手指在屏幕上划动的事件,在划动整个过程中,每一帧都会触发panHandler
如果是多点触摸屏幕,FingerEvent.FINGER_BEGIN 只在第一个手指接触屏幕时触发
FingerEvent.FINGER_END 只在所有手指全部离开屏幕时触发
FingerGestureEvent.GESTURE_PAN 在第一个手指划动时触发
这里是对开发平台依赖度比较强的地方,每个平台的触摸事件定义均有所不同,只要能达到相同的目的即可
*/
private function initTouch():Void
{
this.addEventListener(FingerEvent.FINGER_BEGIN, beginHandler);
this.addEventListener(FingerGestureEvent.GESTURE_PAN, panHandler);
this.addEventListener(FingerEvent.FINGER_END, endHandler);
}
private function beginHandler(e:FingerEvent):Void
{
__onTouch=__current;
__isTouch=true;
}
private function endHandler(e:FingerEvent):Void
{
/*
手指离开屏幕后,结束触摸,根据最后一次记录的速度计算卡片需要飞行的距离__dist
*/
__dist=__current-__speedX/SPEED_FACTOR;
/*
将__dist限制为__min到__max之间的整数
*/
if(__dist<__min)
{
__dist=__min;
}
else if(__dist>__max)
{
__dist=__max;
}
else
{
__dist=Math.round(__dist);
}
__isTouch=false;
}
private function panHandler(e:FingerGestureEvent):Void
{
/*
在手指划动过程中,记录此次划动手指位移,位移的距离=当前帧手指x-刚一接触屏幕时的手指x
*/
__offsetX=e.offsetX;
/*
在手指划动过程中,时刻记录划动手指位移速度,速度=当前帧手指x-前一帧手指x
*/
__speedX=e.speedX;
/*
手指划动时,计算卡片需要位移的距离,更新当前的__current
*/
var dist:Float=__onTouch-__offsetX/OFFSET_FACTOR;
if(dist<__min)
{
__current=__min-Math.sqrt(__min-dist)*.5; //当划动到最左端,给一个弹性的感觉
}
else if(dist>__max)
{
__current=__max+Math.sqrt(dist-__max)*.5; //当划动到最右端,给一个弹性的感觉
}
else
{
__current=dist;
}
updateCards();
sortDepth();
}
/*
计算所有卡片x坐标,缩放,透明度的方法
其中所有卡片都是以卡片中心进行缩放,而非左上角
*/
private function updateCards():Void
{
var i:Int=0;
var l:Int=__cardsArr.length;
while(i0?0:NumberUtil.clamp(Math.abs(alphaRatio), 0, 1);
card.x=distX;
card.y=540;
/*
给卡片缩放赋予一个差值,让靠近屏幕中心的缩放更平滑
*/
card.scaleX=card.scaleY=circular(scaleRatio, 0, 1, 1);
card.alpha=alphaRatio;
i++;
}
}
/*
计算所有卡片前后遮挡关系的方法,原理是遍历__depthsArr,比较卡片之间的缩放值
缩放值越大,在场景中的深度值越大,越靠前
*/
private function sortDepth():Void
{
__depthsArr.sort(sortByScale);
var i:Int=__depthsArr.length;
while((i--)>0)
{
this.addChild(__depthsArr[i]);
}
}
/*
根据缩放值确定卡片A,卡片B的前后遮挡关系,给sortDepth方法提供比较结果
*/
private function sortByScale(a:DisplayObject, b:DisplayObject):Int
{
if (ReflectUtil.getField(a, "scaleX") > ReflectUtil.getField(b, "scaleX"))
return -1;
else if (ReflectUtil.getField(a, "scaleX") < ReflectUtil.getField(b, "scaleX"))
return 1;
return 0;
}
private function circular(t:Float, b:Float, c:Float, d:Float):Float
{
return c * Math.sqrt(1 - (t = t / d - 1) * t) + b;
}
}