What do you want to achieve? - A selector that moves to the selected button in a non-hardcoded way(tweening to position of the button and scaling it to the size of the button.)
What is the issue? - All the buttons are sorted by using the UIListLayout, so i cannot rely on the button.Position, since it’s controlled by the said layout.
What solutions have you tried so far? …Looked up a few solutions on Devforum, like this one. Did not work. The second one didn’t work too.
–
Since i can’t rely on the UDim2 position(influenced by UIListLayout), i somehow need to convert the AbsolutePosition to legit UDim2. That’s my question.
Most tab changing work(the selector behavior too) is stored inside a ModuleScript:
local currenttab --instance to hover back afterwards
local opened
local ts = game:GetService("TweenService")
local ti = TweenInfo.new(0.35,Enum.EasingStyle.Exponential,Enum.EasingDirection.Out)
local selector = game.Players.LocalPlayer.PlayerGui.ScreenGui.MainFrame.Under.Base.Selector
local Main = game.Players.LocalPlayer.PlayerGui.ScreenGui.MainFrame.Under
--tab: string
local function FindMatchingTab(tab)
local target = tostring(tab)
local search = Main.Base.Container
for _,v in pairs(search:GetChildren()) do
if v:IsA("TextButton") and v.Name == target then
return v
end
end
end
--DevForum implementation variant. Does not work properly.
local function convertAbsoluteToScale(frame)
local container = frame.Parent
local containerAbsPos = container.AbsolutePosition
local containerAbsSize = container.AbsoluteSize
local frameAbsPos = frame.AbsolutePosition
local frameRelativePos = frameAbsPos - containerAbsPos
return UDim2.fromScale(frameRelativePos.X / containerAbsSize.X, frameRelativePos.Y / containerAbsSize.Y)
end
--
--[[
Opens the UI at the desired tab.
tab: String
]]
function module:OpenAtTab(tab)
local result = FindMatchingTab(tab)
if opened == false or opened == nil then
opened = true
currenttab = result
ts:Create(Main,ti,{Size=UDim2.new(0.95, 0,0.895, 0)}):Play()
ts:Create(selector,ti,{Position = convertAbsoluteToScale(result), Size = result.Size}):Play()
end
--TODO: Actual tabs changing. Not yet implemented.
end
If clears things up, this is a snippet. Other logic are just basically placeholders for now…
Hello! It appears as if you are attempting to do the opposite of what my linked code segment was intending on doing. When you say you want to convert to Position(Scale), I assume that is relative to the parent GUI. I’ve provided a small code segment below that should do just that(grab the Scale position relative to the GUI using absolute position and size data).
local gui = inst:FindFirstAncestorOfClass("ScreenGui")
local absSize = gui.AbsoluteSize
local absPos = gui.AbsolutePosition
return
UDim2.fromScale(inst.AbsolutePosition.X / absSize.X + absPos.X, inst.AbsolutePosition.Y / absSize.Y + absPos.Y),
UDim2.fromScale(inst.AbsoluteSize.X / absSize.X, inst.AbsoluteSize.Y / absSize.Y)
If you clone/reparent the GuiObject to a ScreenGui or other GuiObject that covers the full screen exactly and set the base GuiObjects position and size to these Scale UDim2 values, it should line up.
hihihi thanks for actually spending time on this question
I tried it and i am genuinely confused what is wrong with this.
I created a mockup UI where everything should line up, based on the
If you clone/reparent the GuiObject to a ScreenGui or other GuiObject that covers the full screen exactly and set the base GuiObjects position and size to these Scale UDim2 values, it should line up.
--localscript to catch the actual button press. Present here just to show what i pass to the module
local selector = script.Parent.Selector
local container = script.Parent.Frame
local changer = require(game.ReplicatedStorage.Modules.TabFrameworkHandler)
for _,v in pairs(container:GetChildren()) do
if v:IsA("TextButton") then
v.MouseButton1Click:Connect(function()
changer:Change(v)
end)
end
end
--module snippet(s)
local viewSize = workspace.Camera.ViewportSize
function absToScale(inst:GuiObject): (UDim2, UDim2)
return
UDim2.fromScale(inst.AbsolutePosition.X / viewSize.X, inst.AbsolutePosition.Y / viewSize.Y),
UDim2.fromScale(inst.AbsoluteSize.X / viewSize.X, inst.AbsoluteSize.Y / viewSize.Y)
end
--
function module:Change(tab:Instance)
ts:Create(game.Players.LocalPlayer.PlayerGui.test.Frame.Selector,ti,{Position = absToScale(tab), Size = tab.Size}):Play()
--the selector is currently hardcoded into the tween, will change later
end
My code segment returns two UDim values. This segment would incorporate both. Also ensure both have an AnchorPoint at 0,0
function module:Change(tab:Instance)
local position, size = absToScale(tab)
ts:Create(game.Players.LocalPlayer.PlayerGui.test.Frame.Selector,ti,{Position = position, Size = size}):Play()
end
Let me know how this works, and if it doesn’t please send what the absolute position of both instances are after running the code. Thanks!
I found the issue, I forgot to account for UI inset by using Camera.ViewSize. I have attached an updated code segment which uses the size and position, and relies off of the Gui instead of the Camera.
function absToScale(inst:GuiObject): (UDim2, UDim2)
local gui = inst:FindFirstAncestorOfClass("ScreenGui")
local absSize = gui.AbsoluteSize
local absPos = gui.AbsolutePosition
return
UDim2.fromScale(inst.AbsolutePosition.X / absSize.X + absPos.X, inst.AbsolutePosition.Y / absSize.Y + absPos.Y),
UDim2.fromScale(inst.AbsoluteSize.X / absSize.X, inst.AbsoluteSize.Y / absSize.Y)
end
The variable gui will reference the parent gui of inst. I’ve also attached a small test place to demonstrate this.