cocos2dx伸缩式列表效果

效果:

代码:

ElasticListView.h

#pragma once

//std
#include <string>
#include <map>

//cocos
#include "cocos2d.h"
#include "cocostudio/CocoStudio.h"
#include "ui/CocosGUI.h"

//self
//#include "studioUi/StudioUiBase.h"


using namespace std;

USING_NS_CC;
using namespace cocos2d::ui;
using namespace cocostudio;
using namespace cocostudio::timeline;


//列表项
class ElasticItem
{
public:
    ElasticItem();
    virtual ~ElasticItem();
    //清理
    void Clear();
    //创建ElasticList
    static ElasticItem* Create(Node *pRoot, Widget::ccWidgetTouchCallback callback,int itemIndex);
    //SetIsHaveExtTxt
    static void SetIsHaveExtTxt(bool isHave){ IsHaveExtTxt = isHave; }

    //初始化
    virtual bool Init(Node *pRoot, Widget::ccWidgetTouchCallback callback,int itemIndex);
    

public:
    //设置列表值
    void SetValue(int value){ _ElasticItemValue = value; }
    ///获取列表值
    int GetValue(){ return _ElasticItemValue; }
    //设置列表名称
    void SetItemName(const char *pName);
    //设置列表名称颜色
    void SetItemNameColor(const Color3B& color);
    //设置列表扩展文本
    void SetExtTxt(const char *pName);
    //设置扩展文本颜色
    void SetSetExtTxtColor(const Color3B& color);
    //设置扩展文本是否可见
    void SetExtTextVisible(bool bset);
    //获取控件根节点
    Node *GetRootNode(){ return _pElasticItemBtn; }
    //设置位置
    void SetPos(Vec2 &pos){ _pElasticItemBtn->setPosition(pos); }
    //显示隐藏
    void Show(bool bShow){ _pElasticItemBtn->setVisible(bShow); }
    //选中处理
    void OnSelect();
    //取消选中处理
    void OnCancleSelect();
    //更新item文本位置
    void UpdateItemTxtPos();



protected:

    //
    static bool IsHaveExtTxt;                //是否有扩展Txt

    int _itemIndex;                            //列表项索引
    int _ElasticItemValue;                    //列表项值

    //ui
    Text* _pItemNameTxt;                    //ItemNameTxt
    Text* _pExtTxt;                            //扩展Txt
    ui::Button* _pElasticItemBtn;            //列表项按钮
};



typedef map<int, ElasticItem*> ElasticItemMap;    //列表子项

class ElasticListView;
//弹出式列表
class ElasticList
{
public:
    //弹出弹入类型
    enum ActionType
    {
        ActionNone=0,        //没有动作
        ActionOut,            //弹出
        ActionIn,            //弹入
    };

    //item list 状态
    enum ItemListState
    {
        ListStateOut = 0,        //弹出
        ListStateIn,            //弹入
    };

public:
    ElasticList();
    virtual ~ElasticList();
    //创建
    static ElasticList* Create(int listIndex, ElasticListView *pElasticListView);
    //初始化
    virtual bool Init(int listIndex, ElasticListView *pElasticListView);
public:
    //设置列表值
    void SetValue(int value){ _elasticListValue = value; }
    //获取列表值
    int GetValue(){ return _elasticListValue; }
    //设置listIndex
    void SetListIndex(int value){ _listIndex = value; }
    //获取listIndex
    int GetListIndex(){ return _listIndex; }
    //设置列表名称
    void SetListName(const char *pName);
    //获取控件根节点
    Node *GetRootNode(){ return _pListPanel; }
    //获取ListSize
    Size GetListSize(){ return _pListPanel->getContentSize(); }
    //获取List高度
    float GetListHeight(){ return _totalHeight; }
    //设置位置
    void SetPos(Vec2 &pos){ _pListPanel->setPosition(pos); }
    //更新ElasticItem
    void UpdateElasticItem();
    //更新ElasticItem txt pos
    void UpdateElasticItemTxtPos();
    //更新
    void Update(float dt);
    //item touch callback
    void OnItemTouch(Ref* pSender, Widget::TouchEventType touchuType);
    //listname touch callback
    void OnListNameTouch(Ref* pSender, Widget::TouchEventType touchuType);
    //改变list state
    void ChangeListState(ItemListState tarState);
    //是否正在伸缩list
    bool IsElasticing();
    //清理
    void Clear();


    //选中item
    void SelectItem(ElasticItem *pItem);
    //获取item
    ElasticItem *GetItem(int itemIndex);
    //添加item
    ElasticItem *AddItem(int itemIndex);
    //删除item
    void DelItem(int itemIndex);

protected:
    //弹出更新
    void ActionOutUpdate(float dt);
    //弹入更新
    void ActionInUpdate(float dt);

protected:

    //data
    static const int NameVerticalPanding = 10;    //listname上方间距
    static const int ItemVerticalPanding = 6;    //ElasticItem上方间距
    static float ScaleSteep;                    //缩放系数
    

