Join the RoClicks Discord
RoClicks

PixelRows.luau

Luau, 61 lines from UI overview

Download PixelRows.luau
--!strict
-- PixelRows: size ScrollingFrame rows in PIXELS worked out from the list's own height.
-- Inside a ScrollingFrame, a child's Scale size resolves against the CANVAS. With
-- AutomaticCanvasSize the canvas is measured from the children, so Scale rows and the canvas define
-- each other: rows collapse (scale*count < 1), explode (> 1, seen at 112 million px), or settle at
-- an arbitrary size. Pixel rows break the loop; AutomaticCanvasSize then just follows content.

local PixelRows = {}

-- list: the ScrollingFrame. visible: how many rows should fit in the window. gap: px between rows.
function PixelRows.bind(list: ScrollingFrame, visible: number, gap: number): () -> ()
	local layout = list:FindFirstChildOfClass("UIListLayout") or Instance.new("UIListLayout")
	layout.SortOrder = Enum.SortOrder.LayoutOrder
	layout.Padding = UDim.new(0, gap) -- Offset, never Scale, for the same reason as the rows
	layout.Parent = list

	list.AutomaticCanvasSize = Enum.AutomaticSize.Y
	list.CanvasSize = UDim2.new(0, 0, 0, 0)

	local function apply()
		local h = list.AbsoluteSize.Y
		if h <= 0 then return end
		local rowH = math.floor((h - gap * (visible - 1)) / visible)
		for _, row in list:GetChildren() do
			if row:IsA("GuiObject") then
				row.Size = UDim2.new(1, -list.ScrollBarThickness, 0, rowH)
			end
		end
	end

	local conns = {
		list:GetPropertyChangedSignal("AbsoluteSize"):Connect(apply), -- still adapts to screen size
		list.ChildAdded:Connect(function() task.defer(apply) end),
	}
	apply()
	return function()
		for _, c in conns do c:Disconnect() end
	end
end

-- Audit any pasted UI kit: flags Scale-sized rows inside ScrollingFrames and Scale CanvasSize.
function PixelRows.audit(root: Instance): { string }
	local out = {}
	for _, d in root:GetDescendants() do
		if d:IsA("ScrollingFrame") then
			if d.CanvasSize.Y.Scale > 1.01 then
				table.insert(out, d:GetFullName() .. ": CanvasSize.Y.Scale = " .. d.CanvasSize.Y.Scale)
			end
			for _, c in d:GetChildren() do
				if c:IsA("GuiObject") and c.Size.Y.Scale > 0 then
					table.insert(out, c:GetFullName() .. ": row height is Scale " .. c.Size.Y.Scale)
					break
				end
			end
		end
	end
	return out
end

return PixelRows