1、CustomScrollLayer.h
#pragma once
#include "cocos2d.h"
USING_NS_CC;
class CustomScrollLayer:public Layer
{
public:
CustomScrollLayer();
~CustomScrollLayer();
private:
Vec2 _pox[3];
int _leftItemIndex;
int _midItemIndex;
int _rightItemIndex;
float _space;
bool _isScrollActionOver;
bool _hasMoveScrolled;
public:
std::vector<Node*> m_items;
static CustomScrollLayer* create(Vec2 midItemPox, float space, std::vector<Node*> allItems);
bool init(Vec2 midItemPox, float space, std::vector<Node*> allItems);
void onEnter()override;
void onExit()override;
bool touchBegan(Touch *pTouch, Event *pEvent);
void touchMoved(Touch *pTouch, Event *pEvent);
void touchEnded(Touch *pTouch, Event *pEvent);
private:
void initPosX(Vec2 midItemPox,std::vector<Node*> allItems);
void startMoveActions(bool isGoLeft = true);
void disapperAction(bool isLeftDisAppear);
void scaleDownAction(bool isGoLeft);
void scaleUpAction(bool isGoLeft);
void showAction(bool isShowRightItem);
void resetItemIndex(bool isGoLeft);
bool hitTest(Touch* pTouch, int index);
};
2、CustomScrollLayer.cpp
#include "CustomScrollLayer.h"
//#include "AppUtils.h"
#define SCALE_SPACE 0.3f
#define SCROLL_ACTION_DURATION 0.3f
#define MOVE_SCROLL_SPACE 50
CustomScrollLayer::CustomScrollLayer()
{
_leftItemIndex = 0;
_midItemIndex = 0;
_rightItemIndex = 0;
_space = 0;
_isScrollActionOver = true;
_hasMoveScrolled = false;
}
CustomScrollLayer::~CustomScrollLayer()
{
}
CustomScrollLayer* CustomScrollLayer::create(Vec2 midItemPox, float space, std::vector<Node*> allItems)
{
CustomScrollLayer* pRet = new CustomScrollLayer();
if (pRet&&pRet->init(midItemPox, space,allItems))
{
pRet->autorelease();
}
else
{
delete pRet;
pRet = NULL;
}
return pRet;
}
bool CustomScrollLayer::init(Vec2 midItemPox, float space, std::vector<Node*> allItems)
{
if (!Layer::init()) return false;
_space = space;
initPosX(midItemPox,allItems);
return true;
}
void CustomScrollLayer::onEnter()
{
Layer::onEnter();
auto touchEvent = EventListenerTouchOneByOne::create();
touchEvent->onTouchBegan = CC_CALLBACK_2(CustomScrollLayer::touchBegan, this);
touchEvent->onTouchMoved = CC_CALLBACK_2(CustomScrollLayer::touchMoved, this);
touchEvent->onTouchEnded = CC_CALLBACK_2(CustomScrollLayer::touchEnded, this);
touchEvent->setSwallowTouches(true);
_eventDispatcher->addEventListenerWithFixedPriority(touchEvent, 10);
}
void CustomScrollLayer::onExit()
{
_eventDispatcher->removeEventListenersForTarget(this);
Layer::onExit();
}
bool CustomScrollLayer::touchBegan(Touch *pTouch, Event *pEvent)
{
return true;
}
void CustomScrollLayer::touchMoved(Touch *pTouch, Event *pEvent)
{
Point begin = pTouch->getStartLocation();
Point cur = pTouch->getLocation();
cur.subtract(begin);
if ((cur.x>MOVE_SCROLL_SPACE|cur.x<-MOVE_SCROLL_SPACE)&&!_hasMoveScrolled&&_isScrollActionOver)
{
_hasMoveScrolled = true;
startMoveActions(cur.x<0);
}
}
void CustomScrollLayer::touchEnded(Touch *pTouch, Event *pEvent)
{
if (hitTest(pTouch,_leftItemIndex))
{
startMoveActions(false);
}
else if(hitTest(pTouch, _rightItemIndex))
{
startMoveActions(true);
}
else if (hitTest(pTouch, _midItemIndex))
{
MessageBox("Execute Menu Pressed Event!","执行按钮点击方法");
//AppUtils::toastMessage(this, "Execute Menu Pressed Event!", 640);
}
_hasMoveScrolled = false;
}
void CustomScrollLayer::initPosX(Vec2 midItemPox,std::vector<Node*> allItems)
{
_pox[0] = Vec2(midItemPox.x - _space, midItemPox.y);
_pox[1] = Vec2(midItemPox.x, midItemPox.y);
_pox[2] = Vec2(midItemPox.x + _space, midItemPox.y);
_midItemIndex = 1;
_rightItemIndex = _midItemIndex + 1;
for (size_t i = 0; i < allItems.size(); i++)
{
Node* item = allItems.at(i);
item->setColor(Color3B::GRAY);
if (i < 3)
{
item->setPosition(_pox[i]);
if (i==1)
{
item->setScale(1+ SCALE_SPACE);
item->setColor(Color3B::WHITE);
}
}
else
{
item->setVisible(false);
item->setScale(1 - SCALE_SPACE);
}
addChild(item);
m_items.push_back(item);
}
}
void CustomScrollLayer::startMoveActions(bool isGoLeft/* = true*/)
{
_isScrollActionOver = false;
// 缩小消失
disapperAction(isGoLeft);
// 缩小移动变灰
scaleDownAction(isGoLeft);
// itemRight
scaleUpAction(isGoLeft);
resetItemIndex(isGoLeft);
if (m_items.size()>3)
{
showAction(isGoLeft);
}
}
void CustomScrollLayer::disapperAction(bool isLeftDisAppear)
{
Node* target = NULL;
if (isLeftDisAppear)
{
target = m_items.at(_leftItemIndex);
}
else
{
target = m_items.at(_rightItemIndex);
}
target->setZOrder(100);
ScaleTo* pScaleTo = ScaleTo::create(m_items.size() <= 3?SCROLL_ACTION_DURATION/2: SCROLL_ACTION_DURATION, 1 - SCALE_SPACE);
CallFunc* pCallFunc = CallFunc::create([=]() {
target->setVisible(false);
if (m_items.size() <=3)
{
showAction(isLeftDisAppear);
}
});
Sequence* pSequence = Sequence::create(pScaleTo, pCallFunc, NULL);
target->runAction(pSequence);
}
void CustomScrollLayer::scaleDownAction(bool isGoLeft)
{
Node* target = m_items.at(_midItemIndex);
target->setZOrder(200);
target->setColor(Color3B::GRAY);
ScaleTo* pScaleTo = ScaleTo::create(SCROLL_ACTION_DURATION, 1);
MoveTo* pMoveTo = MoveTo::create(SCROLL_ACTION_DURATION, isGoLeft?_pox[0]:_pox[2]);
Spawn* pSpawn = Spawn::create(pScaleTo, pMoveTo, NULL);
target->runAction(pSpawn);
}
void CustomScrollLayer::scaleUpAction(bool isGoLeft)
{
Node* target = NULL;
if (isGoLeft)
{
target = m_items.at(_rightItemIndex);
}
else
{
target = m_items.at(_leftItemIndex);
}
target->setZOrder(300);
MoveTo* pMoveTo = MoveTo::create(SCROLL_ACTION_DURATION, _pox[1]);
ScaleTo* pScaleTo = ScaleTo::create(SCROLL_ACTION_DURATION, 1 + SCALE_SPACE);
Spawn* pSpawn = Spawn::create(pMoveTo, pScaleTo, NULL);
CallFunc* pCallFunc = CallFunc::create([=]() {
target->setColor(Color3B::WHITE);
});
Sequence* pSequence = Sequence::create(pSpawn, pCallFunc, NULL);
target->runAction(pSequence);
}
void CustomScrollLayer::showAction(bool isShowRightItem)
{
Node* target = NULL;
if (isShowRightItem)
{
target = m_items.at(_rightItemIndex);
}
else
{
target = m_items.at(_leftItemIndex);
}
target->setZOrder(50);
target->setVisible(true);
if (!isShowRightItem)
{
target->setPosition(_pox[0]);
}
else
{
target->setPosition(_pox[2]);
}
ScaleTo* pScaleTo = ScaleTo::create(m_items.size() <= 3 ? SCROLL_ACTION_DURATION / 2: SCROLL_ACTION_DURATION, 1);
CallFunc* pCallFunc = CallFunc::create([=]() {
_isScrollActionOver = true;
});
Sequence* pSequence = Sequence::create(pScaleTo,pCallFunc,NULL);
target->runAction(pSequence);
}
void CustomScrollLayer::resetItemIndex(bool isGoLeft)
{
if (isGoLeft)
{
_leftItemIndex = _midItemIndex;
_midItemIndex = _rightItemIndex;
_rightItemIndex = _midItemIndex + 1;
if (_rightItemIndex >= m_items.size())
{
_rightItemIndex = 0;
}
}
else
{
_rightItemIndex = _midItemIndex;
_midItemIndex = _leftItemIndex;
_leftItemIndex = _midItemIndex - 1;
if (_leftItemIndex < 0)
{
_leftItemIndex = m_items.size()-1;
}
}
}
bool CustomScrollLayer::hitTest(Touch* pTouch,int index)
{
Point pre = pTouch->getStartLocation();
Point cur = pTouch->getLocation();
Rect rect = m_items.at(index)->getBoundingBox();
if (rect.containsPoint(pre) && rect.containsPoint(cur) && _isScrollActionOver)
{
return true;
}
return false;
}
3、使用
void MainRoomLayer::testForScrollLayer()
{
std::vector<Node*> itemNames;
itemNames.push_back(Sprite::create("test/room1.png"));
itemNames.push_back(Sprite::create("test/room2.png"));
itemNames.push_back(Sprite::create("test/room3.png"));
itemNames.push_back(Sprite::create("test/room3.png"));
auto size = Director::getInstance()->getVisibleSize();
CustomScrollLayer* pScrollLayer = CustomScrollLayer::create(Vec2(size.width/2,size.height/2), 400,itemNames);
pScrollLayer->setPositionY((size.height - pScrollLayer->getContentSize().height)/2);
addChild(pScrollLayer);
}