GetPropertyChangedSignal("ViewportSize") Behaviour

Is it guaranteed that in the moment of :GetPropertyChangedSignal(“ViewportSize”) was fired all UI have already changed absolute sizes and positions?

I am writing script that adjusts stroke for all resolutions and it doesn’t work sometimes when you rotate your phone and I don’t really know why it happens. Sometimes stroke is incorrect. But after a shake (go to vertical - go to horizontal) it goes normal again.

Here is a script:

local Players = game:GetService("Players")
local PlayerGUI = Players.LocalPlayer.PlayerGui

local ORIGINAL_SCREEN = Vector2.new(800, 414) -- iPhone XR
local FRAME_SIZE_ATTRIBUTE = "DefaultAbsoluteSizeX"
local STROKE_THICKNESS_ATTRIBUTE = "DefaultThickness"


local camera = workspace.CurrentCamera


local StrokeService = {}


function StrokeService._updateStrokeSize(self: StrokeService)
	for _, child in PlayerGUI:GetDescendants() do
		if not child:IsA("UIStroke") then
			continue
		end
		
		local defaultThickness = child:GetAttribute(STROKE_THICKNESS_ATTRIBUTE)
		
		local parent = child.Parent
		local defaultSize = parent:GetAttribute(FRAME_SIZE_ATTRIBUTE)
		if defaultSize then
			child.Thickness = parent.AbsoluteSize.X / defaultSize * defaultThickness
		else
			child.Thickness = camera.ViewportSize.Magnitude / ORIGINAL_SCREEN.Magnitude * defaultThickness
		end
	end
end


function StrokeService.Init(self: StrokeService)
	camera:GetPropertyChangedSignal("ViewportSize"):Connect(function()
		print(camera.ViewportSize)
		self:_updateStrokeSize()
	end)
	
	self:_updateStrokeSize()
end


export type StrokeService = typeof(StrokeService)


return StrokeService
1 Like

Depends
If you have a deferred signal behavior (default), then yes.

I also suggest you to remove init function and instead call it right awey from the module.

Custom stroke scaling is absolutelly not needed anymore since UIStrike beta already fixes it

  1. I use Crusherfire module loader, which requires init functions for each module.
  2. I agree, but I have a full game that is already built and because of that I don’t wanna switch to new UIStroke API.

Why are you sure that with deferred signal behaviour answer is yes? It depends on the order of handlers in invocation point as far as I understand.

Why would you ever need that?

Maybe because it’s the truth? Learn how the task scheduler Roblox uses works.

It’s sad that instead of answering “Sizes and positions will be updated on RenderStepped while your handlers will be called on [something], so the answer is yes.” it’s easier for you to answer with “Maybe because it’s the truth? Learn how the task scheduler Roblox uses works.”

Some idea I have is while viewport size is changing but it is grabbing the old Size instead. Have you tried to wait? maybe just a milisec after to see if that solves it?

	camera:GetPropertyChangedSignal("ViewportSize"):Connect(function()
		print(camera.ViewportSize)
		RunService.Heartbeat:Wait()
		self:_updateStrokeSize()
	end)

Another idea could be that maybe to listen to the

child.Parent:GetPropertyChangedSignal(“AbsoluteSize”):Connect(function()
self:_updateStrokeSize()
end)

Nvm I lied, I can't correctly replicate the position of UIObjects
AbsoluteSize doesn’t get triggered.

Also Crusherfire Module Loader is fire, very useful features it has.

i am not sure, but it seems like the problem is that i am setting all attribute values in preview mode in studio and preview mode doesn’t apply screen insets: so if you would make topbar with screeninsets = topbar you wouldn’t see it really on the top of screen and so on, in preview mode it still looks like you are just have a frame on the center of the screen. and because of that i am setting all attributes, then when player starts the game it turns out that part of the screen is actually smaller because now screen insets are applied, so attributes applied on big screen, but they have to be applied on real screen, with screen insets applied

ui that was bugging was under coreuiinsets and they are smaller