    bool _needUpdateUi;                            //需要更新ui
    int _elasticListValue;                        //列表值
    int _listIndex;                                //list索引
    float _totalHeight;                            //总高度

    
    ElasticListView *_pElasticListView;            //ElasticListView指针

    //action
    ActionType _curActionType;                //当前动作类型
    ItemListState _curListState;            //当前list状态

    //ui
    Layout *_pListPanel;                    //列表容器
    ui::Button *_pListName;                    //列表名
    ElasticItemMap _itemList;                //子项列表
};



typedef map<int, ElasticList*> ElasticListMap;    //列表map

typedef std::function<void(int)> ElasticItemListener;

//弹出式列表视图,内含多个ElasticList
class ElasticListView
{
public:
    ElasticListView();
    virtual ~ElasticListView();
    //获取list克隆控件
    Widget *GetElasticListClone(){ return _pElasticListClone; }
    //获取item克隆控件
    Widget *GetElasticItemClone(){ return _pElasticItemClone; }

    //创建ElasticList
    void AddElasticList(ElasticList *pElasticList);
    //获取ElasticList
    ElasticList * GetElasticList(int index);


public:
    //初始化
    bool Init(Node *pRoot);
    //注册更新
    void RigisterUpdate();
    //更新
    void Update(float dt);
    //更新ElasticList
    void UpdateElasticList();
    //是否正在缩放list
    bool IsElasticingList(){ return _isElasticing; }
    //设置是否正在缩放list
    void SetIsElasticingList(bool bSet);
    //保存ScrollView百分比位置
    void SaveScrollViewPercent();
    //恢复ScrollView百分比位置
    void RecoveryScrollViewPercent();
    //开始伸缩前的准备
    void PrepareElastic();
    //是否可以伸缩
    bool CanElasticList();
    //设置选中项
    void SetCurSelectItem(ElasticItem *pItem);
    //设置选中项
    void SetCurSelectItem(int listIndex, int itemIndex);
    //获取选中项
    ElasticItem *GetCurSelectItem(){ return _pCurSelectItem; }
    //设置选中监听回调
    void SetItemListener(const ElasticItemListener &listener){ _pSelItemListener = listener; }
    //清理
    void Clear();


protected:

    ElasticListMap _elasticListMap;                //列表map
    static const int VerticalPanding = 10;        //ElasticList垂直间距
    float _totalHeight;                            //总高度
    bool _isElasticing;                            //正在缩放list
    float _scrollViewPercent;                    //ScrollView百分比位置

    ElasticItemListener _pSelItemListener;        //选中item事件
    ElasticItem *_pCurSelectItem;                //当前选中的item

    //ui
    Widget *_pElasticListClone;                    //elasticList clone
    Widget *_pElasticItemClone;                    //elasticItem clone
    ui::ScrollView *_pConScrollView;            //ScrollView容器
};
View Code

 

ElasticListView.cpp

#include "ElasticListView.h"

//self
#include "studioUi/commonFun/ComUiFun.h"

using namespace StudioComFunSpce;

//-------------ElasticItem---------------------------------------------

bool ElasticItem::IsHaveExtTxt=false;

ElasticItem::ElasticItem()
{
    _ElasticItemValue = 0;
    _itemIndex = 0;

    _pElasticItemBtn = nullptr;
    _pItemNameTxt = nullptr;
    _pExtTxt = nullptr;
}

ElasticItem::~ElasticItem()
{
}
void ElasticItem::Clear()
{

    _pElasticItemBtn->removeFromParentAndCleanup(0);
}


ElasticItem* ElasticItem::Create(Node *pRoot, Widget::ccWidgetTouchCallback callback, int itemIndex)
{
    ElasticItem * pRet = nullptr;

    ElasticItem * pElasticItem = new (std::nothrow) ElasticItem();
    if (pElasticItem && pElasticItem->Init(pRoot, callback,itemIndex))
    {
        pRet = pElasticItem;
    }
    else
    {
        CC_SAFE_DELETE(pRet);
    }

    return pRet;
}

bool ElasticItem::Init(Node *pRoot, Widget::ccWidgetTouchCallback callback, int itemIndex)
{
    bool ret = false;

    do
    {            
        _pElasticItemBtn = static_cast<ui::Button*>(pRoot);
        CC_BREAK_IF(!_pElasticItemBtn || !callback);

        Node *pNode = nullptr;


        //
        _itemIndex = itemIndex;

        //btnTxt
        pNode = FindUiChildNode(_pElasticItemBtn, "btnTxt");
        _pItemNameTxt = static_cast<Text*>(pNode);
        CC_BREAK_IF(!_pItemNameTxt);
        //extBtnTxt0
        if (IsHaveExtTxt)
        {
            pNode = FindUiChildNode(_pElasticItemBtn, "extBtnTxt0");
            _pExtTxt = static_cast<Text*>(pNode);
            CC_BREAK_IF(!_pExtTxt);
        }
        

    
        //UserData
        _pElasticItemBtn->setUserData(this);
        //event
        _pElasticItemBtn->addTouchEventListener(callback);
        

        ret = true;
    } while (0);


    return ret;
}

