• 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
  • 相关阅读:
    Java实现 LeetCode 56 合并区间
    JQuery实现对html结点的操作(创建,添加,删除)
    JQuery实现对html结点的操作(创建,添加,删除)
    JQuery实现对html结点的操作(创建,添加,删除)
    Java实现 LeetCode 55 跳跃游戏
    Java实现 LeetCode 55 跳跃游戏
    Java实现 LeetCode 55 跳跃游戏
    Java实现 LeetCode 54 螺旋矩阵
    Java实现 LeetCode 54 螺旋矩阵
    Java实现 LeetCode 54 螺旋矩阵
  • 原文地址:https://www.cnblogs.com/gamesky/p/5431469.html
Copyright © 2020-2023  润新知