模拟iOS原生手势,简单实现点击(双击)、长按、滑动、拖动等功能。
代码如下:
//
// CGesture.h
// ActionLabel
//
// Created by xujw on 16/3/15.
/* 手势识别 仿iphone 简单长按 点击(双击等) 滑动 拖动等。 * 使用方法: * auto gesture = CGesture::createTapGesture(target,callback,taps); * this->addChild(gestrue) */
#ifndef CGesture_h
#define CGesture_h
#include <stdio.h>
#include "cocos2d.h"
USING_NS_CC;
typedef enum gestureDirection
{
kDirectUp = 0,kDirectDown = 1,kDirectLeft = 2,kDirectRight = 3
}GestureDirection;
typedef std::function<void(Touch*)> GestureCallback;
typedef std::function<void(Touch*,GestureDirection)> SwipeGestureCallback;
#define SHAKE_LENGTH 100
class CGesture:public Layer
{
private:
bool _isCanTouch;
int _tapNum;
public:
CGesture();
~CGesture();
bool init();
CREATE_FUNC(CGesture);
public:
//点击
static CGesture* createTapGesture(Node*target,GestureCallback callback,int tapsrequired=1);
//长按
static CGesture* createLongPressGesture(Node*target,float delay = 1.0f);
//滑动
static CGesture* createSwipeGesture(Node*target,SwipeGestureCallback callback);
//拖动
static CGesture* createPanGestrue(Node*target,GestureCallback callback);
};
#endif /* CGesture_h */
//
// CGesture.cpp
// ActionLabel
//
// Created by xujw on 16/3/15.
//
//
#include "CGesture.h"
#include <time.h>
CGesture::CGesture()
:_isCanTouch(false),_tapNum(0)
{}
CGesture::~CGesture()
{}
bool CGesture::init()
{
if (!Layer::init())
{
return false;
}
return true;
}
CGesture* CGesture::createTapGesture(Node*target,int tapsrequired)
{
CCASSERT(callback && target,"callback or target is null");
auto parent = target->getParent();
auto gesture = CGesture::create();
auto lis = EventListenerTouchOneByOne::create();
lis->onTouchBegan = [=](Touch *touch,Event *event)
{
auto Box = target->getBoundingBox();
auto pos = touch->getLocation();
if (parent) {
pos = parent->convertToNodeSpace(pos);
}
if (Box.containsPoint(pos))
{
gesture->_tapNum ++;
}
return true;
};
lis->onTouchMoved = [=](Touch *touch,Event *event)
{
auto startPos = touch->getStartLocation();
auto curPos = touch->getLocation();
auto subPos = curPos - startPos;
if (fabs(subPos.x)>=10 || fabs(subPos.y)>=10)
{
gesture->_tapNum = 0;
gesture->unschedule("GestureTapNumReset");
}
};
lis->onTouchEnded = [=](Touch *touch,Event *event)
{
if (gesture->_tapNum >= tapsrequired)
{
auto Box = target->getBoundingBox();
auto pos = touch->getLocation();
auto parent = target->getParent();
if (parent) {
pos = parent->convertToNodeSpace(pos);
}
if (Box.containsPoint(pos))
{
gesture->_tapNum = 0;
gesture->unschedule("GestureTapNumReset");
callback(touch);
}
}
gesture->scheduleOnce([=](float dt)
{
gesture->_tapNum = 0;
},0.5,"GestureTapNumReset");
};
gesture->getEventDispatcher()->addEventListenerWithSceneGraPHPriority(lis,target);
return gesture;
}
CGesture* CGesture::createLongPressGesture(Node*target,float delay)
{
CCASSERT(callback && target,Event *event)
{
auto Box = target->getBoundingBox();
auto pos = touch->getLocation();
if (parent) {
pos = parent->convertToNodeSpace(pos);
}
if (Box.containsPoint(pos))
{
gesture->scheduleOnce([=](float){
gesture->_isCanTouch = true;
},delay,"GestureChangeTouchState");
return true;
}
else
{
return false;
}
};
lis->onTouchMoved = [=](Touch *touch,Event *event)
{
//长按时滑动算取消
auto startPos = touch->getStartLocation();
auto curPos = touch->getLocation();
auto subPos = curPos - startPos;
if (fabs(subPos.x)>=10 || fabs(subPos.y)>=10)
{
gesture->unschedule("GestureChangeTouchState");
gesture->_isCanTouch = false;
}
};
lis->onTouchEnded = [=](Touch *touch,Event *event)
{
auto Box = target->getBoundingBox();
auto pos = touch->getLocation();
if (parent) {
pos = parent->convertToNodeSpace(pos);
}
if (gesture->_isCanTouch)
{
if (Box.containsPoint(pos))
{
callback(touch);
}
}
else
{
gesture->unschedule("GestureChangeTouchState");
}
gesture->_isCanTouch = false;
};
gesture->getEventDispatcher()->addEventListenerWithSceneGraPHPriority(lis,target);
return gesture;
}
CGesture* CGesture::createSwipeGesture(Node*target,SwipeGestureCallback callback)
{
CCASSERT(callback && target,"callback or target is null");
auto parent = target->getParent();
auto gesture = CGesture::create();
auto lis = EventListenerTouchOneByOne::create();
lis->onTouchBegan = [=](Touch *touch,Event *event)
{
auto pos = touch->getLocation();
auto Box = target->getBoundingBox();
if (parent) {
pos = parent->convertToNodeSpace(pos);
}
if (Box.containsPoint(pos))
{
gesture->_isCanTouch = true;
}
else{
gesture->_isCanTouch = false;
}
return gesture->_isCanTouch;
};
lis->onTouchMoved = [=](Touch *touch,Event *event){};
lis->onTouchEnded = [=](Touch *touch,Event *event)
{
auto pos = touch->getLocation();
auto Box = target->getBoundingBox();
if (parent) {
pos = parent->convertToNodeSpace(pos);
}
//起始点都在target范围内才响应
if (!gesture->_isCanTouch || !Box.containsPoint(pos))
{
gesture->_isCanTouch = false;
return ;
}
auto startPos = touch->getStartLocation();
auto curPos = touch->getLocation();
auto subPos = curPos - startPos;
if (fabs(subPos.x) > fabs(subPos.y))
{
//左右移动
if (subPos.x > SHAKE_LENGTH)
{
//向右移动
callback(touch,kDirectRight);
}
else if (subPos.x < -SHAKE_LENGTH)
{
//向左移动
callback(touch,kDirectLeft);
}
}
else
{
if (subPos.y > SHAKE_LENGTH)
{
//向上移动
callback(touch,kDirectUp);
}
else if (subPos.y < -SHAKE_LENGTH)
{
//向下移动
callback(touch,kDirectDown);
}
}
};
gesture->getEventDispatcher()->addEventListenerWithSceneGraPHPriority(lis,gesture);
return gesture;
}
CGesture* CGesture::createPanGestrue(Node*target,GestureCallback callback)
{
CCASSERT(callback && target,Event *event)
{
auto Box = target->getBoundingBox();
auto pos = touch->getLocation();
if (parent) {
pos = parent->convertToNodeSpace(pos);
}
if (Box.containsPoint(pos))
{
gesture->_isCanTouch = true;
}
return true;
};
lis->onTouchMoved = [=](Touch *touch,Event *event)
{
if (gesture->_isCanTouch)
{
callback(touch);
}
};
lis->onTouchEnded = [=](Touch *touch,Event *event)
{
gesture->_isCanTouch = false;
};
gesture->getEventDispatcher()->addEventListenerWithSceneGraPHPriority(lis,target);
return gesture;
}