void ElasticItem::SetItemName(const char *pName)
{
    if (_pItemNameTxt)
    {
        _pItemNameTxt->setString(pName);
    }    
}

void ElasticItem::SetItemNameColor(const Color3B& color)
{
    if (_pItemNameTxt)
    {
        _pItemNameTxt->setColor(color);
    }
}

void ElasticItem::SetExtTxt(const char *pName)
{
    if (_pExtTxt)
    {
        _pExtTxt->setString(pName);
    }
}

void ElasticItem::SetExtTextVisible(bool bset)
{
    if (_pExtTxt)
    {
        _pExtTxt->setVisible(bset);
    }
}

void ElasticItem::SetSetExtTxtColor(const Color3B& color)
{
    if (_pExtTxt)
    {
        _pExtTxt->setColor(color);
    }
}


void ElasticItem::OnSelect()
{
    _pElasticItemBtn->setBright(false);
    _pElasticItemBtn->setEnabled(false);
}

void ElasticItem::OnCancleSelect()
{
    _pElasticItemBtn->setBright(true);
    _pElasticItemBtn->setEnabled(true);
}

void ElasticItem::UpdateItemTxtPos()
{
    bool bOnelyNameTxt = true;
    Size itemSize = _pElasticItemBtn->getContentSize();
    Size nameTxtSize = _pItemNameTxt->getContentSize();
    Size extTxtSize;
    Vec2 naemPos(itemSize.width / 2, itemSize.height / 2);
    Vec2 extPos = naemPos;

    
    if (_pExtTxt&&_pExtTxt->isVisible())
    {
        bOnelyNameTxt = false;
        extTxtSize = _pExtTxt->getContentSize();
    }
        

    //只有ItemNameTxt
    if (bOnelyNameTxt)
    {
        naemPos.x = (itemSize.width - nameTxtSize.width) / 2;

        _pItemNameTxt->setPosition(naemPos);
    }
    else
    {
        naemPos.x = (itemSize.width - nameTxtSize.width - extTxtSize.width) / 2;
        extPos.x = naemPos.x + nameTxtSize.width + 2;

        _pItemNameTxt->setPosition(naemPos);
        _pExtTxt->setPosition(extPos);
    }
    
    
}

//-------------ElasticList---------------------------------------------

float ElasticList::ScaleSteep=0.04f;


ElasticList::ElasticList()
{
    _pListPanel = nullptr;
    _pListName = nullptr;
    _pElasticListView = nullptr;

    _needUpdateUi = false;

    _listIndex = 0;
    _elasticListValue = 0;

    _totalHeight = 0;

    _curListState = ListStateOut;
    _curActionType = ActionNone;
}

ElasticList::~ElasticList()
{
    //释放内存
    ElasticItemMap::iterator it;
    ElasticItem* pElasticItem = nullptr;
    for (it = _itemList.begin(); it != _itemList.end();)
    {
        pElasticItem = it->second;
        pElasticItem->Clear();
        CC_SAFE_DELETE(pElasticItem);
        it = _itemList.erase(it);
    }
}

void ElasticList::Clear()
{

    _needUpdateUi = true;
    _curListState = ListStateOut;
    _curActionType = ActionNone;

    //更新容器高度
    _totalHeight =  _pListName->getContentSize().height + NameVerticalPanding * 2;
    Size panelSize = _pListPanel->getContentSize();
    panelSize.height = _totalHeight;
    _pListPanel->setContentSize(panelSize);


    //释放内存
    ElasticItemMap::iterator it;
    ElasticItem* pElasticItem = nullptr;
    for (it = _itemList.begin(); it != _itemList.end();)
    {
        pElasticItem = it->second;
        pElasticItem->Clear();
        CC_SAFE_DELETE(pElasticItem);
        it = _itemList.erase(it);
    }

    _itemList.clear();
}

ElasticList* ElasticList::Create(int listIndex, ElasticListView *pElasticListView)
{
    ElasticList * pRet = nullptr;

    ElasticList * pElasticList = new (std::nothrow) ElasticList();
    if (pElasticList && pElasticList->Init(listIndex, pElasticListView))
    {
        pRet = pElasticList;
    }
    else
    {
        CC_SAFE_DELETE(pRet);
    }

    return pRet;
}

