摺疊菜單,用過jquery accordion的同窗都知道是啥玩藝兒~,圖片效果就是介樣:jquery
cocos2dx不帶有此控件,所以咱們動手來實現一個。json
原理很簡單,展開的時候往listview裏insertCustomItem,收起的時候從listview裏removeItem。下面給出一個功能豐富的摺疊菜單控件。
先看控件主類:函數
--[[ 二級摺疊菜單組 構造: local groupData = { { title = '分類1', items = { { id = 1, count = 20, lv = 19 }, { id = 2, count = 21, lv = 21 }, { id = 3, count = 22, lv = 23 }, } }, { title = '圖騰', items = { { id = 500001, count = 32, lv = 19 }, { id = 500002, count = 21, lv = 65 }, { id = 500003, count = 22, lv = 27 }, } }, { title = '武器', items = { { id = 101002, count = 20, lv = 45 }, { id = 101003, count = 21, lv = 34 }, } }, } self._goodsCateList = gm.Common.UIMenuList.new( cc.size( 310, 510 ), groupData ) -- 必須設置標題類型和內容類型,重寫可改變樣式 self._goodsCateList:setClass( gm.Market.MarketMenuTitle, gm.Market.MarketMenuItem ) -- 可選參數,是否可同時展開多個分組,默認false self._goodsCateList.showMulti = true -- 可選參數,是否默認選中組中第一個item self._goodsCateList.autoSelectFirstItem = true -- 可選參數,選中的title索引,默認爲1 self._goodsCateList.defaultGroup = 1 -- 可選參數,選中的item索引,默認爲1 self._goodsCateList.defaultItem = 1 加入舞臺: self._goodsCateList:addToParent( self._bg, { x = 0, y = 0 } ) @author cc --]] gm = gm or {} rm = rm or {} local gm = gm local rm = rm gm.Common = gm.Common or {} gm.Common.UIMenuList = class( "Common.UIMenuList" ) gm.Common.UIMenuList._name = "Common.UIMenuList" local g = gm.Common.UIMenuList --------------------------------------------------------------------------------- -- -- -- 如下定義私有部分 -- -- -- --------------------------------------------------------------------------------- local function log( ... ) print( '>>>>gm.Common.UIMenuList<<<<:', ...) end -- 點擊標題項 function g:_onTouchTitle( sender ) local titleInst = sender._inst -- 收縮點擊項 if titleInst.selected then self:_unSelectTitleInst( titleInst ) return end -- 若是同時只展開一個分組,則隱藏上次展開的 if not self._showMulti and self._selectedTitle then self:_unSelectTitleInst( self._selectedTitle ) end -- 展開點擊項 local index = self._listView:getIndex( sender ) local group = titleInst.data local itemInst for itemIdx, itemData in ipairs( group.items ) do itemInst = self:_createItemInst( itemData ) self._listView:insertCustomItem( itemInst.ui, index + itemIdx ) -- 將第一項設置爲當前選中的內容項 if self._autoSelectFirstItem and itemIdx == 1 then self.selectedItem = itemInst end end -- 設置當前選中的標題項 self.selectedTitle = titleInst end -- 點擊內容項 function g:_onTouchItem( sender, eventType ) if eventType == ccui.TouchEventType.ended then self.selectedItem = sender._inst end if self._itemClickFunc then self._itemClickFunc( sender, eventType ) end end -- 收起標題項對應的分組 function g:_unSelectTitleInst( titleInst ) local index = self._listView:getIndex( titleInst.ui ) local group = titleInst.data local itemInst for i = 1, #group.items do -- 析構刪除項 itemInst = self._listView:getItem( index + 1 )._inst itemInst:finalize() -- 選中項被刪除 if self._selectedItem and self._selectedItem == itemInst then self._selectedItem = nil end self._listView:removeItem( index + 1 ) end titleInst.selected = false if titleInst == self._selectedTitle then self._selectedTitle = nil end end -- 建立標題項 function g:_createTitleInst( data ) if not self._titleCls then log( '沒有設置標題類型!' ) return end local titleInst = self._titleCls.new( ) titleInst.data = data titleInst.ui._inst = titleInst makeTouchHandle( self, titleInst.ui, self._onTouchTitle ) return titleInst end -- 建立內容項 function g:_createItemInst( data ) if not self._itemCls then log( '沒有設置內容類型!' ) return end local itemInst = self._itemCls.new( ) itemInst.data = data itemInst.ui._inst = itemInst makeTouchHandle2( self, itemInst.ui, self._onTouchItem ) return itemInst end -- 初始化 function g:_initialize( ) self._listView = ccui.ListView:create() self._listView:setBounceEnabled( true ) self._listView:setDirection( ccui.ScrollViewDir.vertical ) self._listView:setSize( self._size ) if not self._groupData then log( '分組數據爲空!' ) return end local titleInst, itemInst self._titleInstList = {} for groupIdx, group in ipairs( self._groupData ) do titleInst = self:_createTitleInst( group ) self._listView:pushBackCustomItem( titleInst.ui ) table.insert( self._titleInstList, titleInst ) -- 展開默認分組 if self._defaultGroupIdx and groupIdx == self._defaultGroupIdx then self.selectedTitle = titleInst for itemIdx, itemData in ipairs( group.items ) do itemInst = self:_createItemInst( itemData ) self._listView:pushBackCustomItem( itemInst.ui ) -- 選中默認項 if self._defaultItemIdx and itemIdx == self._defaultItemIdx then self.selectedItem = itemInst end end end end end --------------------------------------------------------------------------------- -- -- -- 如下定義set, get 部分函數 -- -- -- --------------------------------------------------------------------------------- function g:_getUi( ) return self._listView end -- 是否同時展開多個組 function g:_setShowMulti( value ) self._showMulti = value end -- 獲取數據 function g:_getGroupData( ) return self._groupData end function g:_setGroupData( value ) self._groupData = value end -- 設置默認展開的分組索引 -- @i value function g:_setDefaultGroup( value ) self._defaultGroupIdx = value end -- 設置默認選中的item索引 --@i value function g:_setDefaultItem( value ) self._defaultItemIdx = value end -- 獲取選中的標題項 function g:_getSelectedTitle( ) return self._selectedTitle end function g:_setSelectedTitle( value ) value.selected = true self._selectedTitle = value rm.BindManager.propertyChanged( self, "selectedTitle" ) end -- 獲取選中的內容項 function g:_getSelectedItem( ) return self._selectedItem end function g:_setSelectedItem( value ) if self._selectedItem then self._selectedItem.selected = false end value.selected = true self._selectedItem = value rm.BindManager.propertyChanged( self, "selectedItem" ) end -- 設置點擊item項的回調函數 function g:_setItemClickFunc( value ) self._itemClickFunc = value end -- 設置是否自動選中組中第一個item function g:_setAutoSelectFirstItem( value ) self._autoSelectFirstItem = value end --------------------------------------------------------------------------------- -- -- -- 如下定義公共部分 -- -- -- --------------------------------------------------------------------------------- -- 構造 -- @t size cc.size類型 -- @t groupData 分組數據,結構如{ { title = tData, items = { iData1, iData2 } }, ... } function g:ctor( size, groupData ) self._size = size or cc.size( 200, 200 ) self._groupData = groupData self._titleInstList = nil self._defaultGroupIdx = nil self._defaultItemIdx = nil self._selectedTitle = nil self._selectedItem = nil self._titleCls = nil self._itemCls = nil self._showMulti = false self._autoSelectFirstItem = false self._itemClickFunc = nil end -- 設置標題項和內容項類型 -- @t titleClass 繼承自gm.Common.UIMenuItem,重寫可改變樣式 -- @t itemClass 繼承自gm.Common.UIMenuItem,重寫可改變樣式 function g:setClass( titleClass, itemClass ) self._titleCls = titleClass self._itemCls = itemClass end -- 添加到舞臺 -- @widget parent 父顯示對象 -- @t pos 位置,{ x = , y = } -- @i zOrder 層級 function g:addToParent( parent, pos, zOrder ) if not parent then log( '父顯示對象不可爲空!' ) return end self:_initialize() zOrder = zOrder or 1 pos = pos or cc.p( 0, 0 ) self._listView:setPosition( pos ) parent:addChild( self._listView, zOrder ) end -- 刷新當前展開的分組,只可在互斥(showMulti = false)模式下使用 -- @t group 數據,結構如{ title = tData, items = { iData1, iData2 } } function g:refreshSelectedTitle( group ) if not self._selectedTitle then return end self:refreshTitle( self._selectedTitle, group ) end -- 刷新指定位置的分組 -- @i titleIndex 分組索引 -- @t group 組數據 function g:refreshTitleAtIndex( titleIndex, group ) local title = self._titleInstList( titleIndex ) self:refreshTitle( title, group ) end -- 刷新指定分組 -- @t 某個分組 -- @t group 組數據 function g:refreshTitle( title, group ) local index = self._listView:getIndex( title.ui ) local prevNumItems = title.selected and #title.data.items or 0 local currNumItems = #group.items local deltaNum = prevNumItems - currNumItems local itemInst -- 設置title數據 title:_setData( group ) self._groupData[ table.indexOf( self._titleInstList, title ) ] = group -- title沒展開,如下無需執行 if not title.selected then return end -- 設置item數據 for itemIdx, itemData in ipairs( group.items ) do if itemIdx <= prevNumItems then itemInst = self._listView:getItem( index + itemIdx )._inst itemInst:_setData( itemData ) else itemInst = self:_createItemInst( itemData ) self._listView:insertCustomItem( itemInst.ui, index + itemIdx ) end end -- 舊數量比當前數量多,須要刪除多餘的item if deltaNum > 0 then for i = 1, deltaNum do itemInst = self._listView:getItem( index + currNumItems + 1 )._inst itemInst:finalize() -- 選中項被刪除 if self._selectedItem and self._selectedItem == itemInst then self._selectedItem = nil end self._listView:removeItem( index + currNumItems + 1 ) end end end -- 刷新整個控件 -- @t 控件數據,結構如構造函數同名參數所示 function g:refresh( groupData ) self._groupData = groupData if not self._groupData then log( '分組數據爲空!' ) return end local prevNumTitles = #self._titleInstList local currNumTitles = #groupData local deltaNum = prevNumTitles - currNumTitles local titleInst -- 刷新全部分組 for groupIdx, group in ipairs( groupData ) do if groupIdx <= prevNumTitles then titleInst = self._titleInstList[ groupIdx ] self:refreshTitle( titleInst, group ) else titleInst = self:_createTitleInst( group ) self._listView:pushBackCustomItem( titleInst.ui ) table.insert( self._titleInstList, titleInst ) end end -- 新分組比舊分組少,須要刪除多餘的title if deltaNum > 0 then local numListItems = #self._listView:getItems() -- 清空所有 if currNumTitles == 0 then for i = numListItems - 1, 0, -1 do titleInst = self._listView:getItem( i )._inst titleInst:finalize() end self._listView:removeAllItems() self._titleInstList = {} self._selectedTitle = nil self._selectedItem = nil return end local lastTitleInst = self._titleInstList[ currNumTitles ] local index = self._listView:getIndex( lastTitleInst.ui ) + ( lastTitleInst.selected and #lastTitleInst.data.items or 0 ) for i = numListItems - 1, index + 1, -1 do -- 析構被刪除的title titleInst = self._listView:getItem( i )._inst titleInst:finalize() -- 選中title被刪除 if self._selectedTitle and self._selectedTitle == titleInst then self._selectedTitle = nil end -- 選中項被刪除 if self._selectedItem and self._selectedItem == titleInst then self._selectedItem = nil end self._listView:removeItem( i ) end -- 從title列表中移除 for i = prevNumTitles, currNumTitles + 1, -1 do table.remove( self._titleInstList, i ) end end end -- 析構 function g:finalize() if self._listView then self._listView:removeFromParent() self._listView = nil end self._titleInstList = nil self._groupData = nil self._itemClickFunc = nil end
咱們把摺疊菜單抽象成標題項(title)和內容項(item),title即指標題項,展開標題項顯示出來的內容項叫item。title和item均從uimenuitem派生而來,這們作的好處是咱們能夠方便的更改摺疊菜單標題項和內容項的樣式。ui
下面來看看uimenuitem.lua:lua
--[[ 摺疊菜單項 @author cc --]] gm = gm or {} rm = rm or {} local gm = gm local rm = rm gm.Common = gm.Common or {} gm.Common.UIMenuItem = class( "Common.UIMenuItem" ) gm.Common.UIMenuItem._name = "Common.UIMenuItem" local g = gm.Common.UIMenuItem --------------------------------------------------------------------------------- -- -- -- 如下定義私有部分 -- -- -- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- -- -- -- 如下定義set, get 部分函數 -- -- -- --------------------------------------------------------------------------------- -- 獲取顯示對象 function g:_getUi( ) return self._ui end function g:_getData( ) return self._data end -- 設置數據 function g:_setData( value ) self._data = value end function g:_getSelected( ) return self._selected end -- 設置選中狀態 function g:_setSelected( value ) self._selected = value end --------------------------------------------------------------------------------- -- -- -- 如下定義公共部分 -- -- -- --------------------------------------------------------------------------------- -- 構造 function g:ctor( ) self._selected = false self._data = nil self:initialize() end -- 初始化 function g:initialize( ) self._ui = nil end -- 析構 function g:finalize( ) if self._ui then self._ui:removeFromParent( ) self._ui = nil end end
下面舉個簡單的使用例子,spa
local groupData = { { title = { cate = 1, cate_desc = '技能書' }, items = { { sub_cate = 1, sub_cate_desc = '一級技能書', }, { sub_cate = 2, sub_cate_desc = '二級技能書', }, { sub_cate = 3, sub_cate_desc = '三級技能書', } } }, { title = { cate = 2, cate_desc = '寶石' }, items = { { sub_cate = 1, sub_cate_desc = '攻擊寶石', }, { sub_cate = 2, sub_cate_desc = '暴擊寶石', } } }, { title = { cate = 3, cate_desc = '月石' }, items = { { sub_cate = 1, sub_cate_desc = '很好的月石', } } }, } self._goodsCateList = gm.Common.UIMenuList.new( cc.size( 204, 482 ), groupData ) self._goodsCateList:setClass( gm.Market.MarketMenuTitle, gm.Market.MarketMenuItem ) self._goodsCateList.showMulti = true self._goodsCateList.defaultGroup = 1 self._goodsCateList.defaultItem = 1 self._goodsCateList:addToParent( self._bg, cc.p( 15, 24 ) )
這裏方便演示手寫了分類數據,但通常狀況下是用遍歷生成的。經過上面這段代碼,咱們生成了一個摺疊菜單,效果即本文首部的演示圖片。3d
這裏用到的兩個類gm.Market.MarketMenuTitle和gm.Market.MarketMenuItem便是用來自定義摺疊菜單樣式的,代碼也一塊貼出:code
--[[ 市場摺疊菜單標題項 @author cc --]] gm = gm or {} rm = rm or {} local gm = gm local rm = rm gm.Market = gm.Market or {} gm.Market.MarketMenuTitle = class( "Market.MarketMenuTitle", gm.Common.UIMenuItem ) gm.Market.MarketMenuTitle._name = "Market.MarketMenuTitle" local g = gm.Market.MarketMenuTitle --------------------------------------------------------------------------------- -- -- -- 如下定義私有部分 -- -- -- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- -- -- -- 如下定義set, get 部分函數 -- -- -- --------------------------------------------------------------------------------- -- 設置數據 function g:_setData( value ) self._data = value self._labelName:setText( value.title.cate_desc ) end -- 設置選中狀態 function g:_setSelected( value ) self._selected = value local texture = value and 'tab_btn_4.png' or 'tab_btn_3.png' self._imgBg:loadTexture( texture, ccui.TextureResType.plistType ) end --------------------------------------------------------------------------------- -- -- -- 如下定義公共部分 -- -- -- --------------------------------------------------------------------------------- -- -- 構造 -- function g:ctor( ) -- g.super.ctor( self ) -- end -- 初始化 function g:initialize( ) g.super.initialize( self ) self._ui = ccs.GUIReader:getInstance():widgetFromJsonFile('ui/new_market_menu_title.json') self._labelName = self._ui:getChildByName('LabName') self._imgBg = self._ui:getChildByName('ImgBg') end -- -- 析構 -- function g:finalize( ) -- g.super.finalize( self ) -- end
--[[ 市場摺疊菜單內容項 @author cc --]] gm = gm or {} rm = rm or {} local gm = gm local rm = rm gm.Market = gm.Market or {} gm.Market.MarketMenuItem = class( "Market.MarketMenuItem", gm.Common.UIMenuItem ) gm.Market.MarketMenuItem._name = "Market.MarketMenuItem" local g = gm.Market.MarketMenuItem --------------------------------------------------------------------------------- -- -- -- 如下定義私有部分 -- -- -- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- -- -- -- 如下定義set, get 部分函數 -- -- -- --------------------------------------------------------------------------------- -- 設置數據 function g:_setData( value ) self._data = value self._labelName:setText( value.sub_cate_desc ) end -- 設置選中狀態 function g:_setSelected( value ) self._selected = value self._imgSelected:setVisible( value ) end --------------------------------------------------------------------------------- -- -- -- 如下定義公共部分 -- -- -- --------------------------------------------------------------------------------- -- 構造 function g:ctor( ) g.super.ctor( self ) end -- 初始化 function g:initialize( ) g.super.initialize( self ) self._ui = ccs.GUIReader:getInstance():widgetFromJsonFile('ui/new_market_menu_item.json') self._labelName = self._ui:getChildByName('LabName') self._imgSelected = self._ui:getChildByName('ImgSelected') end -- 析構 function g:finalize( ) g.super.finalize( self ) end
摺疊菜單,用過jquery accordion的同窗都知道是啥玩藝兒~,圖片效果就是介樣:對象
cocos2dx不帶有此控件,所以咱們動手來實現一個。blog
原理很簡單,展開的時候往listview裏insertCustomItem,收起的時候從listview裏removeItem。下面給出一個功能豐富的摺疊菜單控件。
先看控件主類:
--[[ 二級摺疊菜單組 構造: local groupData = { { title = '分類1', items = { { id = 1, count = 20, lv = 19 }, { id = 2, count = 21, lv = 21 }, { id = 3, count = 22, lv = 23 }, } }, { title = '圖騰', items = { { id = 500001, count = 32, lv = 19 }, { id = 500002, count = 21, lv = 65 }, { id = 500003, count = 22, lv = 27 }, } }, { title = '武器', items = { { id = 101002, count = 20, lv = 45 }, { id = 101003, count = 21, lv = 34 }, } }, } self._goodsCateList = gm.Common.UIMenuList.new( cc.size( 310, 510 ), groupData ) -- 必須設置標題類型和內容類型,重寫可改變樣式 self._goodsCateList:setClass( gm.Market.MarketMenuTitle, gm.Market.MarketMenuItem ) -- 可選參數,是否可同時展開多個分組,默認false self._goodsCateList.showMulti = true -- 可選參數,是否默認選中組中第一個item self._goodsCateList.autoSelectFirstItem = true -- 可選參數,選中的title索引,默認爲1 self._goodsCateList.defaultGroup = 1 -- 可選參數,選中的item索引,默認爲1 self._goodsCateList.defaultItem = 1 加入舞臺: self._goodsCateList:addToParent( self._bg, { x = 0, y = 0 } ) @author cc --]] gm = gm or {} rm = rm or {} local gm = gm local rm = rm gm.Common = gm.Common or {} gm.Common.UIMenuList = class( "Common.UIMenuList" ) gm.Common.UIMenuList._name = "Common.UIMenuList" local g = gm.Common.UIMenuList --------------------------------------------------------------------------------- -- -- -- 如下定義私有部分 -- -- -- --------------------------------------------------------------------------------- local function log( ... ) print( '>>>>gm.Common.UIMenuList<<<<:', ...) end -- 點擊標題項 function g:_onTouchTitle( sender ) local titleInst = sender._inst -- 收縮點擊項 if titleInst.selected then self:_unSelectTitleInst( titleInst ) return end -- 若是同時只展開一個分組,則隱藏上次展開的 if not self._showMulti and self._selectedTitle then self:_unSelectTitleInst( self._selectedTitle ) end -- 展開點擊項 local index = self._listView:getIndex( sender ) local group = titleInst.data local itemInst for itemIdx, itemData in ipairs( group.items ) do itemInst = self:_createItemInst( itemData ) self._listView:insertCustomItem( itemInst.ui, index + itemIdx ) -- 將第一項設置爲當前選中的內容項 if self._autoSelectFirstItem and itemIdx == 1 then self.selectedItem = itemInst end end -- 設置當前選中的標題項 self.selectedTitle = titleInst end -- 點擊內容項 function g:_onTouchItem( sender, eventType ) if eventType == ccui.TouchEventType.ended then self.selectedItem = sender._inst end if self._itemClickFunc then self._itemClickFunc( sender, eventType ) end end -- 收起標題項對應的分組 function g:_unSelectTitleInst( titleInst ) local index = self._listView:getIndex( titleInst.ui ) local group = titleInst.data local itemInst for i = 1, #group.items do -- 析構刪除項 itemInst = self._listView:getItem( index + 1 )._inst itemInst:finalize() -- 選中項被刪除 if self._selectedItem and self._selectedItem == itemInst then self._selectedItem = nil end self._listView:removeItem( index + 1 ) end titleInst.selected = false if titleInst == self._selectedTitle then self._selectedTitle = nil end end -- 建立標題項 function g:_createTitleInst( data ) if not self._titleCls then log( '沒有設置標題類型!' ) return end local titleInst = self._titleCls.new( ) titleInst.data = data titleInst.ui._inst = titleInst makeTouchHandle( self, titleInst.ui, self._onTouchTitle ) return titleInst end -- 建立內容項 function g:_createItemInst( data ) if not self._itemCls then log( '沒有設置內容類型!' ) return end local itemInst = self._itemCls.new( ) itemInst.data = data itemInst.ui._inst = itemInst makeTouchHandle2( self, itemInst.ui, self._onTouchItem ) return itemInst end -- 初始化 function g:_initialize( ) self._listView = ccui.ListView:create() self._listView:setBounceEnabled( true ) self._listView:setDirection( ccui.ScrollViewDir.vertical ) self._listView:setSize( self._size ) if not self._groupData then log( '分組數據爲空!' ) return end local titleInst, itemInst self._titleInstList = {} for groupIdx, group in ipairs( self._groupData ) do titleInst = self:_createTitleInst( group ) self._listView:pushBackCustomItem( titleInst.ui ) table.insert( self._titleInstList, titleInst ) -- 展開默認分組 if self._defaultGroupIdx and groupIdx == self._defaultGroupIdx then self.selectedTitle = titleInst for itemIdx, itemData in ipairs( group.items ) do itemInst = self:_createItemInst( itemData ) self._listView:pushBackCustomItem( itemInst.ui ) -- 選中默認項 if self._defaultItemIdx and itemIdx == self._defaultItemIdx then self.selectedItem = itemInst end end end end end --------------------------------------------------------------------------------- -- -- -- 如下定義set, get 部分函數 -- -- -- --------------------------------------------------------------------------------- function g:_getUi( ) return self._listView end -- 是否同時展開多個組 function g:_setShowMulti( value ) self._showMulti = value end -- 獲取數據 function g:_getGroupData( ) return self._groupData end function g:_setGroupData( value ) self._groupData = value end -- 設置默認展開的分組索引 -- @i value function g:_setDefaultGroup( value ) self._defaultGroupIdx = value end -- 設置默認選中的item索引 --@i value function g:_setDefaultItem( value ) self._defaultItemIdx = value end -- 獲取選中的標題項 function g:_getSelectedTitle( ) return self._selectedTitle end function g:_setSelectedTitle( value ) value.selected = true self._selectedTitle = value rm.BindManager.propertyChanged( self, "selectedTitle" ) end -- 獲取選中的內容項 function g:_getSelectedItem( ) return self._selectedItem end function g:_setSelectedItem( value ) if self._selectedItem then self._selectedItem.selected = false end value.selected = true self._selectedItem = value rm.BindManager.propertyChanged( self, "selectedItem" ) end -- 設置點擊item項的回調函數 function g:_setItemClickFunc( value ) self._itemClickFunc = value end -- 設置是否自動選中組中第一個item function g:_setAutoSelectFirstItem( value ) self._autoSelectFirstItem = value end --------------------------------------------------------------------------------- -- -- -- 如下定義公共部分 -- -- -- --------------------------------------------------------------------------------- -- 構造 -- @t size cc.size類型 -- @t groupData 分組數據,結構如{ { title = tData, items = { iData1, iData2 } }, ... } function g:ctor( size, groupData ) self._size = size or cc.size( 200, 200 ) self._groupData = groupData self._titleInstList = nil self._defaultGroupIdx = nil self._defaultItemIdx = nil self._selectedTitle = nil self._selectedItem = nil self._titleCls = nil self._itemCls = nil self._showMulti = false self._autoSelectFirstItem = false self._itemClickFunc = nil end -- 設置標題項和內容項類型 -- @t titleClass 繼承自gm.Common.UIMenuItem,重寫可改變樣式 -- @t itemClass 繼承自gm.Common.UIMenuItem,重寫可改變樣式 function g:setClass( titleClass, itemClass ) self._titleCls = titleClass self._itemCls = itemClass end -- 添加到舞臺 -- @widget parent 父顯示對象 -- @t pos 位置,{ x = , y = } -- @i zOrder 層級 function g:addToParent( parent, pos, zOrder ) if not parent then log( '父顯示對象不可爲空!' ) return end self:_initialize() zOrder = zOrder or 1 pos = pos or cc.p( 0, 0 ) self._listView:setPosition( pos ) parent:addChild( self._listView, zOrder ) end -- 刷新當前展開的分組,只可在互斥(showMulti = false)模式下使用 -- @t group 數據,結構如{ title = tData, items = { iData1, iData2 } } function g:refreshSelectedTitle( group ) if not self._selectedTitle then return end self:refreshTitle( self._selectedTitle, group ) end -- 刷新指定位置的分組 -- @i titleIndex 分組索引 -- @t group 組數據 function g:refreshTitleAtIndex( titleIndex, group ) local title = self._titleInstList( titleIndex ) self:refreshTitle( title, group ) end -- 刷新指定分組 -- @t 某個分組 -- @t group 組數據 function g:refreshTitle( title, group ) local index = self._listView:getIndex( title.ui ) local prevNumItems = title.selected and #title.data.items or 0 local currNumItems = #group.items local deltaNum = prevNumItems - currNumItems local itemInst -- 設置title數據 title:_setData( group ) self._groupData[ table.indexOf( self._titleInstList, title ) ] = group -- title沒展開,如下無需執行 if not title.selected then return end -- 設置item數據 for itemIdx, itemData in ipairs( group.items ) do if itemIdx <= prevNumItems then itemInst = self._listView:getItem( index + itemIdx )._inst itemInst:_setData( itemData ) else itemInst = self:_createItemInst( itemData ) self._listView:insertCustomItem( itemInst.ui, index + itemIdx ) end end -- 舊數量比當前數量多,須要刪除多餘的item if deltaNum > 0 then for i = 1, deltaNum do itemInst = self._listView:getItem( index + currNumItems + 1 )._inst itemInst:finalize() -- 選中項被刪除 if self._selectedItem and self._selectedItem == itemInst then self._selectedItem = nil end self._listView:removeItem( index + currNumItems + 1 ) end end end -- 刷新整個控件 -- @t 控件數據,結構如構造函數同名參數所示 function g:refresh( groupData ) self._groupData = groupData if not self._groupData then log( '分組數據爲空!' ) return end local prevNumTitles = #self._titleInstList local currNumTitles = #groupData local deltaNum = prevNumTitles - currNumTitles local titleInst -- 刷新全部分組 for groupIdx, group in ipairs( groupData ) do if groupIdx <= prevNumTitles then titleInst = self._titleInstList[ groupIdx ] self:refreshTitle( titleInst, group ) else titleInst = self:_createTitleInst( group ) self._listView:pushBackCustomItem( titleInst.ui ) table.insert( self._titleInstList, titleInst ) end end -- 新分組比舊分組少,須要刪除多餘的title if deltaNum > 0 then local numListItems = #self._listView:getItems() -- 清空所有 if currNumTitles == 0 then for i = numListItems - 1, 0, -1 do titleInst = self._listView:getItem( i )._inst titleInst:finalize() end self._listView:removeAllItems() self._titleInstList = {} self._selectedTitle = nil self._selectedItem = nil return end local lastTitleInst = self._titleInstList[ currNumTitles ] local index = self._listView:getIndex( lastTitleInst.ui ) + ( lastTitleInst.selected and #lastTitleInst.data.items or 0 ) for i = numListItems - 1, index + 1, -1 do -- 析構被刪除的title titleInst = self._listView:getItem( i )._inst titleInst:finalize() -- 選中title被刪除 if self._selectedTitle and self._selectedTitle == titleInst then self._selectedTitle = nil end -- 選中項被刪除 if self._selectedItem and self._selectedItem == titleInst then self._selectedItem = nil end self._listView:removeItem( i ) end -- 從title列表中移除 for i = prevNumTitles, currNumTitles + 1, -1 do table.remove( self._titleInstList, i ) end end end -- 析構 function g:finalize() if self._listView then self._listView:removeFromParent() self._listView = nil end self._titleInstList = nil self._groupData = nil self._itemClickFunc = nil end
咱們把摺疊菜單抽象成標題項(title)和內容項(item),title即指標題項,展開標題項顯示出來的內容項叫item。title和item均從uimenuitem派生而來,這們作的好處是咱們能夠方便的更改摺疊菜單標題項和內容項的樣式。
下面來看看uimenuitem.lua:
--[[ 摺疊菜單項 @author cc --]] gm = gm or {} rm = rm or {} local gm = gm local rm = rm gm.Common = gm.Common or {} gm.Common.UIMenuItem = class( "Common.UIMenuItem" ) gm.Common.UIMenuItem._name = "Common.UIMenuItem" local g = gm.Common.UIMenuItem --------------------------------------------------------------------------------- -- -- -- 如下定義私有部分 -- -- -- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- -- -- -- 如下定義set, get 部分函數 -- -- -- --------------------------------------------------------------------------------- -- 獲取顯示對象 function g:_getUi( ) return self._ui end function g:_getData( ) return self._data end -- 設置數據 function g:_setData( value ) self._data = value end function g:_getSelected( ) return self._selected end -- 設置選中狀態 function g:_setSelected( value ) self._selected = value end --------------------------------------------------------------------------------- -- -- -- 如下定義公共部分 -- -- -- --------------------------------------------------------------------------------- -- 構造 function g:ctor( ) self._selected = false self._data = nil self:initialize() end -- 初始化 function g:initialize( ) self._ui = nil end -- 析構 function g:finalize( ) if self._ui then self._ui:removeFromParent( ) self._ui = nil end end
下面舉個簡單的使用例子,
local groupData = { { title = { cate = 1, cate_desc = '技能書' }, items = { { sub_cate = 1, sub_cate_desc = '一級技能書', }, { sub_cate = 2, sub_cate_desc = '二級技能書', }, { sub_cate = 3, sub_cate_desc = '三級技能書', } } }, { title = { cate = 2, cate_desc = '寶石' }, items = { { sub_cate = 1, sub_cate_desc = '攻擊寶石', }, { sub_cate = 2, sub_cate_desc = '暴擊寶石', } } }, { title = { cate = 3, cate_desc = '月石' }, items = { { sub_cate = 1, sub_cate_desc = '很好的月石', } } }, } self._goodsCateList = gm.Common.UIMenuList.new( cc.size( 204, 482 ), groupData ) self._goodsCateList:setClass( gm.Market.MarketMenuTitle, gm.Market.MarketMenuItem ) self._goodsCateList.showMulti = true self._goodsCateList.defaultGroup = 1 self._goodsCateList.defaultItem = 1 self._goodsCateList:addToParent( self._bg, cc.p( 15, 24 ) )
這裏方便演示手寫了分類數據,但通常狀況下是用遍歷生成的。經過上面這段代碼,咱們生成了一個摺疊菜單,效果即本文首部的演示圖片。
這裏用到的兩個類gm.Market.MarketMenuTitle和gm.Market.MarketMenuItem便是用來自定義摺疊菜單樣式的,代碼也一塊貼出:
--[[ 市場摺疊菜單標題項 @author cc --]] gm = gm or {} rm = rm or {} local gm = gm local rm = rm gm.Market = gm.Market or {} gm.Market.MarketMenuTitle = class( "Market.MarketMenuTitle", gm.Common.UIMenuItem ) gm.Market.MarketMenuTitle._name = "Market.MarketMenuTitle" local g = gm.Market.MarketMenuTitle --------------------------------------------------------------------------------- -- -- -- 如下定義私有部分 -- -- -- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- -- -- -- 如下定義set, get 部分函數 -- -- -- --------------------------------------------------------------------------------- -- 設置數據 function g:_setData( value ) self._data = value self._labelName:setText( value.title.cate_desc ) end -- 設置選中狀態 function g:_setSelected( value ) self._selected = value local texture = value and 'tab_btn_4.png' or 'tab_btn_3.png' self._imgBg:loadTexture( texture, ccui.TextureResType.plistType ) end --------------------------------------------------------------------------------- -- -- -- 如下定義公共部分 -- -- -- --------------------------------------------------------------------------------- -- -- 構造 -- function g:ctor( ) -- g.super.ctor( self ) -- end -- 初始化 function g:initialize( ) g.super.initialize( self ) self._ui = ccs.GUIReader:getInstance():widgetFromJsonFile('ui/new_market_menu_title.json') self._labelName = self._ui:getChildByName('LabName') self._imgBg = self._ui:getChildByName('ImgBg') end -- -- 析構 -- function g:finalize( ) -- g.super.finalize( self ) -- end
--[[ 市場摺疊菜單內容項 @author cc --]] gm = gm or {} rm = rm or {} local gm = gm local rm = rm gm.Market = gm.Market or {} gm.Market.MarketMenuItem = class( "Market.MarketMenuItem", gm.Common.UIMenuItem ) gm.Market.MarketMenuItem._name = "Market.MarketMenuItem" local g = gm.Market.MarketMenuItem --------------------------------------------------------------------------------- -- -- -- 如下定義私有部分 -- -- -- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- -- -- -- 如下定義set, get 部分函數 -- -- -- --------------------------------------------------------------------------------- -- 設置數據 function g:_setData( value ) self._data = value self._labelName:setText( value.sub_cate_desc ) end -- 設置選中狀態 function g:_setSelected( value ) self._selected = value self._imgSelected:setVisible( value ) end --------------------------------------------------------------------------------- -- -- -- 如下定義公共部分 -- -- -- --------------------------------------------------------------------------------- -- 構造 function g:ctor( ) g.super.ctor( self ) end -- 初始化 function g:initialize( ) g.super.initialize( self ) self._ui = ccs.GUIReader:getInstance():widgetFromJsonFile('ui/new_market_menu_item.json') self._labelName = self._ui:getChildByName('LabName') self._imgSelected = self._ui:getChildByName('ImgSelected') end -- 析構 function g:finalize( ) g.super.finalize( self ) end