-
Notifications
You must be signed in to change notification settings - Fork 458
Description
ScreenStack implements its own children life updates:
osu-framework/osu.Framework/Screens/ScreenStack.cs
Lines 377 to 395 in 37e1475
| protected override bool UpdateChildrenLife() | |
| { | |
| if (!base.UpdateChildrenLife()) return false; | |
| // In order to provide custom suspend/resume logic, screens always have RemoveWhenNotAlive set to false. | |
| // We need to manually handle removal here (in the opposite order to how the screens were pushed to ensure bindable sanity). | |
| if (exited.FirstOrDefault()?.IsAlive == false) | |
| { | |
| foreach (var s in exited) | |
| { | |
| RemoveInternal(s, false); | |
| DisposeChildAsync(s); | |
| } | |
| exited.Clear(); | |
| } | |
| return true; | |
| } |
When screens are exited they are .Expire()d, calculating their expiry time as LatestTransformEndTime:
osu-framework/osu.Framework/Screens/ScreenStack.cs
Lines 315 to 319 in 37e1475
| if (source == null) | |
| { | |
| // This is the first screen that exited | |
| toExit.AsDrawable().Expire(); | |
| } |
Which means that the intended usage of screens is something like:
void OnExit()
{
this.FadeOut(1000);
// Expecting the screen to die after 1000ms.
}
The problem is that UpdateChildrenLife occurs prior to children being updated, which may cause unintended effects if the transforms aren't updated for the final time. It's likely fine for something like a FadeOut() because the final frame will already be at a low alpha value, but consider the following situation:
void OnExit()
{
this.TransformBindableTo(audioVolumeBindable, 0, 1000);
}
In this case, the effect is not fine as it leaves the sample with >0 volume in the final frame.
This expiry process probably needs to be re-considered a bit, and this may even be an issue outside of screens too because the base UpdateChildrenLife() implementation works much the same way.