bool ElasticList::Init(int listIndex, ElasticListView *pElasticListView)
{
    bool ret = false;

    do 
    {
        CC_BREAK_IF(!pElasticListView);
    
        _listIndex = listIndex;
        _pElasticListView = pElasticListView;

        //变量
        char tc[128] = {0};
        Node *pNode = nullptr;
        Widget *pElasticItemClone = nullptr;
        int itemHeight = 0;

        //获取克隆控件
        Widget *pElasticListClone = pElasticListView->GetElasticListClone();
        CC_BREAK_IF(!pElasticListClone);

        //ElasticList克隆控件
        Widget *pElasticListTemp = pElasticListClone->clone();
        CC_BREAK_IF(!pElasticListTemp);
        pElasticListTemp->setVisible(true);

        //修改控件名
        sprintf(tc, "elasticList%d", _listIndex);
        pElasticListTemp->setName(tc);

        //elasticList
        _pListPanel = static_cast<Layout*>(pElasticListTemp);
        CC_BREAK_IF(!_pListPanel);

        //elasticListName
        pNode = FindUiChildNode(pElasticListTemp, "elasticListName");
        _pListName = static_cast<ui::Button*>(pNode);
        CC_BREAK_IF(!_pListName);
        Widget::ccWidgetTouchCallback nameCallback = CC_CALLBACK_2(ElasticList::OnListNameTouch, this);
        _pListName->addTouchEventListener(nameCallback);

        //更新高度
        _totalHeight = _totalHeight + _pListName->getContentSize().height + NameVerticalPanding* 2;

        //elasticItem
        pNode = FindUiChildNode(pElasticListTemp, "elasticItem");
        pElasticItemClone = static_cast<Widget*>(pNode);
        CC_BREAK_IF(!pElasticItemClone);
        //itemHeight = pElasticItemClone->getContentSize().height + ItemVerticalPanding;

        //设置更新标记
        _needUpdateUi = true;

        //删除item
        pElasticListTemp->removeChild(pElasticItemClone);

        ret = true;
    } while (0);


    return ret;
}

ElasticItem *ElasticList::AddItem(int itemIndex)
{
    ElasticItem* pElasticItem = nullptr;

    do 
    {
        //变量
        char tc[128] = { 0 };
        Node *pNode = nullptr;
        Widget *pElasticItemClone = nullptr;
        int itemHeight = 0;

        //elasticItem克隆控件
        pElasticItemClone = _pElasticListView->GetElasticItemClone();
        CC_BREAK_IF(!pElasticItemClone);
        itemHeight = pElasticItemClone->getContentSize().height + ItemVerticalPanding;

        //更新高度
        _totalHeight = _totalHeight + itemHeight;

        Widget *pElasticItemTemp = pElasticItemClone->clone();
        CC_BREAK_IF(!pElasticItemTemp);

        //callback
        Widget::ccWidgetTouchCallback callback = CC_CALLBACK_2(ElasticList::OnItemTouch, this);

        //创建ElasticItem
        pElasticItem = ElasticItem::Create(pElasticItemTemp, callback, itemIndex);
        CC_BREAK_IF(!pElasticItem);

        //修改控件名
        sprintf(tc, "elasticItem%d", itemIndex);
        pElasticItemTemp->setName(tc);

        //添加
        _pListPanel->addChild(pElasticItem->GetRootNode());
        _itemList[itemIndex] = pElasticItem;

        //设置更新标记
        _needUpdateUi = true;



    } while (0);
    
    return pElasticItem;
}

void ElasticList::DelItem(int itemIndex)
{
    ElasticItemMap::iterator it = _itemList.find(itemIndex);
    if (it != _itemList.end())
    {
        _itemList.erase(it);

        //设置更新标记
        _needUpdateUi = true;
    }
        
}

void ElasticList::SetListName(const char *pName)
{
    do 
    {
        CC_BREAK_IF(!pName);

        Node *pNode = nullptr;
        Text *pText = nullptr;

        //btnTxt
        pNode = FindUiChildNode(_pListName, "btnTxt");
        pText = static_cast<Text*>(pNode);
        CC_BREAK_IF(!pText);

        pText->setString(pName);

    } while (0);
}

void ElasticList::UpdateElasticItemTxtPos()
{

    //更新ElasticItem txt位置
    ElasticItemMap::iterator it;
    for (it = _itemList.begin(); it != _itemList.end();it++)
    {
        ElasticItem* pElasticItem = it->second;
        if (pElasticItem)
        {
            pElasticItem->UpdateItemTxtPos();
        }
    }
}

void  ElasticList::UpdateElasticItem()
{
    int totalHeight = _totalHeight;

    Size panelSize = _pListPanel->getContentSize();
    Size nameSizes = _pListName->getContentSize();
    
    Vec2 pos(panelSize.width/2,0);


    //更新ListName位置
    pos.y = totalHeight - NameVerticalPanding;
    _pListName->setPosition(pos);
    totalHeight = totalHeight - NameVerticalPanding - nameSizes.height;

    //更新ElasticItem位置
    ElasticItemMap::iterator it;
    for (it = _itemList.begin(); it != _itemList.end();it++)
    {
        ElasticItem* pElasticItem = it->second;
        if (pElasticItem)
        {
            Size itemSizes = pElasticItem->GetRootNode()->getContentSize();

            pos.y = totalHeight - ItemVerticalPanding;
            pElasticItem->SetPos(pos);

            totalHeight = totalHeight - ItemVerticalPanding - itemSizes.height;
        }
    }


    //更新容器高度
    panelSize.height = _totalHeight;
    _pListPanel->setContentSize(panelSize);

    //更新ElasticList
    _pElasticListView->UpdateElasticList();
}

