Description
openedon Sep 30, 2024
Description
Maui provides very poor Layout performance on iOS during translations (eg. custom animations, scrolling, or collection view type systems), and I believe I have now found the cause. Hopefully there is an easy workaround or solution. I am open to any suggestions.
This is likely also the cause of the generally poor scrolling and CollectionView performance in iOS as both will also likely depend on translation changes to function, and thus also be subject to these endless re-measures and re-arranges.
PROBLEM
In a working system, adjusting the translation of an element should NEVER provoke a re-measure/re-layout/re-arrange of the object or all its children. That is the whole point of translation. It is supposed to be a fast and efficient way to adjust the position of something WITHOUT re-doing every measurement and layout.
This is working in Android/Windows. Adjusting the translation of an element does NOT provoke a re-layout/re-arrange of the object or all children. No re-measure or arrange occurs on translation change.
However, in iOS ArrangeChildren
is being run on every single translation change. And Measure
is being run extremely often as well provoked by only translation changes (though not quite as often).
This is brutalizing the performance in iOS as any translation change leads to continuous re-layouts and re-measures of all children of the translated object starting from its parent and propagating down through the entire child hierarchy.
DEMONSTRATION PROJECT
This is demonstrated through the bug project here: https://github.com/jonmdev/iOSTranslationArrangeBug
The project is created in only two files:
CAbsoluteLayout.cs - This is a derived class of AbsoluteLayout to implement a custom layout manager so we can see the layouts on debug when they happen through the overrides of Measure
and ArrangeChildren
. The custom layout manager is just a simplified copy and paste from Maui's AbsoluteLayoutManager.cs. No special changes.
App.xaml.cs - This is just a simple C# project that adds a few of these Custom Absolute Layout elements to the screen and starts oscillating the position of one. It creates a hierarchy of, by styleId names:
"Scroll Window" (AbsoluteLayout)
==="Scroll Content" (AbsoluteLayout)
======Child Abs 0 (AbsoluteLayout)
=========Border
======Child Abs 1 (AbsoluteLayout)
=========Border
======Child Abs 2 (AbsoluteLayout)
=========Border
"Scroll Content" is the moved object. In iOS, we will see how arranges and measures are spammed as its translation changes from its parent ("Scroll Window") all the way down through the hierarchy.
RESULT
One can see if you run this in Windows/Android there are NO ongoing lines showing Measure
or ArrangeChildren
are being run (as expected). You will get on project load only once or twice something like:
[0:] MEASURE CHILDREN OF: Scroll Window NUM CHILDREN 1
[0:] MEASURE CHILDREN OF: Scroll Content NUM CHILDREN 3
[0:] MEASURE CHILDREN OF: Child Abs 0 NUM CHILDREN 1
[0:] MEASURE CHILDREN OF: Child Abs 1 NUM CHILDREN 1
[0:] MEASURE CHILDREN OF: Child Abs 2 NUM CHILDREN 1
[0:] ARRANGE CHILDREN OF: Scroll Window NUM CHILDREN 1
[0:] ARRANGE CHILDREN OF: Scroll Content NUM CHILDREN 3
[0:] ARRANGE CHILDREN OF: Child Abs 0 NUM CHILDREN 1
[0:] ARRANGE CHILDREN OF: Child Abs 1 NUM CHILDREN 1
[0:] ARRANGE CHILDREN OF: Child Abs 2 NUM CHILDREN 1
This is normal behavior in Android/Windows.
However, in iOS, these outputs are spammed on a continuous basis as the translation keeps changing. You will get an infinite number of such re-measurements and re-arranges. The arranges occur on literally every single Translation change while the measures occur only at certain points of the oscillation (unclear why).
In general, manipulating the translations in iOS of anything in the real world with complex hierarchies is extremely costly and nothing runs as smoothly as it should even on high end iOS devices. This is likely why.
We cannot afford to be re-arranging the whole hierarchy every time a translation occurs and this should not be happening.
CAUSE / SOLUTION?
Is there any obvious cause or solution that comes to mind?
Any workaround or solution (or ideas) would be very appreciated.
Steps to Reproduce
- Load the bug project.
- Run in Windows/Android. See there is no
ArrangeChildren
orMeasure
being run on an ongoing basis. - Run in iOS and see these functions are running on a continuous basis as the translation is changed.
Link to public reproduction project repository
https://github.com/jonmdev/iOSTranslationArrangeBug
Version with bug
8.0.91 SR9.1
Is this a regression from previous behavior?
No, this is something new
Affected platforms
iOS