首页 > 代码库 > 使用cocos-2dx 3.x 封装的PageView

使用cocos-2dx 3.x 封装的PageView

转载请注明出处

  • helkyle.tk/blog/2014/11/27/cocos-2dx-3xPageView.html (这是我在github 上搭的个人博客,以后的东西可能都放这里)
  • http://blog.csdn.net/joueu

之前使用PageView 觉得用起来好像不太爽,没办法达到我想要实现的功能,又不想修改源码。最近闲得蛋疼就花了半天时间捣鼓一个出来,就命名叫XKPageView吧,XK嘛...大家好像都这么命名~
废话不多说,先看显示效果

因为是在模拟器上录像的,所以看上去会有点卡...真机测试就不会了。 (编号为5那个怎么会那么大嗟?) 看代码...


我就直接上代码啦,代码里面都有注释了,一些太简单的东西就不多啰嗦。如果有问题的话可以留言问我哈~ ,没有时间测试那么多...所以可能会有不少bug


PageView.h

//  XKPageView.h
//  XKPageView
//
//  Created by Joueu on 14-11-26.
//
//

#ifndef __XKPageView__XKPageView__
#define __XKPageView__XKPageView__

#include "cocos2d.h"
#include "cocos-ext.h"

USING_NS_CC;
USING_NS_CC_EXT;

class XKPageView;
class XKPageViewDelegate
{
public:

    virtual ~XKPageViewDelegate(){};
    XKPageViewDelegate(){};
    virtual Size sizeForPerPage() = 0;
    virtual void pageViewDidScroll(XKPageView *pageView){};
};

class XKPageView:public ScrollView
{
public:
    static XKPageView *create(Size size,XKPageViewDelegate *delegate);
    virtual bool init(Size size,XKPageViewDelegate *delegate);
public:
    void setPageSize(Size size);
    virtual void setContentOffsetInDuration(Vec2 offset, float dt);
    virtual void setContentOffset(Vec2 offset);
private:
    void performedAnimatedScroll(float dt);
    int current_index;
    float current_offset;
    //调整offset 的函数
    void adjust(float offset);
    Size pageSize;
    CC_SYNTHESIZE(XKPageViewDelegate *, _delegate, Delegate);
public:
    int pageCount;
    void addPage(Node *node);
    Node *getPageAtIndex(int index);
};

#endif /* defined(__XKPageView__XKPageView__) */


XKPageView.cpp

//
//  XKPageView.cpp
//  XKPageView
//
//  Created by Joueu on 14-11-26.
//
//

#include "XKPageView.h"

#define XKPAGEVIEW_TAG 10086

XKPageView *XKPageView::create(Size size,XKPageViewDelegate *delegate)
{
    XKPageView *page = new XKPageView();
    if (page && page -> init(size,delegate)) {
        page -> autorelease();
    }else {
        CC_SAFE_RELEASE(page);
    }
    return  page;
}

bool XKPageView::init(Size size,XKPageViewDelegate *delegate)
{
    if (!ScrollView::initWithViewSize(size)) {
        return false;
    }
    //必须有delegate,否则断掉
    CCASSERT(delegate, "delegate should not be NULL!");
    setDelegate(delegate);
    if (_delegate) {
        //获取page的大小
        pageSize = _delegate -> sizeForPerPage();
    }
    //init Data
    pageCount = 0;
    current_index = 0;

this -> setTouchEnabled(false);

auto listener = EventListenerTouchOneByOne::create();
listener -> onTouchBegan = [&](Touch *touch, Event *event){
    _dragging = false;
    if (_direction == ScrollView::Direction::HORIZONTAL) {
        current_offset = this -> getContentOffset().x;
    }else {
        current_offset = this -> getContentOffset().y;
    }
    return true;
};
listener -> onTouchMoved = [&](Touch *touch, Event *event){
    float start, end;
    if (_direction == ScrollView::Direction::HORIZONTAL) {
        start = touch -> getStartLocation().x;
        end = touch -> getLocation().x;
    }else {
        start = touch -> getStartLocation().y;
        end = touch -> getLocation().y;
    }
    float offset = end - start;
    // * 2的作用是调节滚动速度,需要调滑动速度的 可以改这个值
    if (_direction == ScrollView::Direction::HORIZONTAL)
        this -> setContentOffset(Vec2(current_offset + offset * 2, 0));
    else
        this -> setContentOffset(Vec2(0, current_offset + offset * 2));
};
listener -> onTouchEnded = [&](Touch *touch, Event *event){
    float start = current_offset, end;
    if (_direction == ScrollView::Direction::HORIZONTAL) {
        end = this -> getContentOffset().x;
    }else {
        end = this -> getContentOffset().y;
    }
    float offset = end - start;
    this -> adjust(offset);
    _dragging = true;
};
Director::getInstance() -> getEventDispatcher() -> addEventListenerWithSceneGraphPriority(listener, this);
return true;
}