void ElasticList::OnListNameTouch(Ref* pSender, Widget::TouchEventType touchuType)
{
    do 
    {
        ui::Button *pBtn = static_cast<ui::Button*>(pSender);
        CC_BREAK_IF(!pBtn);

        if (touchuType == Widget::TouchEventType::BEGAN)
        {
            pBtn->setScale(1.2f);
        }
        else if (touchuType == Widget::TouchEventType::CANCELED)
        {
            pBtn->setScale(1.0f);
        }
        else if (touchuType == Widget::TouchEventType::MOVED)
        {
        }
        else if (touchuType == Widget::TouchEventType::ENDED)
        {
            pBtn->setScale(1.0f);

            //
            if (_itemList.size()>0)
            {
                if (_curActionType == ActionNone&&_pElasticListView->CanElasticList())
                {
                    if (_curListState == ListStateIn)
                    {
                        ChangeListState(ListStateOut);
                    }
                    else if (_curListState == ListStateOut)
                    {
                        ChangeListState(ListStateIn);
                    }
                }

            }
            

        }

    } while (0);
}

void ElasticList::OnItemTouch(Ref* pSender, Widget::TouchEventType touchuType)
{
    do
    {
        ui::Button *pBtn = static_cast<ui::Button*>(pSender);
        CC_BREAK_IF(!pBtn);

        if (touchuType == Widget::TouchEventType::BEGAN)
        {
        }
        else if (touchuType == Widget::TouchEventType::CANCELED)
        {
        }
        else if (touchuType == Widget::TouchEventType::MOVED)
        {
        }
        else if (touchuType == Widget::TouchEventType::ENDED)
        {
            void *p = pBtn->getUserData();
            //int *pValue = (int*)p;
            ElasticItem *pItem = (ElasticItem*)p;;
            CC_BREAK_IF(!pItem);

            //选中
            SelectItem(pItem);

        }

    } while (0);
}

void ElasticList::SelectItem(ElasticItem *pItem)
{
    do 
    {
        CC_BREAK_IF(!pItem);
        ElasticItem *pLastItem = _pElasticListView->GetCurSelectItem();
        if (pItem != pLastItem)
        {
            //取消选中处理
            if (pLastItem)
                pLastItem->OnCancleSelect();
            //选中处理
            pItem->OnSelect();
            //保存指针
            _pElasticListView->SetCurSelectItem(pItem);
        }
        


    } while (0);
    
}

bool ElasticList::IsElasticing()
{
    bool ret = false;

    if (_curActionType != ActionNone)
        ret = true;

    return ret;
}


ElasticItem * ElasticList::GetItem(int itemIndex)
{
    ElasticItem *pRet = nullptr;
    do
    {
        ElasticItem* pItem = _itemList.at(itemIndex);
        CC_BREAK_IF(!pItem);

        pRet = pItem;
    } while (0);


    return pRet;
}

void ElasticList::ChangeListState(ItemListState tarState)
{
    if (_curActionType == ActionNone&&_curListState != tarState)
    {
        if (tarState == ListStateIn)
        {
            _curActionType = ActionIn;

            //设置正在缩放
            _pElasticListView->SetIsElasticingList(true);
        }
        else if (tarState == ListStateOut)
        {
            _curActionType = ActionOut;

            //设置正在缩放
            _pElasticListView->SetIsElasticingList(true);

            //ElasticItem处理
            ElasticItemMap::iterator it;
            for (it = _itemList.begin(); it != _itemList.end();it++)
            {
                ElasticItem* pElasticItem = it->second;
                if (pElasticItem)
                    pElasticItem->Show(true);

            }
        }
    }
}

void ElasticList::Update(float dt)
{
    if (_needUpdateUi)
    {
        //更新ElasticItem
        UpdateElasticItem();

        _needUpdateUi = false;
    }
    

    if (_curActionType != ActionNone)
    {
        if (_curActionType == ActionIn)
            ActionInUpdate(dt);
        else if (_curActionType == ActionOut)
            ActionOutUpdate(dt);
    }



}

