一.概述
本文缩写说明: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
Lua
GlobalTimeTicket = GlobalTimeTicket or {}
auto_id = auto_id or 0
function autoId()
auto_id = auto_id + 1
return 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 = true
self.is_stop = nil
end
return 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 end
with_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 0
interval = interval or 1
local schedul_hander = self.scheduler:scheduleScriptFunc(function(dt)
if self.is_stop then return end
if call_back ~= nil then
if limit_time == 1 then
self:remove(with_name)
elseif limit_time > 1 then
limit_time = limit_time - 1
end
call_back(dt)
end
end, interval, false)
self.schedulers[with_name] = schedul_hander
return with_name
end
-- 删除一个定时器
function GlobalTimeTicket:remove(with_name)
if with_name == nil then return end
local schedul_hander = self.schedulers[with_name]
if schedul_hander ~= nil then
self.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)
end
self.schedulers = {}
end
function GlobalTimeTicket:hasTicket(with_name)
local schedul_hander = self.schedulers[with_name]
if schedul_hander ~= nil then
return true
end
return false
end
function GlobalTimeTicket:getSchedulers()
return self.schedulers
end
-- 停止定时器
function GlobalTimeTicket:stop()
self.is_stop = true
self:removeAll()
end
3.3 sv封装模块:svCmn
Lua
--[[使用例子
if not self.svCmn then
local 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)
end
self.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 = parent
self.pos = pos or cc.p(0, 0)
self.dir = dir or ScrollViewDir.vertical
self.start_pos = start_pos or ScrollViewStartPos.top
self.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 -- 第一个单元的起点X
self.end_x = self.setting.end_x or self.start_x -- 最后一个单元结束X间隔 如果是nil 默认 和 start_x一致
self.start_y = self.setting.start_y or 0 -- 第一个单元的起点Y
self.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_width
self.container_height = setting.container_height
self.inner_hight_offset = setting.inner_hight_offset or 0 -- 内容高度偏移值(仅对纵向有效)
--横向的只支持一行的..
if self.dir == ScrollViewDir.horizontal then
self.row = 1
end
self:calculationMaxSum()
end
function svCmn:updateSetting(setting)
if not setting then return end
for k,v in pairs(setting) do
self[k] = v
end
end
--desc:计算一下一屏最多创建的个数
function svCmn:calculationMaxSum()
local max_sum
if self.dir == ScrollViewDir.horizontal then
max_sum = (math.ceil(self.size.width / (self.item_width + self.space_x)) + 1) * self.row
else
max_sum = (math.ceil(self.size.height / (self.item_height + self.space_y)) + 1) * self.col
end
self.cacheMaxSize = max_sum
end
function svCmn:createRootWnd()
self:setContentSize(self.size)
if not tolua.isnull(self.parent) then
self.parent:addChild(self)
end
self: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()
end
function svCmn:registerEvent()
if self.need_dynamic == true then
self.scroll_view:addEventListener(function(sender, eventType)
if eventType == ccui.ScrollviewEventType.containerMoved then
self:checkRectIntersectsRect()
if self.checkovercallback then
self.checkovercallback()
end
end
end)
end
end
function svCmn:registerScriptHandlerSingle(func, handlerId)
self.handler[handlerId] = func
end
function svCmn:numberOfCells()
local cells = ScrollViewFuncType.NumberOfCells
if not self.handler or not self.handler[cells] then return end
return self.handler[cells]()
end
--刷新每一个cell
function svCmn:updateCellByIndex(cell, index)
if not self.handler[ScrollViewFuncType.UpdateCellByIndex] then return end
if not cell.index then
cell.create_index = index
end
print("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 end
print("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 end
self.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)
end
function svCmn:setBounceEnabled( status )
self.scroll_view:setBounceEnabled(status)
end
--desc:移动的过程中盘点是否不再可视范围,不再的时候移除掉,放到对象池,并且准备下一次创建
function svCmn:checkRectIntersectsRect()
if self.dir == ScrollViewDir.vertical then
if self.start_pos == ScrollViewStartPos.top then
self:checkOverShowByVertical()
else
-- 支持ScrollViewStartPos.bottom的了 --by lwc
self:checkOverShowByVerticalBottom()
end
elseif self.dir == ScrollViewDir.horizontal then
self:checkOverShowByHorizontal()
end
end
function svCmn:checkOverShowByVertical()
if not self.allCellList then return end
local container_y = self.container:getPositionY()
--计算 视图的上部分和下部分在self.container 的位置
local bot = -container_y
local top = self.size.height + bot
local col_count = math.ceil(#self.allCellList/self.col)
--下面因为 self.allCellList 是一维数组 所以要换成二维来算
--活跃cell开始行数
local activeCellStartRow = 1
for i=1, col_count do
local index = 1 + (i-1)* self.col
local cell = self.allCellList[index]
activeCellStartRow = i
if cell and cell.y - self.item_height * 0.5 <= top then
break
end
end
--活跃cell结束行数
local activeCellEndRow = col_count
if bot > 0 then
for i = activeCellStartRow, col_count do
local index = 1 + (i-1)* self.col
local cell = self.allCellList[index]
if cell and cell.y + self.item_height * 0.5 < bot then
activeCellEndRow = i - 1
break
end
end
end
-- print("@保留--> top --> :"..top .." self.col:"..self.col)
-- print("@保留--> bot --> :"..bot )
-- print("@保留--> 开始行: "..activeCellStartRow.."@结束行: "..activeCellEndRow)
local max_count = self:numberOfCells()
if max_count then
for i=1, col_count do
if i >= activeCellStartRow and i <= activeCellEndRow then
for k=1, self.col do
local index = (i-1) * self.col + k
if not self.activeCellIdx[index] then
if index <= max_count then
self:updateCellAtIndex(index)
self.activeCellIdx[index] = true
end
end
end
else
for k=1, self.col do
local index = (i-1) * self.col + k
if index <= max_count then
self.activeCellIdx[index] = false
end
end
end
end
end
end
function svCmn:checkOverShowByVerticalBottom()
if not self.allCellList then return end
local container_y = self.container:getPositionY()
--计算 视图的上部分和下部分在self.container 的位置
local bot = -container_y
local top = self.size.height + bot
local col_count = math.ceil(#self.allCellList/self.col)
--下面因为 self.allCellList 是一维数组 所以要换成二维来算
--活跃cell开始行数
local activeCellStartRow = col_count
for i=col_count, 1,-1 do
local index = 1 + (i-1)* self.col
local cell = self.allCellList[index]
activeCellStartRow = i
if cell and cell.y - self.item_height * 0.5 <= top then
break
end
end
--活跃cell结束行数
local activeCellEndRow = 1
if bot > 0 then
for i = activeCellStartRow, 1, -1 do
local index = 1 + (i-1)* self.col
local cell = self.allCellList[index]
if cell and cell.y + self.item_height * 0.5 < bot then
activeCellEndRow = i + 1
break
end
end
end
-- print("@保留--> top --> :"..top .." self.col:"..self.col)
-- print("@保留--> bot --> :"..bot )
-- print("@保留--> 开始行: "..activeCellStartRow.."@结束行: "..activeCellEndRow)
local max_count = self:numberOfCells()
for i=1, col_count do
if i <= activeCellStartRow and i >= activeCellEndRow then
for k=1, self.col do
local index = (i-1) * self.col + k
if not self.activeCellIdx[index] then
if index <= max_count then
self:updateCellAtIndex(index)
self.activeCellIdx[index] = true
end
end
end
else
for k=1, self.col do
local index = (i-1) * self.col + k
if index <= max_count then
self.activeCellIdx[index] = false
end
end
end
end
end
function svCmn:checkOverShowByHorizontal()
if not self.allCellList then return end
local container_x = self.container:getPositionX()
--计算 视图的左部分和右部分在self.container 的位置
local top = -container_x
local bot = top + self.size.width
local row_count = #self.allCellList
--横向的只支持一行
--活跃cell开始行数
local activeCellStartRow = 1
if top > 0 then
for index=1, row_count do
local cell = self.allCellList[index]
activeCellStartRow = index
if cell and cell.x + self.item_width * 0.5 >= top then
break
end
end
end
--活跃cell结束行数
local activeCellEndRow = row_count
for index = activeCellStartRow, row_count do
local cell = self.allCellList[index]
if cell and cell.x - self.item_width * 0.5 > bot then
activeCellEndRow = index - 1
break
end
end
-- print("@保留--> top --> :"..top .." self.row:"..self.row)
-- print("@保留--> bot --> :"..bot )
-- print("@保留--> 开始行: "..activeCellStartRow.."@结束行: "..activeCellEndRow)
local max_count = self:numberOfCells()
if max_count then
for index=1, row_count do
if index >= activeCellStartRow and index <= activeCellEndRow then
if not self.activeCellIdx[index] then
if index <= max_count then
self:updateCellAtIndex(index)
self.activeCellIdx[index] = true
end
end
else
if index <= max_count then
self.activeCellIdx[index] = false
end
end
end
end
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))
end
function svCmn:jumpToMove(pos, time, callback)
local target_pos = self:checkPosition(pos.x, pos.y)
time = time or 1
local 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 then
callback()
end
end)))
end
function svCmn:checkPosition(x, y)
local _x, _y = self.container:getPositionX(), self.container:getPositionY()
if self.dir == ScrollViewDir.horizontal then
_x = _x + x
elseif self.dir == ScrollViewDir.vertical then
_y = _y + y
end
if _x > 0 then
_x = 0
elseif _x < (self.size.width - self.container_size.width) then
_x = self.size.width - self.container_size.width
end
if _y > 0 then
_y = 0
elseif _y < (self.size.height - self.container_size.height) then
_y = self.size.height - self.container_size.height
end
return cc.p(_x, _y)
end
--获取当前容器的y位置
function svCmn:getCurContainerPosY()
if self.container and not tolua.isnull(self.container) then
return self.container:getPositionY()
end
end
--获取当前容器的x位置
function svCmn:getCurContainerPosX()
if self.container and not tolua.isnull(self.container) then
return self.container:getPositionX()
end
end
function svCmn:setInnerContainer()
local number = self:numberOfCells()
local container_width = self.container_width or self.size.width
local container_height = self.container_height or self.size.height
if self.dir == ScrollViewDir.horizontal then -- 水平
if self.container_width == nil then
local num = math.ceil(number / self.row)
container_width = num * self.item_width + self.end_x + self.start_x + (num - 1) * self.space_x
end
else
if self.container_height == nil then
local 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_offset
end
end
container_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 then
self.scroll_view:jumpToTop()
elseif self.start_pos == ScrollViewStartPos.bottom then
self.scroll_view:jumpToBottom()
end
end
--刷新当前显示的item数据 (不改变任何位置的,前提数据数量没有改变如果有改变用 reload)
function svCmn:resetCurrentItems()
for i,v in pairs(self.activeCellIdx) do
if v then
self:updateCellAtIndex(i)
end
end
end
--根据index 刷新对应索引..如果在显示视图内
function svCmn:resetItemByIndex(index)
-- body
if self.activeCellIdx[index] then
self:updateCellAtIndex(index)
end
end
--获取活跃中的cell对象
function svCmn:getActiveCellList()
local list = {}
for i,v in pairs(self.activeCellIdx) do
if v and self.allCellList[i] and self.allCellList[i].cell then
table.insert(list, self.allCellList[i].cell)
end
end
return list
end
--获取index索引对应cell(不管是否活跃)
function svCmn:getCellByIndex(index)
if self.allCellList[index] and self.allCellList[index].cell then
return self.allCellList[index].cell
end
end
--获取index索引对应cellXY位置(不管是否活跃)
function svCmn:getCellXYByIndex(index)
if self.allCellList[index] then
return self.allCellList[index].x, self.allCellList[index].y
end
end
--获取index索引对应cellXY位置(不活跃会返回空)
function svCmn:getActiveCellByIndex(index)
if self.activeCellIdx[index] and self.allCellList[index] then
return self.allCellList[index].cell
end
end
--获取当前容器所在显示窗口的x y位置
function svCmn:getContainerXY()
if self.container then
local x, y = self.container:getPosition()
return x, y
end
end
--获取当前容器所在显示窗口的x y位置
function svCmn:setContainerXY(x, y)
if self.container then
if x and y then
self.container:setPosition(x,y)
else
if x then
self.container:setPositionX(x)
end
if y then
self.container:setPositionY(y)
end
end
end
end
--根据索引判断是否活跃中
function svCmn:isActiveByIndex(index)
if self.activeCellIdx[index] then
return true
end
return false
end
--移动到以选中idenx的位置作为在中间 显示 目前只支持y 方向的
function svCmn:jumpToMoveByIndex(index)
if not self.allCellList[index] then return end
local y = self.allCellList[index].y or 0
local pos = self.container_size.height - (y + self.size.height * 0.5 )
if pos < 0 then
pos = 0
end
local pos_per = pos * 100 / (self.container_size.height - self.size.height)
if pos_per ~= pos_per then
pos_per = 0;
end
if pos_per > 100 then
pos_per = 100
end
if pos_per == 100 then
if self.start_pos == ScrollViewStartPos.top then
self:checkOverShowByVertical()
else
self:checkOverShowByVerticalBottom()
end
end
self.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 then
self:updateSetting(setting)
end
local old_width , old_height = 0, 0
if self.container_size then
old_width = self.container_size.width
old_height = self.container_size.height
end
self.allCellList = {}
self.activeCellIdx = {}
for k, v in ipairs(self.cacheList) do
--相当于隐藏
v:setPositionX(-10000)
end
--设置容器大小
self:setInnerContainer()
local number = self:numberOfCells()
if number == 0 then
return
end
for i = 1, number do
local cell = nil
if i <= self.time_show_index then
cell = self:getCacheCellByIndex(i)
end
local count = #self.allCellList
local x, y
if self.position_data_list then
local pos = self.position_data_list[count + 1]
if pos then
x, y = pos.x, pos.y
else
x, y = self:getCellPosition(count + 1)
end
else
x, y = self:getCellPosition(count + 1)
end
local cellData = {cell = cell, x = x, y = y}
table.insert(self.allCellList, cellData)
end
if self.is_first_init then
self:startTimeTicket()
else
--如果时间显示索引小于总数 应该显示继续当前定时器 让下面的能显示出来
if self.time_show_index <= number then
self:startTimeTicket()
end
end
if is_keep_position then
--是否保持当前显示位置
local cur_container_x = self.cur_container_x or 0
local cur_container_y = self.cur_container_y or 0
if self.dir == ScrollViewDir.vertical then --竖方向
if self.start_pos == ScrollViewStartPos.top then
local temp_height = self.container_size.height - old_height
cur_container_y = cur_container_y - temp_height
end
if cur_container_y > 0 then
cur_container_y = 0
elseif cur_container_y < (self.size.height - self.container_size.height) then
cur_container_y = self.size.height - self.container_size.height
end
elseif self.dir == ScrollViewDir.horizontal then --横方向
if cur_container_x > 0 then
cur_container_x = 0
elseif cur_container_x < (self.size.width - self.container_size.width) then
cur_container_x = self.size.width - self.container_size.width
end
end
self.container:setPosition(cur_container_x, cur_container_y)
self:checkRectIntersectsRect()
else
if select_index == nil then
local maxRefreshNum
if self.dir == ScrollViewDir.horizontal then -- 水平
maxRefreshNum = self.cacheMaxSize - self.row
else
maxRefreshNum = self.cacheMaxSize - self.col
end
local refreshNum = number < maxRefreshNum and number or maxRefreshNum
for i = 1, refreshNum do
if i <= self.time_show_index then
self:updateCellAtIndex(i)
end
self.activeCellIdx[i] = true
end
else
self:selectCellByIndex(select_index)
end
end
if self.is_auto_scroll then
local cur_max_count = self.cacheMaxSize
if self.dir == ScrollViewDir.horizontal then
cur_max_count = cur_max_count - 2 * self.row
else
cur_max_count = cur_max_count - 2 * self.col
end
if number <= cur_max_count then
self:setClickEnabled(false)
else
self:setClickEnabled(true)
end
end
end
--选中index索引对象(如果列表允许 会排序在开始第一位)
function svCmn:selectCellByIndex(index)
local index = index or 1
if self.allCellList[index] == nil then
index = 1
end
if self.allCellList[index] == nil then return end
--一屏幕显示的最大数量
local maxRefreshNum
if self.dir == ScrollViewDir.horizontal then -- 水平
maxRefreshNum = self.cacheMaxSize - self.row
else
maxRefreshNum = self.cacheMaxSize - self.col
end
local number = self:numberOfCells()
if number < maxRefreshNum then
--不够显示一屏幕
if self.time_show_index == 0 then
self.time_show_index = index
end
for i = 1, number do
if i <= self.time_show_index then
self:updateCellAtIndex(i)
end
self.activeCellIdx[i] = true
end
else
--列表允许 情况
if self.dir == ScrollViewDir.horizontal then -- 水平
--容器x方向位置
local container_x
if index == 1 then
container_x = 0
else
container_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 then
container_x = max_contariner_x
end
local show_index = math.floor(math.abs(container_x) / self.item_width) + 1
if self.time_show_index < show_index then
self.time_show_index = show_index
end
self.container:setPositionX(container_x)
self:checkRectIntersectsRect()
else -- 垂直
local container_y
if index == 1 then
container_y = (self.start_y + self.allCellList[index].y + self.item_height * 0.5) - self.size.height
else
container_y = (self.allCellList[index].y + (self.item_height + self.space_y) * 0.5) - self.size.height
end
if container_y < 0 then
container_y = 0
end
local index_1 = math.floor( (self.container_size.height - (container_y + self.size.height)) / self.item_height) + 1
local show_index = (index_1 - 1) * self.col + 1
if self.time_show_index < show_index then
self.time_show_index = show_index
end
self.container:setPositionY(- container_y)
self:checkRectIntersectsRect()
end
end
if index > 0 and index <= self:numberOfCells() then
local cell = self:getCacheCellByIndex(index)
cell.index = index
self.allCellList[index].cell = cell
self:onCellTouched(cell, index)
end
end
function svCmn:setOnCellTouched(index)
local cell = self:getCacheCellByIndex(index)
cell.index = index
self.allCellList[index].cell = cell
self:onCellTouched(cell, index)
end
function svCmn:startTimeTicket()
if self.time_ticket == nil then
if #self.allCellList == 0 then
return
end
--到时间显示的索引
local once_num = self.once_num or 1
local _callback = function()
if tolua.isnull(self.container) then return end
local count = self.time_show_index + once_num
local index = self.time_show_index + 1
if index == 0 then
index = 1
end
local size = #self.allCellList
self.time_show_index = self.time_show_index + once_num
for i = index, count do
if i > size then
--超过总数了
break
end
local cellData = self.allCellList[i]
if cellData and cellData.cell == nil then
cellData.cell = self:getCacheCellByIndex(i)
end
if self.activeCellIdx[i] then
self:updateCellAtIndex(i)
end
end
if self.time_show_index >= size then
self:clearTimeTicket()
self.is_first_init = false
end
end
self.time_ticket = GlobalTimeTicket:getInstance():add(_callback, self.delay / display.DEFAULT_FPS)
end
end
function svCmn:clearTimeTicket()
if self.time_ticket ~= nil then
GlobalTimeTicket:getInstance():remove(self.time_ticket)
self.time_ticket = nil
end
end
function svCmn:getCellPosition(index)
local cur_item_index = index
local anchor_point = cc.p(0.5,0.5)
local _x, _y = 0, 0
if 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))
else
if 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)
end
end
return _x, _y
end
--通过创建或复用的方式,获取index对应的cell对象
function svCmn:getCacheCellByIndex(index)
local cacheIndex = (index - 1) % self.cacheMaxSize + 1
if not self.cacheList[cacheIndex] then
local newCell = self:createNewCell(index)
if newCell then
newCell:setAnchorPoint(cc.p(0.5, 0.5))
newCell:setPositionX(-10000)--隐藏
self.cacheList[cacheIndex] = newCell
self.scroll_view:addChild(newCell)
end
return newCell
else
return self.cacheList[cacheIndex]
end
end
--cell设置位置,并刷新cell的UI
function svCmn:updateCellAtIndex(index)
if index > self.time_show_index then
return
end
if not self.allCellList[index] then return end
local cellData = self.allCellList[index]
if cellData.cell == nil then
cellData.cell = self:getCacheCellByIndex(index) --self.allCellList的cell赋值在这里
end
cellData.cell:setPosition(cellData.x, cellData.y)
self:updateCellByIndex(cellData.cell, index)
end
function svCmn:clearTimeTicket()
if self.time_ticket ~= nil then
GlobalTimeTicket:getInstance():remove(self.time_ticket)
self.time_ticket = nil
end
end
function svCmn:getMaxSize()
return self.container_size
end
function svCmn:getContainer()
return self.container
end
function svCmn:scrollToPercentVertical( percent, time )
if percent ~= percent then percent = 0 end
self.scroll_view:scrollToPercentVertical(percent, time, true)
end
function svCmn:DeleteMe()
doStopAllActions(self.container)
self:clearTimeTicket()
for k, item in ipairs(self.cacheList) do
if item.DeleteMe then
item:DeleteMe()
end
end
self.allCellList = nil
self.activeCellIdx = nil
self.cacheList = nil
self:removeAllChildren()
self:removeFromParent()
end
3.4 应用举例
Lua
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 then
local 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)
end
self.svCmn:reloadData()
end
function ModuleTest:createNewCell(width, height)
local cell = ActionCommonItem.new()
return cell
end
function ModuleTest:numberOfCells()
if not self.cellData then return 0 end
return #self.cellData
end
function ModuleTest:updateCellByIndex(cell, index)
local onecellData = self.cellData[index]
cell.root_wnd:getChildByName("label"):setString(onecellData.index)
end