ScreenStack implements its own children life updates:
|
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:
|
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.
ScreenStackimplements its own children life updates:osu-framework/osu.Framework/Screens/ScreenStack.cs
Lines 377 to 395 in 37e1475
When screens are exited they are
.Expire()d, calculating their expiry time asLatestTransformEndTime:osu-framework/osu.Framework/Screens/ScreenStack.cs
Lines 315 to 319 in 37e1475
Which means that the intended usage of screens is something like:
The problem is that
UpdateChildrenLifeoccurs 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 aFadeOut()because the final frame will already be at a low alpha value, but consider the following situation: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.