void ElasticList::ActionOutUpdate(float dt)
{
    do
    {
        int count = _itemList.size();
        CC_BREAK_IF(count == 0);
        ElasticItemMap::iterator it = _itemList.begin();
        ElasticItem* pFirstItem = it->second;
        CC_BREAK_IF(!pFirstItem);

        //scale
        static float totalScale = 0.01f;
        totalScale += ScaleSteep;

        float verticalPanding = ItemVerticalPanding*totalScale;
        //


        Size panelSize = _pListPanel->getContentSize();
        Size nameSizes = _pListName->getContentSize();
        Size itemSize = pFirstItem->GetRootNode()->getContentSize();
        float totalHeight = (itemSize.height + ItemVerticalPanding)*totalScale*count + (nameSizes.height + NameVerticalPanding * 2);
        Vec2 pos(panelSize.width / 2, 0);

        //更新容器高度
        panelSize.height = totalHeight;
        _pListPanel->setContentSize(panelSize);

        //更新ListName位置
        pos.y = totalHeight - NameVerticalPanding;
        _pListName->setPosition(pos);
        totalHeight = totalHeight - NameVerticalPanding - nameSizes.height;

        //更新ElasticItem位置
        for (it = _itemList.begin(); it != _itemList.end(); it++)
        {
            ElasticItem* pElasticItem = it->second;
            if (pElasticItem)
            {
                Node *pItemRoot = pElasticItem->GetRootNode();
                //scale
                pItemRoot->setScaleY(totalScale);
                //size
                Size itemSizes = pItemRoot->getContentSize();

                pos.y = totalHeight - verticalPanding;
                pElasticItem->SetPos(pos);

                totalHeight = totalHeight - verticalPanding - itemSizes.height*totalScale;
            }
        }


        //结束处理
        if (totalScale >= 0.95f)
        {
            //ElasticItem处理
            for (it = _itemList.begin(); it != _itemList.end(); it++)
            {
                ElasticItem* pElasticItem = it->second;
                if (pElasticItem)
                {
                    Node *pItemRoot = pElasticItem->GetRootNode();
                    //scale
                    pItemRoot->setScaleY(1.0f);
                }
            }

            //更新ElasticItem
            UpdateElasticItem();

            //更新ElasticListView
            _pElasticListView->UpdateElasticList();
            //设置结束缩放
            _pElasticListView->SetIsElasticingList(false);


            //状态设置
            _curActionType = ActionNone;
            _curListState = ListStateOut;
            totalScale = 0.01f;
        }

    } while (0);
}

void ElasticList::ActionInUpdate(float dt)
{
    do 
    {
        int count = _itemList.size();
        CC_BREAK_IF(count==0);
        ElasticItemMap::iterator it =_itemList.begin();
        ElasticItem* pFirstItem = it->second;
        CC_BREAK_IF(!pFirstItem);
        //scale
        static float totalScale = 1.0f;
        totalScale -= ScaleSteep;

        float verticalPanding = ItemVerticalPanding*totalScale;
        //

        
        Size panelSize = _pListPanel->getContentSize();
        Size nameSizes = _pListName->getContentSize();
        Size itemSize = pFirstItem->GetRootNode()->getContentSize();
        float totalHeight = (itemSize.height + ItemVerticalPanding)*totalScale*count + (nameSizes.height + NameVerticalPanding * 2);
        //totalHeight = (_totalHeight - nameSizes.height - VerticalPanding)*totalScale;

        Vec2 pos(panelSize.width / 2, 0);

        //更新容器高度
        panelSize.height = totalHeight;
        _pListPanel->setContentSize(panelSize);

        //更新ListName位置
        pos.y = totalHeight - NameVerticalPanding;
        _pListName->setPosition(pos);
        totalHeight = totalHeight - NameVerticalPanding - nameSizes.height;

        //更新ElasticItem位置
        for (it = _itemList.begin(); it != _itemList.end(); it++)
        {
            ElasticItem* pElasticItem = it->second;
            if (pElasticItem)
            {
                Node *pItemRoot = pElasticItem->GetRootNode();
                //scale
                pItemRoot->setScaleY(totalScale);
                //size
                Size itemSizes = pItemRoot->getContentSize();
        
                pos.y = totalHeight - verticalPanding;
                pElasticItem->SetPos(pos);

                totalHeight = totalHeight - verticalPanding - itemSizes.height*totalScale;
            }
        }


        //结束处理
        if (totalScale <= 0.01f)
        {
            //ElasticItem处理
            for (it = _itemList.begin(); it != _itemList.end(); it++)
            {
                ElasticItem* pElasticItem = it->second;
                if (pElasticItem)
                    pElasticItem->Show(false);

            }

            //更新容器高度
            //_totalHeight = nameSizes.height + NameVerticalPanding * 2;
            panelSize.height = nameSizes.height + NameVerticalPanding * 2;
            _pListPanel->setContentSize(panelSize);

            //更新ListName位置
            pos.y = panelSize.height - NameVerticalPanding;
            _pListName->setPosition(pos);


            //更新ElasticListView
            _pElasticListView->UpdateElasticList();


            //设置结束缩放
            _pElasticListView->SetIsElasticingList(false);


            //状态设置
            _curActionType = ActionNone;
            _curListState = ListStateIn;
            totalScale = 1.0f;
        }

    } while (0);
}

//-------------ElasticListView---------------------------------------------



ElasticListView::ElasticListView()
{
    _totalHeight = 0;
    _isElasticing = false;

    _pCurSelectItem = nullptr;
    _pSelItemListener = nullptr;
    _pElasticListClone = nullptr;
}