void XKPageView::adjust(float offset)
{
    Vec2 vec;
    float xOrY;
    if (_direction == ScrollView::Direction::HORIZONTAL) {
        vec = Vec2(-( current_index * (pageSize.width)),0);
        xOrY = pageSize.width;
    }else {
        vec = Vec2(0, -( current_index * (pageSize.height)));
        xOrY = pageSize.height;
    }
    //小于50回到原来位置
    if  (abs(offset) < 50){
        this -> setContentOffsetInDuration(vec,0.1f);
        return;
    }

    int i = abs(offset / (xOrY)) + 1;
    if (offset < 0) {
        current_index += i;
    }else {
        current_index -= i;
    }

    if (current_index < 0) {
        current_index = 0;
    }else if(current_index > 10){
        current_index = 10;
    }

    if (_direction == ScrollView::Direction::HORIZONTAL) {
        vec = Vec2(-( current_index * (pageSize.width)),0);
    }else {
        vec = Vec2(0, -( current_index * (pageSize.height)));
    }

    this -> setContentOffsetInDuration(vec, 0.15f);
}

void XKPageView::setContentOffset(Vec2 offset)
{
    ScrollView::setContentOffset(offset);
    if (_delegate != nullptr)
    {
        _delegate -> pageViewDidScroll(this);
    }
}

void XKPageView::setContentOffsetInDuration(Vec2 offset, float dt)
{
    ScrollView::setContentOffsetInDuration(offset, dt);
    this->schedule(CC_SCHEDULE_SELECTOR(XKPageView::performedAnimatedScroll));
}

void XKPageView::performedAnimatedScroll(float dt)
{
    if (_dragging)
    {
        this->unschedule(CC_SCHEDULE_SELECTOR(XKPageView::performedAnimatedScroll));
        return;
    }

    if (_delegate != nullptr)
    {
        _delegate -> pageViewDidScroll(this);
    }
}

void XKPageView::addPage(Node *node)
{
    if (_direction == ScrollView::Direction::HORIZONTAL) {
        node -> setPosition(Point(pageCount * pageSize.width + node -> getPositionX(),node -> getPositionY()));
        this -> setContentSize(Size((pageCount + 1) * pageSize.width,pageSize.height));
    }else {
        node -> setPosition(Point(node -> getPositionX(),pageCount * pageSize.height + node -> getPositionY()));
        this -> setContentSize(Size(pageSize.width,(pageCount + 1) *pageSize.height));
    }
    node -> setTag(pageCount + XKPAGEVIEW_TAG);
    _container -> addChild(node);
    pageCount ++;

}

Node *XKPageView::getPageAtIndex(int index)
{
    if (index < pageCount && index >= 0) {
        return _container -> getChildByTag(index + XKPAGEVIEW_TAG);
    }
    return  NULL;
}

测试用的HelloWorld.h


#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__  
#include "cocos2d.h"
#include "cocos-ext.h"
#include "XKPageView.h"

USING_NS_CC_EXT;

class HelloWorld : public cocos2d::Layer, public XKPageViewDelegate
{
public:
    // there's no 'id' in cpp, so we recommend returning the class instance pointer
    static cocos2d::Scene* createScene();

    // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
    virtual bool init();

    // implement the "static create()" method manually
    CREATE_FUNC(HelloWorld);

    Layer *getContainer();

