您的位置:首页 > 大数据 > 人工智能

FastScrollView实现及其setContentSize与setInnerContainerSize理解

2017-01-22 10:41 423 查看
FastScrollDataSource  = FastScrollDataSource  or { }

function FastScrollDataSource:getTotalSize( )
end

function FastScrollDataSource:setData( node, dataIndex )
end

FastScrollView = FastScrollView or { }

FastScrollView = class("FastScrollView", function()
local view = ccui.ScrollView:create()
UI.fixScrollView(view)
return view
end)

function FastScrollView:create()
local view = FastScrollView:new()
view: __init( )
return view
end

function FastScrollView:__init()
self.node_list = { }
self:addEventListener( function( sender, eventType )
self:scrollCallback(eventType)
end )
end

function FastScrollView:setScrollSize( rowSize, columnSize, cellWidth, cellHeight  )
self.rowSize = rowSize
self.columnSize = columnSize
self.cellWidth = cellWidth
self.cellHeight = cellHeight
end

function FastScrollView:addScrollNode( node )
table.insert( self.node_list , node )
self:addChild( node )
UI.setVisible( node , false )
end

function FastScrollView:setModel( dataSource )

self.dataSource = dataSource
self.totalSize = dataSource:getTotalSize( )
self.maxVisibleSize = -1
self.newIndex = -1

local contentSize = self:getContentSize()

self.canScrollCallback  = false

local direction = self:getDirection()
if direction == ccui.ScrollViewDir.vertical then
local totalRow = math.ceil( self.totalSize  / self.columnSize )
local totalHeight = totalRow * self.cellHeight
if  totalHeight <= contentSize.height then
totalHeight = contentSize.height
end
self:setInnerContainerSize( cc.size( contentSize.width, totalHeight ) )
self:jumpToTop()
elseif direction == ccui.ScrollViewDir.horizontal then
local totalColumn = math.ceil( self.totalSize / self.rowSize )
local totalWidth = totalColumn * self.cellWidth
if totalWidth <= contentSize.width then
totalWidth = contentSize.width
end
self:setInnerContainerSize( cc.size( totalWidth, contentSize.height ) )
self:jumpToLeft()
end
self.canScrollCallback = true

self.splitItemList = {}
self:updateView( )
end

-- 此方法为船坞添加分割使用
function FastScrollView:setSplitOffsetValue( splitIndex , splitItemHeight )
self.splitIndex = splitIndex
self.splitItemHeight = splitItemHeight
end

function FastScrollView:setScrollListenerCallback( callback )
self.listenerCallback = callback
end

function FastScrollView:updateView( )
local posValue , scrLength , cellLength , start

local direction = self:getDirection()
if direction == ccui.ScrollViewDir.vertical then
posValue = self:getInnerContainer():getPositionY()
cellLength = self.cellHeight
scrLength = self:getInnerContainer():getContentSize().height
start = (posValue + scrLength) - self:getContentSize().height
if self.splitIndex and self.splitItemHeight then
if start > self.splitIndex * self.cellHeight then
start = start - self.splitItemHeight
end
end
if start < 0.5 then
start = 0.5
elseif start > (posValue + scrLength + 0.5) then
start = (posValue + scrLength + 0.5)
end
elseif direction == ccui.ScrollViewDir.horizontal then
cellLength = self.cellWidth
start = -self:getInnerContainer():getPositionX()
if start < 0.5 then
start = 0.5
elseif start > (self:getInnerContainer():getContentSize().width - self:getContentSize().width + 0.5) then
start = (self:getInnerContainer():getContentSize().width - self:getContentSize().width + 0.5)
end
end

local newIndex = math.ceil( start / cellLength )
if newIndex ~= self.newIndex then
local oldIndex = self.newIndex
self.newIndex = newIndex
self:updateInnerNode( newIndex , oldIndex )
end
end

function FastScrollView:updateInnerNode( newIndex , oldIndex )
local totalIndex = self.rowSize * self.columnSize
local itemSize
local cellWidth , cellHeight = self.cellWidth , self.cellHeight
local totalLength

local direction = self:getDirection()
if direction == ccui.ScrollViewDir.vertical then
itemSize = self.columnSize
totalLength = self:getInnerContainer():getContentSize().height
elseif direction == ccui.ScrollViewDir.horizontal then
itemSize = self.rowSize
totalLength = self:getInnerContainer():getContentSize().width
end

local startIndex = (newIndex - 1) * itemSize + 1
local endIndex = startIndex + totalIndex - 1
if endIndex > self.totalSize then
endIndex = self.totalSize
end

local maxVisibleSize = ( endIndex - startIndex + 1 )
local oldVisibleSize = self.maxVisibleSize
self.maxVisibleSize = maxVisibleSize
local node_list = self.node_list
local dataSource = self.dataSource
local curNode = nil

-- 如果是第一次
local startIndexToSet = 1
local endIndexToSet = maxVisibleSize

if oldVisibleSize and  oldVisibleSize >= 0 then
if newIndex > oldIndex then
--头部调到尾部
local adjustSize = ( newIndex - oldIndex ) * itemSize
for i = 1, adjustSize do
curNode = node_list[ 1 ]
table.remove( node_list , 1 )
table.insert( node_list, curNode )
end

-- 从上次显示结尾位置开始
startIndexToSet = (  oldVisibleSize - adjustSize + 1 )
endIndexToSet = maxVisibleSize
else
--尾部调整到头部
local adjustSize = ( oldIndex - newIndex ) * itemSize
for i = 1, adjustSize do
curNode = node_list[ totalIndex ]
table.remove( node_list , totalIndex )
table.insert( node_list, 1,  curNode )
end

