--- What level can you understand my code?Damn!
--- Created by Lua Lee.
--- DateTime: 2024/7/9 20:38
---
TestUi = {}
local _instance = nil
TestUi.__index = TestUi
local BaseUi = SL:Require("alg/dev/ui/Base/BaseUi.lua", true)
-- 创建
function TestUi:new()
if not _instance then
_instance = setmetatable(BaseUi:new("TestUi", nil, "测试UI", nil, nil, nil), TestUi)
_instance.childrens = {} -- 所有子控件
_instance.nowRadian = {} -- 当前弧度
_instance.nowWeight = {} -- 当前权重(用来控制每个元素的状态,比如颜色,透明度,大小等)
_instance.isAutoScrolling = false -- 是否自动滚动
_instance.autoScrollSpeed = 20 -- 自动滚动速度
_instance.changeAngle = 0 -- 改变的角度
_instance.changeOffset = 0 -- 改变的偏移量
_instance.endRadian = 0 -- 结束弧度
_instance.touchStartLocation = 0 -- 接触开始的位置
_instance.touchMoveStartLocation = 0 -- 滚动位置
_instance.lastIndex = 0 -- 上一个索引
_instance.currentIndex = 0 -- 当前下标
_instance.viewCount = 8 -- 控件数量
-- 椭圆参数
_instance.ellipseParam = {
centerX = _instance.containerSize.width / 2,
centerY = _instance.containerSize.height / 2,
a = 300,
b = 100,
}
end
_instance:init()
return _instance
end
-- 计算椭圆各个控件的落点坐标
function TestUi:getEllipsePointAt(radian)
return {
x = _instance.ellipseParam.a * math.cos(radian) + _instance.ellipseParam.centerX,
y = _instance.ellipseParam.b * math.sin(radian) + _instance.ellipseParam.centerY,
}
end
-- 弧度转角度
function TestUi:radianToAngle(radian)
return radian * 180 / math.pi
end
-- 角度转弧度
function TestUi:angleToRadian(angle)
return angle * math.pi / 180
end
-- 获取真实角度
function TestUi:getRealAngle(index)
local realAngle = math.floor(_instance.nowRadian[index] * 180 / math.pi) % 360
if realAngle < 0 then
realAngle = 360 - math.abs(realAngle)
end
return realAngle
end
-- 计算权重
function TestUi:getWeight(realAngle)
local weight = realAngle - 90
weight = 5 - math.abs(weight / 45)
if realAngle > 180 then
weight = math.abs(weight - 1)
weight = weight + 1
end
if weight < 1 then
weight = 1
end
return weight
end
-- 跟随权重变化绘制变大变小或者透明
function TestUi:drawEffect(index)
local realAngle = _instance:getRealAngle(index)
local weight = _instance:getWeight(realAngle)
GUI:setScale(_instance.childrens[index], 1 / weight)
GUI:setLocalZOrder(_instance.childrens[index], 10 - math.abs(weight))
end
-- 初始化界面
function TestUi:initView()
for i = 1, _instance.viewCount do
local radian = (math.pi * 2) / _instance.viewCount * i
local view = GUI:Image_Create(_instance.container, "img" .. i, _instance:getEllipsePointAt(radian).x, _instance:getEllipsePointAt(radian).y, string.format("res/public/word_fubentg_%d.png", i))
GUI:setAnchorPoint(view, 0.5, 0.5)
_instance.nowRadian[i] = radian
_instance.childrens[i] = view
local angle = _instance:radianToAngle(radian)
-- 将270°的元素赋值为currentIndex
if angle >= 269 and angle <= 271 then
_instance.currentIndex = i
_instance.lastIndex = _instance.currentIndex
end
_instance:drawEffect(i)
end
end
-- 根据偏移量或者当前弧度
function TestUi:getRadianFromOffset(offset)
if offset ~= 0 then
return math.atan(offset / _instance.ellipseParam.b)
else
return 0
end
end
-- 处理鼠标松开
function TestUi:handleMouseRelease()
local a = 360.0 / (#_instance.childrens * 2)
local angle = _instance:radianToAngle(_instance.endRadian)
local p = math.floor(angle / a)
if p < 0 then
p = p % 2 ~= 0 and (p - 1) / 2 or p / 2
else
p = p % 2 ~= 0 and (p + 1) / 2 or p / 2
end
-- 这里用取余的方式保证索引不超过table下标,并且table下标从1开始
_instance.currentIndex = (_instance.currentIndex - p - 1) % #_instance.childrens + 1
-- 自动滚动到对应索引
_instance:scrollToIndex()
end
-- 调整所有子元素的
function TestUi:moveIndexs(offset)
local offsetRadian = _instance:getRadianFromOffset(offset)
local length = #_instance.childrens
for i = 1, length do
_instance.nowRadian[i] = _instance.nowRadian[i] + offsetRadian
if i == _instance.currentIndex then
_instance.endRadian = _instance.endRadian + offsetRadian
end
GUI:setPosition(_instance.childrens[i], _instance:getEllipsePointAt(_instance.nowRadian[i]).x, _instance:getEllipsePointAt(_instance.nowRadian[i]).y)
_instance:drawEffect(i)
end
end
function TestUi:scrollToIndex()
_instance.isAutoScrolling = true
_instance.autoScrollSpeed = 10
_instance.changeAngle = 270 - _instance:getRealAngle(_instance.currentIndex)
_instance.changeAngle = _instance:angleToRadian(_instance.changeAngle)
_instance.changeOffset = _instance.ellipseParam.b * math.tan(_instance.changeAngle)
_instance.changeOffset = _instance.changeOffset / _instance.autoScrollSpeed
_instance.changeAngle = _instance.changeAngle / _instance.autoScrollSpeed
-- 开启定时器 自动滚到到当前记录的控件索引位置
SL:schedule(_instance.container, function()
if _instance.isAutoScrolling then
local realAngle = _instance:getRealAngle(_instance.currentIndex)
if realAngle <= 271.0 and realAngle >= 269.0 then
_instance.lastIndex = _instance.currentIndex
_instance.isAutoScrolling = false
end
_instance:moveIndexs(_instance.changeAngle)
end
end, 1 / 60)
end
-- 处理鼠标开始移动的逻辑
function TestUi:handleMouseMove(location)
local moveX = location.x
local offset = moveX - _instance.touchMoveStartLocation
_instance.touchMoveStartLocation = moveX
_instance:moveIndexs(offset)
end
-- 注册事件(这里996我找了很久没有找到鼠标按下拖动获取坐标偏移量的触发事件,不知道有没有大神能搞一个,我这里用的cocos的注册事件,但是非常不好用,这里还需要优化)
function TestUi:registerEvent()
GUI:setTouchEnabled(_instance.container, true)
local listener = cc.EventListenerTouchOneByOne:create()
-- 注册按下(开始)事件处理函数
listener:registerScriptHandler(function(touch, event)
local location = touch:getLocation()
_instance.touchMoveStartLocation = location.x
_instance.touchStartLocation = _instance.touchMoveStartLocation
_instance.endRadian = 0
-- 在此处理按下(开始)事件的逻辑
return true -- 返回 true 表示消费了触摸事件,不再传递给下层的节点
end, cc.Handler.EVENT_TOUCH_BEGAN)
-- 注册移动事件处理函数
listener:registerScriptHandler(function(touch, event)
local location = touch:getLocation()
-- 在此处理移动事件的逻辑
_instance:handleMouseMove(location)
end, cc.Handler.EVENT_TOUCH_MOVED)
-- 注册抬起(离开)事件处理函数
listener:registerScriptHandler(function(touch, event)
local location = touch:getLocation()
-- 在此处理抬起(离开)事件的逻辑
SL:release_print("Touch ended at: ", location.x, location.y)
_instance:handleMouseRelease()
end, cc.Handler.EVENT_TOUCH_ENDED)
-- 将监听器添加到精灵节点上
local eventDispatcher = _instance.container:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, _instance.container)
-- 关闭窗口移除事件
SL:RegisterLUAEvent(LUA_EVENT_CLOSEWIN, "TestUi", function()
-- 移除触摸事件监听
local eventDispatcher = _instance.container:getEventDispatcher()
eventDispatcher:removeEventListenersForTarget(_instance.container)
end)
end
function TestUi:init()
_instance:initView()
_instance:registerEvent()
end
TestUi:new()