Closed noah-peeters closed 3 years ago
Had a few hours to spare so I've introduced some new methods and modified internals to achieve the following:
Icon.new()
:setName("CashSpinnerIcon")
:setRight()
:lock()
:setSize(100, 32)
:set("iconLabelSize", UDim2.new(1,0,1,0))
:give(function(icon)
-- This creates the icon spinner and parents it to the iconButton
local labelSpinner = NumberSpinner.new()
labelSpinner.Name = "LabelSpinner"
labelSpinner.Decimals = 3
labelSpinner.Duration = 0.25
labelSpinner.Parent = icon:getInstance("iconButton")
-- This creates a fake iconLabel which updates the property of all descendant spinner TextLabels when indexed
local textLabel = {}
setmetatable(textLabel, {__newindex = function(_, index, value)
for _, textLabel in pairs(labelSpinner.Frame:GetDescendants()) do
if textLabel:IsA("TextLabel") then
textLabel[index] = value
end
end
end})
-- This overrides existing instances and settings so that they update the spinners properties (instead of the old textlabel)
local iconButton = icon:getInstance("iconButton")
iconButton.ZIndex = 0
icon:setInstance("iconLabel", textLabel, true) -- Passing ``true`` as the third argument destroys the original instance
icon:modifySetting("iconText", {instanceNames = {}}) -- We do this to prevent text being modified within the metatable above
icon:setInstance("iconLabelSpinner", labelSpinner.Frame)
local settingsToConvert = {"iconLabelVisible", "iconLabelAnchorPoint", "iconLabelPosition", "iconLabelSize"}
for _, settingName in pairs(settingsToConvert) do
icon:modifySetting(settingName, {instanceNames = {"iconLabelSpinner"}})
end
-- This applies all the values we just updated
icon:_updateAll()
-- Finally, set your desired text
coroutine.wrap(function()
while wait(0.5) do
labelSpinner.Value = math.random(100000)/1000
end
end)()
end)
How is this? It's a little more code than I'd like necessary although essential to ensure the spinner integrates seamlessly with themes and other features and internals.
You can test this at the playground: https://www.roblox.com/games/6199274521/TopbarPlus-Playground?refPageId=4e9c29a8-6c23-4d42-bb34-41c7ea120389
If this works well I can then deploy the changes.
That's awesome! Great work on implementing this so fast!
I would like if some stuff was abstracted away more. Like this code:
local textLabel = {}
setmetatable(textLabel, {__newindex = function(_, index, value)
for _, textLabel in pairs(labelSpinner.Frame:GetDescendants()) do
if textLabel:IsA("TextLabel") then
textLabel[index] = value
end
end
end})
I would prefer if there was a function, that would search automatically for the Frame's children.
Same goes for the settingsConversion. Could there be a way to make it automatic?
Thanks for implementing this.
Sure thing, this utilises a convertLabelToNumberSpinner
method which abstracts most of the above:
Icon.new()
:setName("CashSpinnerIcon")
:setRight()
:lock()
:setSize(100, 32)
:give(function(icon)
local labelSpinner = NumberSpinner.new()
icon:convertLabelToNumberSpinner(labelSpinner)
labelSpinner.Name = "LabelSpinner"
labelSpinner.Decimals = 3
labelSpinner.Duration = 0.25
coroutine.wrap(function()
while wait(0.5) do
labelSpinner.Value = math.random(100000)/1000
end
end)()
end)
You can test that at the playground and if it works well I can officially deploy and release.
That is really awesome! This is exactly what I was looking for, thanks.
No problem and cheers for the feature suggestion, this has been officially released now in v2.5.1: https://devforum.roblox.com/t/topbarplus-v2-construct-intuitive-topbar-icons/1017485/92
It is currently not possible to wrap a Roblox UI object like a Frame, inside of an Icon. If I want to create a timer that has nice effects, using this module: https://devforum.roblox.com/t/numberspinner-module/1105961. I'm forced to use the Frame that it returns. I would like the frame to behave like an icon (one that is not clickable). This means having the same theme as other icons, adjustable position from the Topbar.
Some ideas that comes to mind: