Keep listed items from overlapping to the outside of the parent UIObject

The problem: https://gyazo.com/047fd88ddc572c1c8d99d00a83df9009

What I am trying to achieve: Keeping the objects within the grey frame from spilling outside said frame at any aspect ratio.

The Developer Hub’s pages on any of the UIComponents are starved of meaningful concept explanations and examples on how they can be used (with some like UIInlineLayout being completely empty), much like many other aspects of the Studio API. Please excuse me if there is an obvious answer for this. Just like my previous thread, I didn’t even know how to search for this to find a pre-written answer.

By enabling ClipDescendants of the parent frame, this will prevent the descendant frames from being rendered outside of the parent frame.

While this does achieve that effect, it creates another problem…

… in which now the boxes are not all visible. The easy solution is to use a ScrollingFrame but I cannot use that for this case because the idea for these boxes is for the user to be able to drag one into another’s place, and because you can’t scroll left or right while dragging, it just makes for a bad user experience.

I was really looking to have the boxes resize downward as the screen narrowed. Would that have to be a scripted effect?

The problem: https://gyazo.com/1f41d525cad55ad06710cc6528f0286b

The solution: https://gyazo.com/70496a9614a7e51cb4bb1b96c5494e06

What I ended up doing was finding the “right” size for all 9 boxes while using a 2:1 aspect ratio on the screen (the “desired aspect ratio”). This “right size” was UDim2.new(0.8, 0, 0.8, 0): Screenshot by Lightshot

I then had a script automatically resize the boxes based on

  • the screen’s current aspect ratio,
  • the desired aspect ratio, and
  • the initial size of each box.

Please note that you do not have to use a 2:1 aspect ratio. You can use any, as long as you record it to the variable that denotes your desired aspect ratio.

In the script, the boxes are referred to as frames.

local Frames={}

local OriginalSizes = {}
local DesiredAspectRatio, CurrentAspectRatio = 2, nil
-- The DesiredAspectRatio here is 2 because the ratio during which the borders were measured was 2:1. If you measured the borders while using a 16:9 ratio, you would simply replace 2 with 16 / 9.

local function RatioAdjustedSize(Frame)
	local ScaleDown = CurrentAspectRatio / DesiredAspectRatio
	return UDim2.new(OriginalSizes[Frame].X.Scale * ScaleDown, OriginalSizes[Frame].X.Offset, OriginalSizes[Frame].Y.Scale * ScaleDown, OriginalSizes[Frame].Y.Offset)
	-- The offset properties are not particularly important
end

local function ResizeBoxes()
	CurrentAspectRatio = workspace.CurrentCamera.ViewportSize.X / workspace.CurrentCamera.ViewportSize.Y
	if CurrentAspectRatio <= DesiredAspectRatio then
		-- I do not scale any of the boxes up if the current aspect ratio is more than the desired because I don't want the boxes spilling out of the top and bottom borders
		-- This however has the side effect of making really tiny boxes exist within the frame, having very large top and bottom borders for users with unusually low aspect ratios. 
		-- For me personally, that is an OK trade-off to not have any spill-over at all.
		for _,Frame in pairs(Frames) do
			Frame.Size = RatioAdjustedSize(Frame)
		end
	end
end

I am aware that it would be easier to have one table with each Frame having its own index and a table as the value, which itself would contain an OriginalSize entry. However, this would require an unfortunate amount of restructuring on my part. It isn’t important to this topic regardless.

Later on in the script, after having filled the Frames table and created entries in the OriginalSizes table for each of them, I run our resizing function for when the user joins the game and also add a listener for changes in screen size in case the user was to resize their window.

ResizeBoxes()
workspace.CurrentCamera:GetPropertyChangedSignal("ViewportSize"):Connect(ResizeBoxes)

And that’s that. Everything stays within its border, and nothing gets clipped, no matter the screen size or aspect ratio.

1 Like