一.概述
本文缩写说明:sv = ScrollView, cell代表ScrollView的一个子节点
本文介绍sv的一种封装类库,来实现快速创建sv,有如下几个优点:
1.item的位置通过参数控制,提高开发效率
2.免去了调用sv的API,提高开发效率
3.分帧创建,提高性能
4.可通过参数控制,复用item类似tableview,提高性能
本文和上一篇Cocos2dx-lua ScrollView[二]进阶篇-CSDN博客
对比有一定相似之处,但也有较多不同,读者可仔细对比代码实现,详细品读,有所取舍和偏爱
二.效果演示
三.代码实现
3.1 说明
a.下面2个模块需要require
b.svCmn是比较复杂的,有必要阅读代码掌握运行原理
c.代码原封不动搬到工程里基本可以正常运行(当然哪里出了问题读者得会排查,本文基本喂饭喂到嘴里了)
d.svCmn经过上线项目验证,可放心使用,在项目中大量推广
3.2 辅助定时器模块:GlobalTimeTicket
GlobalTimeTicket = GlobalTimeTicket or {}auto_id = auto_id or 0
function autoId()auto_id = auto_id + 1return auto_id
end
-- 获取单例
-- New和不New只是一层一层调用__init和__delete,对于单例没有影响
function GlobalTimeTicket:getInstance()if not self.is_init then self.scheduler = cc.Director:getInstance():getScheduler()self.schedulers = {}self.is_init = trueself.is_stop = nilendreturn self
end-- 定时回调 通用版
-- call_back : function 回调函数 必填
-- interval : int 时间间隔 默认1 秒
-- limit_time: int 限制次数 默认0 无限
-- with_name : any 定时器标识 默认自增id
-- 返回用于删除的标识
-- simple : local id = GlobalTimeTicket:getInstance():add(fun) ; GlobalTimeTicket:getInstance():remove(id)
-- : GlobalTimeTicket:getInstance():add(fun, 0.1, 1) -- 次数达到自动删除
-- : GlobalTimeTicket:getInstance():add(fun, 0.1, 3, "name")
function GlobalTimeTicket:add(call_back, interval, limit_time, with_name)if self.is_stop then return endwith_name = with_name or autoId()if nil == call_back or self.schedulers == nil or nil ~= self.schedulers[with_name] then return end -- 已经有定义了,不能重复limit_time = limit_time or 0interval = interval or 1local schedul_hander = self.scheduler:scheduleScriptFunc(function(dt)if self.is_stop then return endif call_back ~= nil thenif limit_time == 1 then self:remove(with_name)elseif limit_time > 1 then limit_time = limit_time - 1endcall_back(dt)endend, interval, false)self.schedulers[with_name] = schedul_handerreturn with_name
end-- 删除一个定时器
function GlobalTimeTicket:remove(with_name)if with_name == nil then return endlocal schedul_hander = self.schedulers[with_name] if schedul_hander ~= nil thenself.scheduler:unscheduleScriptEntry(schedul_hander)self.schedulers[with_name] = nil end
end-- 清除所有定时器
function GlobalTimeTicket:removeAll()for _, v in pairs(self.schedulers) do self.scheduler:unscheduleScriptEntry(v)endself.schedulers = {}
endfunction GlobalTimeTicket:hasTicket(with_name)local schedul_hander = self.schedulers[with_name] if schedul_hander ~= nil thenreturn trueendreturn false
endfunction GlobalTimeTicket:getSchedulers()return self.schedulers
end-- 停止定时器
function GlobalTimeTicket:stop()self.is_stop = trueself:removeAll()
end
3.3 sv封装模块:svCmn
--[[使用例子if not self.svCmn thenlocal setting = {start_x = 18, space_x = 0,start_y = 26, space_y = 6,item_width = 686, item_height = 172,row = 1, col = 1,delay = 4, once_num = 1,}self.svCmn = svCmn.new(self.scr_con, cc.p(0,0) , ScrollViewDir.vertical, ScrollViewStartPos.top, self.scr_con:getContentSize(), setting, cc.p(0, 0))self.svCmn:registerScriptHandlerSingle(handler(self,self.createNewCell), ScrollViewFuncType.CreateNewCell)self.svCmn:registerScriptHandlerSingle(handler(self,self.numberOfCells), ScrollViewFuncType.NumberOfCells)self.svCmn:registerScriptHandlerSingle(handler(self,self.updateCellByIndex), ScrollViewFuncType.UpdateCellByIndex)endself.svCmn:reloadData()
]]----ScrollView的方法类型
ScrollViewFuncType = {UpdateCellByIndex = 1, -- 更新cell体CreateNewCell = 2, -- 创建 新的cell NumberOfCells = 3, -- 返回 数据的数量OnCellTouched = 4, -- 点击cell回调方法
}svCmn = class("svCmn", function()return ccui.Layout:create()
end)function svCmn:ctor(parent, pos, dir, start_pos, size, setting, ap)self.parent = parentself.pos = pos or cc.p(0, 0)self.dir = dir or ScrollViewDir.verticalself.start_pos = start_pos or ScrollViewStartPos.topself.size = size or cc.size(100, 100)self.ap = ap or cc.p(0, 0)self.allCellList = {} --存放cell对象和其坐标,结构:{x, y, cell}, cell存在重复对象, 长度=cell总数量self.cacheList = {} --保存所有实际创建的cell, 长度=cell最大显示数量self.activeCellIdx = {} --保存每个位置的cell当前是否处于显示状态, 长度=cell总数量self.handler = {} --回调方法self.time_show_index = 0 --到时间显示的索引self.is_first_init = true --是否初始化self:analysisSetting(setting)self:createRootWnd()
end--要求规定setting的所有变量 都应该在这里定义出来
function svCmn:analysisSetting(setting)self.setting = setting or {}self.start_x = self.setting.start_x or 0 -- 第一个单元的起点Xself.end_x = self.setting.end_x or self.start_x -- 最后一个单元结束X间隔 如果是nil 默认 和 start_x一致self.start_y = self.setting.start_y or 0 -- 第一个单元的起点Yself.end_y = self.setting.end_y or self.start_y -- 最后一个单元结束Y间隔 如果是nil 默认 和 start_y一致self.space_x = self.setting.space_x or 3 -- 横向间隔空间self.space_y = self.setting.space_y or 3 -- 竖向间隔空间self.item_width = self.setting.item_width or 115 -- 单元的宽度self.item_height = self.setting.item_height or 115 -- 单元的高度self.row = self.setting.row or 5 -- 行数,作用于水平方向的滚动self.col = self.setting.col or 5 -- 列数,作用于垂直方向的滚动self.delay = 1 --self.setting.delay or 4 -- 创建延迟时间 强制改为1 self.once_num = self.setting.once_num or 1 -- 每次创建的数量self.need_dynamic = true -- 默认是无限的self.checkovercallback = self.setting.checkovercallback --滑动回调函数self.is_auto_scroll = setting.is_auto_scroll or false --是否自动判断是否能滚动..个数小于一屏大小时候scroll 不能滚动--位置列表 self.position_data_list = self.setting.position_data_list--固定容器大小 如果有值.将不运算容器大小self.container_width = setting.container_widthself.container_height = setting.container_heightself.inner_hight_offset = setting.inner_hight_offset or 0 -- 内容高度偏移值(仅对纵向有效)--横向的只支持一行的..if self.dir == ScrollViewDir.horizontal thenself.row = 1endself:calculationMaxSum()
endfunction svCmn:updateSetting(setting)if not setting then return endfor k,v in pairs(setting) doself[k] = vend
end--desc:计算一下一屏最多创建的个数
function svCmn:calculationMaxSum()local max_sumif self.dir == ScrollViewDir.horizontal then max_sum = (math.ceil(self.size.width / (self.item_width + self.space_x)) + 1) * self.rowelsemax_sum = (math.ceil(self.size.height / (self.item_height + self.space_y)) + 1) * self.colendself.cacheMaxSize = max_sum
endfunction svCmn:createRootWnd()self:setContentSize(self.size)if not tolua.isnull(self.parent) thenself.parent:addChild(self)endself:setPosition(self.pos)self:setAnchorPoint(self.ap)self.scroll_view = createScrollView(self.size.width, self.size.height, 0, 0, self, self.dir) self.container = self.scroll_view:getInnerContainer() self:registerEvent()
endfunction svCmn:registerEvent()if self.need_dynamic == true thenself.scroll_view:addEventListener(function(sender, eventType)if eventType == ccui.ScrollviewEventType.containerMoved thenself:checkRectIntersectsRect()if self.checkovercallback thenself.checkovercallback()endendend)end
endfunction svCmn:registerScriptHandlerSingle(func, handlerId)self.handler[handlerId] = func
endfunction svCmn:numberOfCells()local cells = ScrollViewFuncType.NumberOfCellsif not self.handler or not self.handler[cells] then return endreturn self.handler[cells]()
end--刷新每一个cell
function svCmn:updateCellByIndex(cell, index)if not self.handler[ScrollViewFuncType.UpdateCellByIndex] then return endif not cell.index thencell.create_index = indexendprint("item刷新ing", "item创建时的索引:"..cell.create_index, "item数据索引变化:" .. (cell.index or "无") .. " -> " .. index)self.handler[ScrollViewFuncType.UpdateCellByIndex](cell, index)
end--创建一个新cell
function svCmn:createNewCell(idx)if not self.handler[ScrollViewFuncType.CreateNewCell] then return endprint("createNewCell", idx)return self.handler[ScrollViewFuncType.CreateNewCell](self.item_width, self.item_height, idx)
end-- --点击cell --在createNewCell 自行实现
function svCmn:onCellTouched(cell, index)if not self.handler[ScrollViewFuncType.OnCellTouched] then return endself.handler[ScrollViewFuncType.OnCellTouched](cell, index)
end--设置 scrollview 是否可点
function svCmn:setClickEnabled(status)self.scroll_view:setTouchEnabled(status)
end
--设置 是否吞噬点击
function svCmn:setSwallowTouches(status)self.scroll_view:setSwallowTouches(status)
endfunction svCmn:setBounceEnabled( status )self.scroll_view:setBounceEnabled(status)
end--desc:移动的过程中盘点是否不再可视范围,不再的时候移除掉,放到对象池,并且准备下一次创建
function svCmn:checkRectIntersectsRect()if self.dir == ScrollViewDir.vertical thenif self.start_pos == ScrollViewStartPos.top thenself:checkOverShowByVertical()else-- 支持ScrollViewStartPos.bottom的了 --by lwcself:checkOverShowByVerticalBottom()endelseif self.dir == ScrollViewDir.horizontal thenself:checkOverShowByHorizontal()end
endfunction svCmn:checkOverShowByVertical()if not self.allCellList then return endlocal container_y = self.container:getPositionY()--计算 视图的上部分和下部分在self.container 的位置local bot = -container_ylocal top = self.size.height + botlocal col_count = math.ceil(#self.allCellList/self.col)--下面因为 self.allCellList 是一维数组 所以要换成二维来算--活跃cell开始行数local activeCellStartRow = 1for i=1, col_count dolocal index = 1 + (i-1)* self.collocal cell = self.allCellList[index]activeCellStartRow = iif cell and cell.y - self.item_height * 0.5 <= top thenbreakendend--活跃cell结束行数local activeCellEndRow = col_countif bot > 0 thenfor i = activeCellStartRow, col_count dolocal index = 1 + (i-1)* self.collocal cell = self.allCellList[index]if cell and cell.y + self.item_height * 0.5 < bot thenactiveCellEndRow = i - 1breakendendend-- print("@保留--> top --> :"..top .." self.col:"..self.col)-- print("@保留--> bot --> :"..bot )-- print("@保留--> 开始行: "..activeCellStartRow.."@结束行: "..activeCellEndRow)local max_count = self:numberOfCells()if max_count thenfor i=1, col_count doif i >= activeCellStartRow and i <= activeCellEndRow thenfor k=1, self.col dolocal index = (i-1) * self.col + kif not self.activeCellIdx[index] thenif index <= max_count thenself:updateCellAtIndex(index)self.activeCellIdx[index] = trueendend endelsefor k=1, self.col dolocal index = (i-1) * self.col + kif index <= max_count thenself.activeCellIdx[index] = falseendendendendend
endfunction svCmn:checkOverShowByVerticalBottom()if not self.allCellList then return endlocal container_y = self.container:getPositionY()--计算 视图的上部分和下部分在self.container 的位置local bot = -container_ylocal top = self.size.height + botlocal col_count = math.ceil(#self.allCellList/self.col)--下面因为 self.allCellList 是一维数组 所以要换成二维来算--活跃cell开始行数local activeCellStartRow = col_countfor i=col_count, 1,-1 dolocal index = 1 + (i-1)* self.collocal cell = self.allCellList[index]activeCellStartRow = iif cell and cell.y - self.item_height * 0.5 <= top thenbreakendend--活跃cell结束行数local activeCellEndRow = 1if bot > 0 thenfor i = activeCellStartRow, 1, -1 dolocal index = 1 + (i-1)* self.collocal cell = self.allCellList[index]if cell and cell.y + self.item_height * 0.5 < bot thenactiveCellEndRow = i + 1breakendendend-- print("@保留--> top --> :"..top .." self.col:"..self.col)-- print("@保留--> bot --> :"..bot )-- print("@保留--> 开始行: "..activeCellStartRow.."@结束行: "..activeCellEndRow)local max_count = self:numberOfCells()for i=1, col_count doif i <= activeCellStartRow and i >= activeCellEndRow thenfor k=1, self.col dolocal index = (i-1) * self.col + kif not self.activeCellIdx[index] thenif index <= max_count thenself:updateCellAtIndex(index)self.activeCellIdx[index] = trueendend endelsefor k=1, self.col dolocal index = (i-1) * self.col + kif index <= max_count thenself.activeCellIdx[index] = falseendendendend
endfunction svCmn:checkOverShowByHorizontal()if not self.allCellList then return endlocal container_x = self.container:getPositionX()--计算 视图的左部分和右部分在self.container 的位置local top = -container_x local bot = top + self.size.widthlocal row_count = #self.allCellList--横向的只支持一行--活跃cell开始行数local activeCellStartRow = 1if top > 0 thenfor index=1, row_count dolocal cell = self.allCellList[index]activeCellStartRow = indexif cell and cell.x + self.item_width * 0.5 >= top thenbreakendendend--活跃cell结束行数local activeCellEndRow = row_countfor index = activeCellStartRow, row_count dolocal cell = self.allCellList[index]if cell and cell.x - self.item_width * 0.5 > bot thenactiveCellEndRow = index - 1breakendend-- print("@保留--> top --> :"..top .." self.row:"..self.row)-- print("@保留--> bot --> :"..bot )-- print("@保留--> 开始行: "..activeCellStartRow.."@结束行: "..activeCellEndRow)local max_count = self:numberOfCells()if max_count thenfor index=1, row_count doif index >= activeCellStartRow and index <= activeCellEndRow thenif not self.activeCellIdx[index] thenif index <= max_count thenself:updateCellAtIndex(index)self.activeCellIdx[index] = trueendend elseif index <= max_count thenself.activeCellIdx[index] = falseendendendend
end--desc:滚动容器移动到指定位置
function svCmn:updateMove(pos)local target_pos = self:checkPosition(pos.x, pos.y)local move_to = cc.MoveTo:create(0.1, cc.p(target_pos.x, target_pos.y))local ease_out = cc.EaseSineOut:create(move_to)self.container:runAction(cc.Sequence:create(ease_out))
endfunction svCmn:jumpToMove(pos, time, callback)local target_pos = self:checkPosition(pos.x, pos.y)time = time or 1local move_to = cc.MoveTo:create(time, cc.p(target_pos.x, target_pos.y))self.container:runAction(cc.Sequence:create(move_to, cc.CallFunc:create(function()if callback thencallback()endend)))
end function svCmn:checkPosition(x, y)local _x, _y = self.container:getPositionX(), self.container:getPositionY()if self.dir == ScrollViewDir.horizontal then_x = _x + xelseif self.dir == ScrollViewDir.vertical then_y = _y + yendif _x > 0 then_x = 0elseif _x < (self.size.width - self.container_size.width) then_x = self.size.width - self.container_size.widthendif _y > 0 then_y = 0elseif _y < (self.size.height - self.container_size.height) then_y = self.size.height - self.container_size.heightendreturn cc.p(_x, _y)
end--获取当前容器的y位置
function svCmn:getCurContainerPosY()if self.container and not tolua.isnull(self.container) thenreturn self.container:getPositionY()end
end
--获取当前容器的x位置
function svCmn:getCurContainerPosX()if self.container and not tolua.isnull(self.container) thenreturn self.container:getPositionX()end
endfunction svCmn:setInnerContainer()local number = self:numberOfCells()local container_width = self.container_width or self.size.widthlocal container_height = self.container_height or self.size.heightif self.dir == ScrollViewDir.horizontal then -- 水平if self.container_width == nil thenlocal num = math.ceil(number / self.row)container_width = num * self.item_width + self.end_x + self.start_x + (num - 1) * self.space_xendelseif self.container_height == nil thenlocal num = math.ceil(number / self.col)container_height = num * self.item_height + self.end_y + self.start_y + (num - 1) * self.space_y + self.inner_hight_offsetendendcontainer_width = math.max(container_width, self.size.width)container_height = math.max(container_height, self.size.height)self.container_size = cc.size(container_width, container_height)--记录在当前的contariner位置..因为在 setInnerContainerSize 方法会被重置self.cur_container_x, self.cur_container_y = self.container:getPosition()self.scroll_view:setInnerContainerSize(self.container_size)if self.start_pos == ScrollViewStartPos.top thenself.scroll_view:jumpToTop()elseif self.start_pos == ScrollViewStartPos.bottom thenself.scroll_view:jumpToBottom()end
end--刷新当前显示的item数据 (不改变任何位置的,前提数据数量没有改变如果有改变用 reload)
function svCmn:resetCurrentItems()for i,v in pairs(self.activeCellIdx) doif v thenself:updateCellAtIndex(i)endend
end--根据index 刷新对应索引..如果在显示视图内
function svCmn:resetItemByIndex(index)-- bodyif self.activeCellIdx[index] thenself:updateCellAtIndex(index)end
end--获取活跃中的cell对象
function svCmn:getActiveCellList()local list = {}for i,v in pairs(self.activeCellIdx) doif v and self.allCellList[i] and self.allCellList[i].cell thentable.insert(list, self.allCellList[i].cell)endendreturn list
end--获取index索引对应cell(不管是否活跃)
function svCmn:getCellByIndex(index)if self.allCellList[index] and self.allCellList[index].cell thenreturn self.allCellList[index].cellend
end--获取index索引对应cellXY位置(不管是否活跃)
function svCmn:getCellXYByIndex(index)if self.allCellList[index] thenreturn self.allCellList[index].x, self.allCellList[index].y end
end--获取index索引对应cellXY位置(不活跃会返回空)
function svCmn:getActiveCellByIndex(index)if self.activeCellIdx[index] and self.allCellList[index] thenreturn self.allCellList[index].cellend
end
--获取当前容器所在显示窗口的x y位置
function svCmn:getContainerXY()if self.container thenlocal x, y = self.container:getPosition()return x, yend
end--获取当前容器所在显示窗口的x y位置
function svCmn:setContainerXY(x, y)if self.container thenif x and y thenself.container:setPosition(x,y)elseif x thenself.container:setPositionX(x) endif y then self.container:setPositionY(y) end endend
end--根据索引判断是否活跃中
function svCmn:isActiveByIndex(index)if self.activeCellIdx[index] thenreturn trueendreturn false
end
--移动到以选中idenx的位置作为在中间 显示 目前只支持y 方向的
function svCmn:jumpToMoveByIndex(index)if not self.allCellList[index] then return endlocal y = self.allCellList[index].y or 0local pos = self.container_size.height - (y + self.size.height * 0.5 )if pos < 0 thenpos = 0endlocal pos_per = pos * 100 / (self.container_size.height - self.size.height)if pos_per ~= pos_per thenpos_per = 0;endif pos_per > 100 thenpos_per = 100endif pos_per == 100 thenif self.start_pos == ScrollViewStartPos.top thenself:checkOverShowByVertical()elseself:checkOverShowByVerticalBottom()endendself.scroll_view:scrollToPercentVertical(pos_per, 0.8, true)
end--desc:设置数据
--select_idnex 从第几个开始
--@setting: 如果有改变的话
--@is_keep_position 是否保持原来位置 --item数量有变化情况. 无变化请用resetCurrentItems
function svCmn:reloadData(select_index, setting, is_keep_position)if setting thenself:updateSetting(setting)endlocal old_width , old_height = 0, 0if self.container_size thenold_width = self.container_size.widthold_height = self.container_size.heightendself.allCellList = {}self.activeCellIdx = {}for k, v in ipairs(self.cacheList) do--相当于隐藏v:setPositionX(-10000)end--设置容器大小self:setInnerContainer()local number = self:numberOfCells()if number == 0 thenreturnendfor i = 1, number dolocal cell = nil if i <= self.time_show_index thencell = self:getCacheCellByIndex(i)endlocal count = #self.allCellListlocal x, yif self.position_data_list thenlocal pos = self.position_data_list[count + 1]if pos thenx, y = pos.x, pos.yelsex, y = self:getCellPosition(count + 1) endelsex, y = self:getCellPosition(count + 1)endlocal cellData = {cell = cell, x = x, y = y}table.insert(self.allCellList, cellData)endif self.is_first_init thenself:startTimeTicket()else--如果时间显示索引小于总数 应该显示继续当前定时器 让下面的能显示出来if self.time_show_index <= number thenself:startTimeTicket()endendif is_keep_position then--是否保持当前显示位置local cur_container_x = self.cur_container_x or 0local cur_container_y = self.cur_container_y or 0if self.dir == ScrollViewDir.vertical then --竖方向if self.start_pos == ScrollViewStartPos.top thenlocal temp_height = self.container_size.height - old_heightcur_container_y = cur_container_y - temp_heightendif cur_container_y > 0 thencur_container_y = 0elseif cur_container_y < (self.size.height - self.container_size.height) thencur_container_y = self.size.height - self.container_size.heightendelseif self.dir == ScrollViewDir.horizontal then --横方向if cur_container_x > 0 thencur_container_x = 0elseif cur_container_x < (self.size.width - self.container_size.width) thencur_container_x = self.size.width - self.container_size.widthendendself.container:setPosition(cur_container_x, cur_container_y)self:checkRectIntersectsRect()elseif select_index == nil thenlocal maxRefreshNum if self.dir == ScrollViewDir.horizontal then -- 水平maxRefreshNum = self.cacheMaxSize - self.rowelsemaxRefreshNum = self.cacheMaxSize - self.colendlocal refreshNum = number < maxRefreshNum and number or maxRefreshNumfor i = 1, refreshNum doif i <= self.time_show_index thenself:updateCellAtIndex(i)endself.activeCellIdx[i] = trueendelseself:selectCellByIndex(select_index)endendif self.is_auto_scroll thenlocal cur_max_count = self.cacheMaxSizeif self.dir == ScrollViewDir.horizontal then cur_max_count = cur_max_count - 2 * self.rowelsecur_max_count = cur_max_count - 2 * self.colendif number <= cur_max_count thenself:setClickEnabled(false)elseself:setClickEnabled(true)endend
end--选中index索引对象(如果列表允许 会排序在开始第一位)
function svCmn:selectCellByIndex(index)local index = index or 1if self.allCellList[index] == nil thenindex = 1endif self.allCellList[index] == nil then return end--一屏幕显示的最大数量local maxRefreshNum if self.dir == ScrollViewDir.horizontal then -- 水平maxRefreshNum = self.cacheMaxSize - self.rowelsemaxRefreshNum = self.cacheMaxSize - self.colendlocal number = self:numberOfCells()if number < maxRefreshNum then--不够显示一屏幕if self.time_show_index == 0 thenself.time_show_index = indexendfor i = 1, number doif i <= self.time_show_index thenself:updateCellAtIndex(i)endself.activeCellIdx[i] = trueendelse--列表允许 情况if self.dir == ScrollViewDir.horizontal then -- 水平--容器x方向位置local container_xif index == 1 thencontainer_x = 0elsecontainer_x = -(self.allCellList[index].x - (self.item_width + self.space_x) * 0.5 )end--容器x方向最大位置local max_contariner_x = -(self.container_size.width - self.size.width)--这两个值都是负数if container_x < max_contariner_x thencontainer_x = max_contariner_xendlocal show_index = math.floor(math.abs(container_x) / self.item_width) + 1if self.time_show_index < show_index thenself.time_show_index = show_indexendself.container:setPositionX(container_x)self:checkRectIntersectsRect()else -- 垂直local container_yif index == 1 thencontainer_y = (self.start_y + self.allCellList[index].y + self.item_height * 0.5) - self.size.height elsecontainer_y = (self.allCellList[index].y + (self.item_height + self.space_y) * 0.5) - self.size.height endif container_y < 0 thencontainer_y = 0endlocal index_1 = math.floor( (self.container_size.height - (container_y + self.size.height)) / self.item_height) + 1local show_index = (index_1 - 1) * self.col + 1if self.time_show_index < show_index thenself.time_show_index = show_indexendself.container:setPositionY(- container_y)self:checkRectIntersectsRect()endendif index > 0 and index <= self:numberOfCells() thenlocal cell = self:getCacheCellByIndex(index)cell.index = indexself.allCellList[index].cell = cellself:onCellTouched(cell, index)end
endfunction svCmn:setOnCellTouched(index)local cell = self:getCacheCellByIndex(index)cell.index = indexself.allCellList[index].cell = cellself:onCellTouched(cell, index)
endfunction svCmn:startTimeTicket()if self.time_ticket == nil thenif #self.allCellList == 0 thenreturnend--到时间显示的索引local once_num = self.once_num or 1local _callback = function()if tolua.isnull(self.container) then return endlocal count = self.time_show_index + once_numlocal index = self.time_show_index + 1if index == 0 thenindex = 1endlocal size = #self.allCellListself.time_show_index = self.time_show_index + once_numfor i = index, count doif i > size then--超过总数了breakendlocal cellData = self.allCellList[i]if cellData and cellData.cell == nil thencellData.cell = self:getCacheCellByIndex(i)endif self.activeCellIdx[i] thenself:updateCellAtIndex(i)endendif self.time_show_index >= size thenself:clearTimeTicket()self.is_first_init = falseendendself.time_ticket = GlobalTimeTicket:getInstance():add(_callback, self.delay / display.DEFAULT_FPS)end
endfunction svCmn:clearTimeTicket()if self.time_ticket ~= nil thenGlobalTimeTicket:getInstance():remove(self.time_ticket)self.time_ticket = nilend
end function svCmn:getCellPosition(index)local cur_item_index = indexlocal anchor_point = cc.p(0.5,0.5)local _x, _y = 0, 0if self.dir == ScrollViewDir.horizontal then_x = self.start_x + self.item_width * anchor_point.x +(self.item_width + self.space_x) *(math.floor((index - 1) / self.row))_y = self.container_size.height -(self.start_y + self.item_height *(1 - anchor_point.y) +((index - 1) % self.row) *(self.item_height + self.space_y))elseif self.start_pos == ScrollViewStartPos.top then_x = self.start_x + self.item_width * anchor_point.x + (self.item_width + self.space_x) *((index - 1) % self.col)_y = self.container_size.height -(self.start_y + self.item_height *(1 - anchor_point.y) +(math.floor((index - 1) / self.col)) *(self.item_height + self.space_y))else_x = self.start_x + self.item_width * anchor_point.x +(self.item_width + self.space_x) *((index - 1) % self.col)_y = self.start_y + self.item_height * anchor_point.y +(math.floor((index - 1) / self.col)) *(self.item_height + self.space_y)endendreturn _x, _y
end--通过创建或复用的方式,获取index对应的cell对象
function svCmn:getCacheCellByIndex(index)local cacheIndex = (index - 1) % self.cacheMaxSize + 1if not self.cacheList[cacheIndex] thenlocal newCell = self:createNewCell(index)if newCell thennewCell:setAnchorPoint(cc.p(0.5, 0.5))newCell:setPositionX(-10000)--隐藏self.cacheList[cacheIndex] = newCellself.scroll_view:addChild(newCell)endreturn newCellelsereturn self.cacheList[cacheIndex]end
end--cell设置位置,并刷新cell的UI
function svCmn:updateCellAtIndex(index)if index > self.time_show_index thenreturnendif not self.allCellList[index] then return endlocal cellData = self.allCellList[index]if cellData.cell == nil thencellData.cell = self:getCacheCellByIndex(index) --self.allCellList的cell赋值在这里endcellData.cell:setPosition(cellData.x, cellData.y)self:updateCellByIndex(cellData.cell, index)
endfunction svCmn:clearTimeTicket()if self.time_ticket ~= nil thenGlobalTimeTicket:getInstance():remove(self.time_ticket)self.time_ticket = nilend
end function svCmn:getMaxSize()return self.container_size
endfunction svCmn:getContainer()return self.container
endfunction svCmn:scrollToPercentVertical( percent, time )if percent ~= percent then percent = 0 endself.scroll_view:scrollToPercentVertical(percent, time, true)
endfunction svCmn:DeleteMe()doStopAllActions(self.container)self:clearTimeTicket()for k, item in ipairs(self.cacheList) doif item.DeleteMe thenitem:DeleteMe()endendself.allCellList = nilself.activeCellIdx = nilself.cacheList = nilself:removeAllChildren()self:removeFromParent()
end
3.4 应用举例
function ModuleTest:updateSVCmn()self.cellData = {[1] = {index = 1},[2] = {index = 2},[3] = {index = 3},[4] = {index = 4},[5] = {index = 5},[6] = {index = 6},[7] = {index = 7},[8] = {index = 8},[9] = {index = 9},[10] = {index = 10},[11] = {index = 11},[12] = {index = 12},}if not self.svCmn thenlocal setting = {start_x = 18, space_x = 0,start_y = 26, space_y = 6,item_width = 686, item_height = 172,row = 1, col = 1,delay = 4, once_num = 1,}self.svCmn = svCmn.new(self.scr_con, cc.p(0,0) , ScrollViewDir.vertical, ScrollViewStartPos.top, self.scr_con:getContentSize(), setting, cc.p(0, 0))self.svCmn:registerScriptHandlerSingle(handler(self,self.createNewCell), ScrollViewFuncType.CreateNewCell)self.svCmn:registerScriptHandlerSingle(handler(self,self.numberOfCells), ScrollViewFuncType.NumberOfCells)self.svCmn:registerScriptHandlerSingle(handler(self,self.updateCellByIndex), ScrollViewFuncType.UpdateCellByIndex)endself.svCmn:reloadData()
endfunction ModuleTest:createNewCell(width, height)local cell = ActionCommonItem.new()return cell
endfunction ModuleTest:numberOfCells()if not self.cellData then return 0 endreturn #self.cellData
endfunction ModuleTest:updateCellByIndex(cell, index)local onecellData = self.cellData[index]cell.root_wnd:getChildByName("label"):setString(onecellData.index)
end