--从开始显示到调整的位置
startIndexToSet = 1
endIndexToSet = adjustSize
end
end

if startIndexToSet < 1 then
startIndexToSet = 1
end

-- 需要重设的节点
for i = startIndexToSet, endIndexToSet do
if node_list[ i ] then
curNode = node_list[ i ]
curNode:setVisible( true )

local round = math.floor( ( startIndex + i - 1 - 1) / itemSize )
local remainder = ( startIndex + i - 1 - 1)  % itemSize

local x , y
if direction == ccui.ScrollViewDir.vertical then
x = cellWidth/2.0 +  cellWidth * remainder
y = cellHeight/2.0 + cellHeight * round
y = totalLength - y
elseif direction == ccui.ScrollViewDir.horizontal then
x = cellWidth/2.0 +  cellWidth * round
y = cellHeight/2.0 + cellHeight * remainder
end
curNode:setPosition( x, y)

dataSource:setData( curNode, startIndex + i - 1 )
end
end

for i, node in ipairs( node_list ) do
node:setVisible( false )
end
for i = 1, maxVisibleSize do
node_list[ i ]:setVisible( true )
end
end

function FastScrollView:scrollCallback( eventType )
if self.canScrollCallback then
if  eventType == ccui.ScrollviewEventType.bounceBottom or
eventType == ccui.ScrollviewEventType.bounceTop then
self.isBounceing = true
return
end
self.isBounceing = nil

self:updateView( )

if self.listenerCallback then
self.listenerCallback()
end
end
end

其实本质很简单,就是根据滚动距离,重新设置滚动视图。

start = (posValue +scrLength) -self:getContentSize().height
就是重新滚动的距离。

-- 船坞滚动试图的模型数据设置

DockShipDatasource = class( "DockShipDatasource" )

function DockShipDatasource:create( dataList , nodeSize , callbackObj , callbackFuncs , splitIndex , splitItemHeight )
local datasource =  DockShipDatasource:new()
datasource.dataList = dataList
datasource.nodeSize = nodeSize
datasource.callbackObj = callbackObj
datasource.callbackFuncs = callbackFuncs
datasource.splitIndex = splitIndex
datasource.splitItemHeight = splitItemHeight
return datasource
end

function DockShipDatasource:setData( node, dataIndex )
local shipData = self.dataList[dataIndex]

if shipData.__cname == "DictWarship" then
if shipData.waitActivate then
node:updateView( shipData, ShipFullNode.STATE_LOCK_CHIP_ENOUGH )
UI.onClickItem( node.btn_bg, self.callbackFuncs[ShipFullNode.STATE_LOCK_CHIP_ENOUGH], self.callbackObj )
else
node:updateView( shipData, ShipFullNode.STATE_LOCK_CHIP_NOT_ENOUGH )
UI.onClickItem( node.btn_bg, self.callbackFuncs[ShipFullNode.STATE_LOCK_CHIP_NOT_ENOUGH], self.callbackObj )
end
else
node:updateView( shipData, ShipFullNode.STATE_UNLOCK )
UI.onClickItem( node.btn_bg, self.callbackFuncs[ShipFullNode.STATE_UNLOCK], self.callbackObj )
end

local scr = node:getParent():getParent()
if  not self.splitLabel then
scr:removeChildByName( "splitLabel" )
local splitLabel = UI.label(  Res.FileNames.res_font_arts_ttf, 20, "——以下尚未解锁——" )
scr:addChild( splitLabel )
splitLabel:setName( "splitLabel" )
splitLabel:setPositionX( scr:getContentSize().width / 2 )
splitLabel:setPositionY( -200 )
scr:setInnerContainerSize( cc.size( scr:getInnerContainer():getContentSize().width , scr:getInnerContainer():getContentSize().height + self.splitItemHeight ) )
scr:jumpToTop()
self.splitLabel = splitLabel
end

if dataIndex >= self.splitIndex then
node:setPositionY( node:getPositionY() - self.splitItemHeight )
end

if dataIndex == self.splitIndex then
self.splitLabel:setPositionY( node:getPositionY() + self.nodeSize.height/2 + self.splitItemHeight/2 )
end
end

function DockShipDatasource:getTotalSize( )
return #self.dataList
end

其实,这个东西就是根据数据源,在滚动的时候,不断刷新数据。当有扩展,比如:加入分割线等后,直接在刷新处处理即可。

self.scrollView:setScrollListenerCallback( function()
local posX = self.scrollView:getInnerContainer():getPositionX()
UI.setVisible( self.spr_left , posX < -20 )
UI.setVisible( self.spr_right , posX > self.scrollView:getContentSize().width - self.scrollView:getInnerContainerSize().width )
end)
考虑这个水平的滚动:这个滚动时,左箭头和右箭头显示逻辑,但是FastScrollView的话,因为里面开始只有几个节点,所以posX开始肯定是0,但是innerContainerSize.width却是个很大的数字。

--test
local posY = self.scrollview:getInnerContainer():getPositionY()
local contentHeight = self.scrollview:getContentSize().height
local innerContainerHeight = self.scrollview:getInnerContainerSize().height
rlog("scrollView test")
rlog("posY:" .. posY)
rlog("contentHeight:" .. contentHeight)
rlog("innerContainerHeight:" .. innerContainerHeight)

[LUA-print] posY:-9632
[LUA-print] contentHeight:400
[LUA-print] innerContainerHeight:10032

右箭头显示逻辑,这个可以理解下innerContainer的位置是怎么做的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: