PGRData/Script/matrix/xui/xuibase/XScrollView.lua

364 lines
11 KiB
Lua
Raw Normal View History

XScrollView = XClass(XLuaBehaviour, "XScrollView")
local DEFAULT_START_VALUE = 0.1 -- 默认起始坐标参数值
local DEFAULT_OFFSET_VALUE = 0.2 -- 默认间隔坐标参数值
local DEFAULT_MIN_VALUE = 0.1 -- 默认最小坐标参数值
local DEFAULT_MAX_VALUE = 0.9 -- 默认最大坐标参数值
local DEFAULT_ANIM_SPEED = 0.5 -- 默认动画速度
--==============================--
--desc: 构造函数
--@ui: 滑动展示区域Ui
--@scrollItems: 滑动列表
--@paramsObj: 扩展参数
--note: 可用扩展参数 selectIndex默认显示第几条、offsetValue滑动列表间偏移量、animSpeed滑动速度
-- moveEndCb滑动结束回掉、direction滑动方向水平或者垂直、isLoop滑动列表是否循环
--==============================--
function XScrollView:Ctor(rootUi, ui, scrollItems, paramsObj)
self.ScrollItems = {}
self.MoveEndCb = function() end
self.SelectItemCb = function() end
self.Direction = XScrollConfig.HORIZONTAL
self.Rect = self.Transform:GetComponent("RectTransform")
self.ContentSize = self.Rect.sizeDelta
self.StartValue = DEFAULT_START_VALUE
self.OffsetValue = DEFAULT_OFFSET_VALUE
self.MinValue = DEFAULT_MIN_VALUE
self.MaxValue = DEFAULT_MAX_VALUE
self.MinBorder = DEFAULT_MIN_VALUE
self.MaxBorder = DEFAULT_MAX_VALUE
self.AnimSpeed = DEFAULT_ANIM_SPEED
self.ItemsCount = #scrollItems
self.IsLoop = false
self.TotalOffset = 0 -- 重置总的滑动偏移计算
self:InitParams(paramsObj)
self:RegisterListener()
self:InitAnimationCurve()
self:InitScorllItems(scrollItems)
end
function XScrollView:AddSelectItemCallback(callback)
self.SelectItemCb = callback
end
function XScrollView:RemoveSelectItemCallback()
self.SelectItemCb = nil
end
function XScrollView:RegisterListener()
self.UiWidget = self.GameObject:AddComponent(typeof(CS.XUiWidget))
self.UiWidget:AddBeginDragListener(function(eventData)
self:OnBeginDrag(eventData)
end)
self.UiWidget:AddEndDragListener(function(eventData)
self:OnEndDrag(eventData)
end)
self.UiWidget:AddDragListener(function(eventData)
self:OnDrag(eventData)
end)
self.UiWidget:AddPointerClickListener(function(eventData)
self:OnPointerClick(eventData)
end)
end
function XScrollView:InitScorllItems(scrollItems)
local count = #scrollItems
for i = 1, count do
local item = scrollItems[i]
item:SetIndex(i)
item:SetParent(self)
item:OnDrag(self.StartValue + (i - 1) * self.OffsetValue)
if (not self.CurrentItem) and item.CurveValue - 0.5 < 0.05 then
self.CurrentItem = item
end
table.insert(self.ScrollItems, item)
end
local minCount = math.floor(1 / self.OffsetValue) -- 滑动区域可展示条目数
if #self.ScrollItems < minCount then
self.MaxValue = self.StartValue + (minCount - 1) * self.OffsetValue
else
self.MaxValue = self.StartValue + (count - 1) * self.OffsetValue
end
if self.SelectIndex then
self:SetSelectItem(self.SelectIndex)
end
end
function XScrollView:InitParams(paramsObj)
if not paramsObj or type(paramsObj) ~= "table" then
return
end
if paramsObj.selectIndex then
local selectIndex = paramsObj.selectIndex
if selectIndex < 1 or selectIndex > self.ItemsCount then
XLog.Warning("XScrollView InitParams use a Invalid selectIndex, selectIndex = " .. selectIndex)
else
self.SelectIndex = selectIndex
end
end
if paramsObj.offsetValue then
if paramsObj.offsetValue < 0 then
XLog.Warning("XScrollView InitParams use a Invalid offsetValue, offsetValue = " .. paramsObj.offsetValue)
else
self.OffsetValue = paramsObj.offsetValue
end
end
if paramsObj.animSpeed then
if paramsObj.animSpeed < 0 then
XLog.Warning("XScrollView InitParams use a Invalid animSpeed, animSpeed = " .. paramsObj.animSpeed)
else
self.AnimSpeed = paramsObj.animSpeed
end
end
if paramsObj.moveEndCb then
self.MoveEndCb = paramsObj.moveEndCb
end
if paramsObj.direction then
local direction = paramsObj.direction
if direction ~= XScrollConfig.HORIZONTAL and direction ~= XScrollConfig.VERTICAL then
XLog.Warning("XScrollView InitParams use a Invalid direction, direction = " .. direction)
else
self.Direction = direction
end
end
if paramsObj.isLoop ~= nil then
self.IsLoop = paramsObj.isLoop
end
end
function XScrollView:SetSelectItem(index)
self.CurrentItem = self.ScrollItems[index]
local offset = 0.5 - self.CurrentItem.CurveValue
for i = 1, #self.ScrollItems do
local item = self.ScrollItems[i]
item:OnDrag(offset)
end
self:AdjustScrollItems(offset)
if (self.SelectItemCb) then
self.SelectItemCb(self.CurrentItem)
end
end
function XScrollView:InitAnimationCurve()
-- Override this function
end
function XScrollView:OnBeginDrag(eventData)
self.StartPoint = eventData.position
self.AddVector = CS.UnityEngine.Vector3.zero
self.Anim = false
end
--==============================--
--desc: 滑动过程回掉
--@eventData: 回掉数据
--==============================--
function XScrollView:OnDrag()
-- Override this function
end
--==============================--
--desc: 滑动结束回掉滑动结束回掉
--@eventData: 回掉数据
--==============================--
function XScrollView:OnEndDrag()
-- Override this function
end
--==============================--
--desc: 动画曲线值计算接口
--@curveValue: 曲线值
--@return 动画计算产生的结果
--==============================--
function XScrollView:Evaluate(curveValue)
-- Override this function
end
--==============================--
--desc: 调整滑动列表元素
--@addValue: 增加的偏移量
--==============================--
function XScrollView:AdjustScrollItems(addValue)
if not self.IsLoop then
return
end
local itemCount = #self.ScrollItems
if addValue < 0 then -- left or down
local moveCount = 0
for i = 1, itemCount do
local item = self.ScrollItems[i]
if item.CurveValue < (self.MinValue - self.OffsetValue / 2) then
moveCount = moveCount + 1
end
end
if moveCount > 0 then
for _ = 1, moveCount do
local lastCurveValue = self.ScrollItems[itemCount].CurveValue
local item = table.remove(self.ScrollItems, 1)
item.CurveValue = lastCurveValue + self.OffsetValue
table.insert(self.ScrollItems, item)
end
end
elseif addValue > 0 then -- right or up
local moveCount = 0
for i = 1, itemCount do
local item = self.ScrollItems[i]
if item.CurveValue >= self.MaxValue then
moveCount = moveCount + 1
end
if moveCount > 0 then
local firstCurveValue = self.ScrollItems[1].CurveValue
local tmpItem = table.remove(self.ScrollItems, itemCount)
tmpItem.CurveValue = firstCurveValue - self.OffsetValue
table.insert(self.ScrollItems, 1, tmpItem)
end
end
end
end
--==============================--
--desc: 滑动结束动画处理
--@offset: 偏移量
--==============================--
function XScrollView:Anim2End(offset)
self.NeedOffset = offset -- 所需偏移量
if offset == 0 then
return
end
if offset > 0 then -- 正方向,向右/向上
self.MoveDir = 1
else -- 反方向,向左/向下
self.MoveDir = -1
end
self.Anim = true
self.TotalOffset = 0 -- 重置已偏移统计
end
--==============================--
--desc: 点击回掉,判断点中节点
--@eventData: 点击回掉数据
--==============================--
function XScrollView:OnPointerClick(eventData)
local gameObject = eventData.pointerPressRaycast.gameObject
for i = 1, #self.ScrollItems do
local item = self.ScrollItems[i]
if item.GameObject == gameObject then
if item.GameObject ~= self.CurrentItem.GameObject then
self.CurrentItem = item
self:Anim2End(0.5 - item.CurveValue)
end
break
end
end
end
function XScrollView:Update()
if not self.Anim then
return
end
local addOffset = CS.UnityEngine.Time.deltaTime * self.AnimSpeed * self.MoveDir
local totalOffset = self.TotalOffset + addOffset
if totalOffset > 0 and totalOffset >= self.NeedOffset then
self.Anim = false
addOffset = self.NeedOffset - self.TotalOffset
end
if totalOffset < 0 and totalOffset <= self.NeedOffset then
self.Anim = false
addOffset = self.NeedOffset - self.TotalOffset
end
for i = 1, #self.ScrollItems do
local item = self.ScrollItems[i]
item:OnDrag(addOffset)
if math.abs(item.CurveValue - 0.5) < 0.05 then -- 当前选中节点
self.CurrentItem = item
end
end
self:AdjustScrollItems(addOffset)
self.TotalOffset = totalOffset
if not self.Anim then
self.MoveEndCb(self.CurrentItem)
end
end
function XScrollView:LateUpdate()
local midItem
local minOffset = 1
for i = 1, #self.ScrollItems do
local item = self.ScrollItems[i]
local v = math.abs(item.CurveValue - 0.5)
-- if math.abs(item.CurveValue - 0.5) < 0.05 then -- 当前选中节点
-- midItem = item
-- end
if v < minOffset then
minOffset = v
midItem = item
end
end
if not midItem then
return
end
local midIndex = midItem.Index
local maxIndex = #self.ScrollItems
for i = 1, midIndex - 1 do
local item = self.ScrollItems[i]
-- if item.CurveValue >= self.MinBorder then
item.Rect:SetSiblingIndex(i)
-- else
-- break
-- end
end
for i = midIndex + 1, maxIndex do
local item = self.ScrollItems[i]
-- if item.CurveValue <= self.MaxBorder then
item.Rect:SetSiblingIndex(maxIndex - i)
-- else
-- break
-- end
end
midItem.Rect:SetSiblingIndex(maxIndex)
end
function XScrollView:Dispose()
local xLuaBehaviour = self.Transform:GetComponent("XLuaBehaviour")
if (xLuaBehaviour) then
CS.UnityEngine.GameObject.Destroy(xLuaBehaviour)
end
if (self.UiWidget) then
CS.UnityEngine.GameObject.Destroy(self.UiWidget)
end
end