ElasticListView::~ElasticListView()
{

    //取消更新
    Director::getInstance()->getScheduler()->unschedule("ElasticListView::Update", this);

    //释放内存
    ElasticListMap::iterator it;
    ElasticList* pElasticList=nullptr;
    for (it = _elasticListMap.begin(); it != _elasticListMap.end();)
    {
        pElasticList = it->second;
        CC_SAFE_DELETE(pElasticList);
        it = _elasticListMap.erase(it);
    }
}



void ElasticListView::Clear()
{

    
    _pCurSelectItem = nullptr;
    _totalHeight = 0;
    _isElasticing = false;

    int count = _elasticListMap.size();


    _totalHeight = 0;
    for (int i = 0; i < count; i++)
    {
        ElasticList* pElasticList = _elasticListMap.at(i);
        if (pElasticList)
        {
            pElasticList->Clear();
        }
    }


}

bool ElasticListView::Init(Node *pRoot)
{
    bool ret = false;

    do
    {
        
        CC_BREAK_IF(!pRoot);

        //
        Node *pNode = nullptr;

        //elasticListView
        pNode = FindUiChildNode(pRoot, "elasticListView");
        _pConScrollView = static_cast<ui::ScrollView*>(pNode);
        _pConScrollView->SetBounceBackDuration(0.5f);
        //_pConScrollView->setBounceEnabled(false);


        //elasticListClone
        pNode = FindUiChildNode(_pConScrollView, "elasticListClone");
        _pElasticListClone = static_cast<Widget*>(pNode);
        CC_BREAK_IF(!_pElasticListClone);
        _pElasticListClone->setVisible(false);

        //elasticItem
        pNode = FindUiChildNode(_pElasticListClone, "elasticItem");
        _pElasticItemClone = static_cast<Widget*>(pNode);
        CC_BREAK_IF(!_pElasticItemClone);



        ret = true;
    } while (0);


    return ret;
}


void ElasticListView::RigisterUpdate()
{
    //注册更新
    ccSchedulerFunc updateCall = CC_CALLBACK_1(ElasticListView::Update, this);
    Director::getInstance()->getScheduler()->schedule(updateCall, this,0, false, "ElasticListView::Update");
}

void ElasticListView::AddElasticList(ElasticList *pElasticList)
{

    do
    {
        CC_BREAK_IF(!pElasticList);

        //char tc[128] = { 0 };

        int index = pElasticList->GetListIndex();

        ////set list name
        //sprintf(tc, "ElasticList%d", index);
        //pElasticList->SetListName(tc);

        //添加
        _pConScrollView->addChild(pElasticList->GetRootNode());
        
        _elasticListMap[index] = pElasticList;

    } while (0);
}

ElasticList* ElasticListView::GetElasticList(int index)
{
    ElasticList* pRet = nullptr;

    ElasticListMap::iterator it = _elasticListMap.find(index);
    if (it!=_elasticListMap.end())
    {
        pRet = it->second;
    }
    
    return pRet;
}

void ElasticListView::UpdateElasticList()
{
    
    int count = _elasticListMap.size();
    Size panelSize = _pConScrollView->getContentSize();
    float totalHeight = 0;
    Vec2 pos(panelSize.width / 2, 0);

    //更新_totalHeight,itemtx pos
    _totalHeight = 0;
    for (int i = 0; i<count; i++)
    {
        ElasticList* pElasticList = _elasticListMap.at(i);
        if (pElasticList)
        {
            _totalHeight = _totalHeight + pElasticList->GetListSize().height + VerticalPanding;

            //itemtx pos
            pElasticList->UpdateElasticItemTxtPos();
        }
    }
    
    //高度保护
    if (_totalHeight < panelSize.height)
    {
        _totalHeight = panelSize.height+10;
    }
    totalHeight = _totalHeight;

    //更新ElasticList位置
    for (int i = 0; i<count; i++)
    {
        ElasticList* pElasticList = _elasticListMap.at(i);
        if (pElasticList)
        {
            pos.y = totalHeight - VerticalPanding;
            pElasticList->SetPos(pos);

            totalHeight = totalHeight - VerticalPanding - pElasticList->GetListSize().height;
        }
    }

    //更新容器高度
    panelSize.height = _totalHeight;
    _pConScrollView->setInnerContainerSize(panelSize);
}

void ElasticListView::Update(float dt)
{
    bool bUpdateList = false;
    ElasticListMap::iterator it;
    for (it = _elasticListMap.begin(); it != _elasticListMap.end();it++)
    {
        it->second->Update(dt);
        if (it->second->IsElasticing())
            bUpdateList=true;
    }

    if (bUpdateList)
    {
        UpdateElasticList();
    }
}

void ElasticListView::SetIsElasticingList(bool bSet)
{
    _isElasticing = bSet;
    //if (bSet)
    //{
    //    SaveScrollViewPercent();
    //}
    //else
    //{
    //    RecoveryScrollViewPercent();
    //}
    
}

void ElasticListView::SaveScrollViewPercent()
{
    CCLOG("-----------------SaveScrollViewPercent--------------------");

    Size panelSize = _pConScrollView->getContentSize();
    Size innerSize = _pConScrollView->getInnerContainerSize();
    Vec2 innerlPos = _pConScrollView->getInnerContainerPosition();

    float minY = panelSize.height - innerSize.height;
    float h = -minY;

    float percent = innerlPos.y*100 / h;

    if (percent < 0)
        percent = -percent;

    _scrollViewPercent = percent;

    CCLOG("--panelSize:(%f,%f)", panelSize.width, panelSize.height);
    CCLOG("--innerSize:(%f,%f)", innerSize.width, innerSize.height);
    CCLOG("--innerlPos:(%f,%f)", innerlPos.x, innerlPos.y);
    CCLOG("--minY=%f,percent=%f", minY, percent);
}

void ElasticListView::RecoveryScrollViewPercent()
{
    CCLOG("-----------------RecoveryScrollViewPercent--------------------");

    Size panelSize = _pConScrollView->getContentSize();
    Size innerSize = _pConScrollView->getInnerContainerSize();
    Vec2 innerlPos = _pConScrollView->getInnerContainerPosition();

    float minY = panelSize.height - innerSize.height;
    float h = -minY;

    float percent = innerlPos.y * 100 / h;

    if (percent < 0)
        percent = -percent;

    CCLOG("--panelSize:(%f,%f)", panelSize.width, panelSize.height);
    CCLOG("--innerSize:(%f,%f)", innerSize.width, innerSize.height);
    CCLOG("--innerlPos:(%f,%f)", innerlPos.x, innerlPos.y);
    CCLOG("--minY=%f,percent=%f", minY, percent);

    //_pConScrollView->scrollToPercentVertical(_scrollViewPercent, 0.5f,false);
}

void ElasticListView::PrepareElastic()
{
    Size panelSize = _pConScrollView->getContentSize();
    Size innerSize = _pConScrollView->getInnerContainerSize();
    Vec2 innerlPos = _pConScrollView->getInnerContainerPosition();

    float minY = panelSize.height - innerSize.height;

    //if (innerlPos.y>)ISAutoScrolling
    //{
    //}
    
}

bool ElasticListView::CanElasticList()
{
    bool ret = false;
    bool isScrooling = _pConScrollView->ISAutoScrolling();
    bool isElasticing = IsElasticingList();

    if (!isScrooling)
    {
        if (!isElasticing)
        {
            ret = true;
        }
    }
    
    
    return ret;
}

void ElasticListView::SetCurSelectItem(ElasticItem *pItem)
{
    do 
    {
        CC_BREAK_IF(!pItem);
        _pCurSelectItem = pItem;

        //选中item事件
        if (_pSelItemListener)
        {
            _pSelItemListener(_pCurSelectItem->GetValue());
        }
        
    } while (0);
    
}

void ElasticListView::SetCurSelectItem(int listIndex, int itemIndex)
{
    do 
    {
        ElasticList* pList = _elasticListMap.at(listIndex);
        CC_BREAK_IF(!pList);
        ElasticItem *pItem=pList->GetItem(itemIndex);
        CC_BREAK_IF(!pItem);

        _pCurSelectItem = pItem;

        //选中item事件
        if (_pSelItemListener)
        {
            _pSelItemListener(_pCurSelectItem->GetValue());
        }

    } while (0);
    
}
View Code

 

使用代码,具体自己理解:

        //创建ElasticListView-------------------------------------------------
        //char tc[128] = { 0 };

        ElasticItem::SetIsHaveExtTxt(true);

        //初始化ElasticListView
        CC_BREAK_IF(!_elasticListView.Init(pConWinNode));

        int langId[EUiTaskTypeCount];

        //创建ElasticList
        for (int i = 0; i < EUiTaskTypeCount; i++)
        {
            ElasticList* pElasticList = ElasticList::Create(i, &_elasticListView);
            CC_BREAK_IF(!pElasticList);

            pElasticList->SetListName(GetStaticLangTxt(langId[i]).c_str());
            pElasticList->SetValue(i);

            //add
            _elasticListView.AddElasticList(pElasticList);
        }
    
    
        //更新ElasticList
        //_elasticListView.UpdateElasticList();
        //注册更新
        _elasticListView.RigisterUpdate();
        //注册选中事件
        ElasticItemListener listener = CC_CALLBACK_1(TaskUiLayer::OnSelItem, this);
        _elasticListView.SetItemListener(listener);



            //创建设置ElasticItem
            ElasticItem *pItem = pElasticList->AddItem(pTblInfo->m_missionid);
            CC_BREAK_IF(!pItem);
            pItem->SetItemName(pTblInfo->m_name.c_str());
            pItem->SetValue(pTblInfo->m_missionid);
View Code

 

posted @ 2016-04-25 16:36  冷夜 - 网游编程技术  阅读(1808)  评论(0编辑  收藏  举报