    // PageViewDelegate
    virtual Size sizeForPerPage();
    virtual void pageViewDidScroll(XKPageView *pageView);
private:
    XKPageView *pageView;
    void addPages();
};

#endif // __HELLOWORLD_SCENE_H__

HelloWorld.cpp


#include "HelloWorldScene.h"
USING_NS_CC;

#define COIN_WIDTH 212
#define COIN_GAP 30
#define COIN_COUNT 11

Scene* HelloWorld::createScene()
{
    // 'scene' is an autorelease object
    auto scene = Scene::create();

    // 'layer' is an autorelease object
    auto layer = HelloWorld::create();

    // add layer as a child to scene
    scene->addChild(layer);

    // return the scene
    return scene;
}

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
    //////////////////////////////
    // 1. super init first
    if ( !Layer::init() )
    {
        return false;
    }
    Size visibleSize = Director::getInstance() -> getVisibleSize();
    //XKPageView::create(可视范围, XKPageViewDelegate, container);
//    auto page = XKPageView::create(Size(visibleSize.width ,COIN_WIDTH), this, this -> getContainer());
    pageView = XKPageView::create(Size(visibleSize.width, COIN_WIDTH), this);
    pageView -> setDirection(ScrollView::Direction::HORIZONTAL);
    //XKPageView的滚动区域
//    page -> setContentSize(Size((COIN_WIDTH + COIN_GAP)* COIN_COUNT ,COIN_WIDTH));
    //container 定位在屏幕中间
    pageView -> setPosition(Point((visibleSize.width - COIN_WIDTH) * 0.5, (visibleSize.height - COIN_WIDTH) * 0.5));

    addPages();
    //设置裁切为false, 这样layer 溢出pageView的Size还能显示,只是为了演示效果而已~
    pageView -> setClippingToBounds(false);
    this -> addChild(pageView);

    /*测试功能而已*/
    Node *node = pageView -> getPageAtIndex(5);
    log("tag = %d",node -> getTag());
    node -> setScale(1.3f);

    return true;
}

void HelloWorld::addPages()
{
    Size coinSize = Sprite::create("coin.png") -> getContentSize();
    //11个layer 加到layer 上
    for (int i = 0; i < COIN_COUNT; i++) {
        auto sprite = Sprite::create("coin.png");
        sprite -> setPosition(coinSize.width * 0.5, coinSize.height * 0.5);
        std::string str = StringUtils::format("%d", i);
        Label *label = Label::createWithSystemFont(str, "Arial", 60);
        label -> setTextColor(Color4B(0,0,0,255));
        Size size = sprite -> getContentSize();
        label -> setPosition(size.width * 0.5, size.height * 0.5);
        sprite -> addChild(label);
        pageView -> addPage(sprite);
    }
}

Layer *HelloWorld::getContainer()
{
    auto layer = Layer::create();
    Size coinSize = Sprite::create("coin.png") -> getContentSize();
    //11个sprite 加到_container 上
    for (int i = 0; i < COIN_COUNT; i++) {
        auto sprite = Sprite::create("coin.png");
        sprite -> setPosition(coinSize.width * 0.5 + i * (coinSize.width + COIN_GAP) , coinSize.height * 0.5);
        layer -> addChild(sprite);
        std::string str = StringUtils::format("%d", i);
        Label *label = Label::createWithSystemFont(str, "Arial", 60);
        label -> setTextColor(Color4B(0,0,0,255));
        Size size = sprite -> getContentSize();
        label -> setPosition(size.width * 0.5, size.height * 0.5);
        sprite -> addChild(label);
    }
    return layer;
}

Size HelloWorld::sizeForPerPage()
{
    //Delegate 的东西,返回每个Page 的Size
    return Size(COIN_WIDTH + COIN_GAP, COIN_WIDTH);
}

void HelloWorld::pageViewDidScroll(XKPageView *pageView)
{
    //监听滚动时间,可以再这里写滚动时候要添加的代码,比如缩放~
    log("pageViewDidScroll");
}

我把代码和图片都放在CSDN上面了,需要的可以去下载~

http://download.csdn.net/detail/joueu/8202549

使用cocos-2dx 3.x 封装的PageView