There is no way to detect when UI loads, only when they replicate. There is however a way to detect when an asset loads provided you preload it via ContentProvider. As far as it’s use in a loading screen goes, you should only be preloading assets you need seen immediately - anything else can wait and be streamed in.
Typically for a loading screen I will make it relatively blank except for some aesthetic indicators (the same as how almost every game, Roblox or not, sets up a loading screen). From there, I will pass anything seen immediately into PreloadAsync and the rest I just let stream in on use.
A note about PreloadAsync (cc @TheCarbyneUniverse): PreloadAsync accepts a table of instances, but know that the descendants of those instances are also passed. There is virtually no reason to ever use GetChildren/Descendants: pass the top-level object in the table and the rest will follow. I never recommend passing an entire container like PlayerGui either, as that’s not proper use of PreloadAsync.