Skip to content

Commit

Permalink
Merge pull request #18193 from Youssef1313/gallery-measure-issue
Browse files Browse the repository at this point in the history
fix(reg): Workaround Gallery measure issue on Android
  • Loading branch information
Youssef1313 authored Sep 15, 2024
2 parents e0a9aa5 + 6c1e90e commit e5ec578
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -938,7 +938,11 @@ public async Task When_InvalidatingMeasureExplicitly()

using var _ = new AssertionScope();

#if __ANDROID__
ctl1.MeasureCount.Should().Be(2);
#else
ctl1.MeasureCount.Should().Be(1);
#endif
ctl2.MeasureCount.Should().Be(2);
ctl3.MeasureCount.Should().Be(1);

Expand Down
5 changes: 5 additions & 0 deletions src/Uno.UI/Extensions/ViewExtensions.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using Android.Views.Animations;
using Microsoft.UI.Xaml.Controls;
using Uno.UI.Controls;
using Microsoft.UI.Xaml.Media;

namespace Uno.UI
{
Expand Down Expand Up @@ -705,6 +706,10 @@ public static string ShowLocalVisualTree(this ViewGroup viewGroup, int fromHeigh
{
root = parent;
}
else if (root is DependencyObject @do && VisualTreeHelper.GetParent(@do) is ViewGroup managedParent)
{
root = managedParent;
}
else
{
break;
Expand Down
7 changes: 6 additions & 1 deletion src/Uno.UI/UI/Xaml/ILayouterElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ internal static bool DoMeasure(this ILayouterElement element, Size availableSize
if (isDirty || frameworkElement is null)
{
// We must reset the flag **BEFORE** doing the actual measure, so the elements are able to re-invalidate themselves
// TODO: We are not controlling measure dirty path on Android. If we did in future, we must clear it here as well.
frameworkElement?.ClearLayoutFlags(UIElement.LayoutFlag.MeasureDirty);

// The dirty flag is explicitly set on this element
Expand All @@ -91,7 +92,9 @@ internal static bool DoMeasure(this ILayouterElement element, Size availableSize
LayoutInformation.SetAvailableSize(element, availableSize);
}

return true; // end of isDirty processing
// TODO: This is NOT correct.
// We shouldn't return here. Skipping children measure is incorrect but fixing it on Android isn't trivial.
return true;
}

// The measure dirty flag is set on one of the descendents:
Expand All @@ -110,6 +113,8 @@ internal static bool DoMeasure(this ILayouterElement element, Size availableSize
{
var previousDesiredSize = childAsUIElement.m_desiredSize;
childAsUIElement.EnsureLayoutStorage();

// TODO: This is NOT correct. This should call DoMeasure (the same method we are in currently!)
element.Layouter.MeasureChild(child, childAsUIElement.m_previousAvailableSize);
var newDesiredSize = childAsUIElement.m_desiredSize;
if (newDesiredSize != previousDesiredSize)
Expand Down
25 changes: 25 additions & 0 deletions src/Uno.UI/UI/Xaml/Media/VisualTreeHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,31 @@ internal static void AddChild(UIElement view, UIElement child)
{
#if __ANDROID__
view.AddView(child);

// Reset to original (invalidated) state
child.ResetLayoutFlags();
if (view.IsMeasureDirtyPathDisabled)
{
FrameworkElementHelper.SetUseMeasurePathDisabled(child); // will invalidate too
}
else
{
child.InvalidateMeasure();
}

if (view.IsArrangeDirtyPathDisabled)
{
FrameworkElementHelper.SetUseArrangePathDisabled(child); // will invalidate too
}
else
{
child.InvalidateArrange();
}

// Force a new measure of this element (the parent of the new child)
view.InvalidateMeasure();
view.InvalidateArrange();

#elif __IOS__ || __MACOS__
view.AddSubview(child);
#elif __CROSSRUNTIME__
Expand Down
3 changes: 3 additions & 0 deletions src/Uno.UI/UI/Xaml/UIElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1149,6 +1149,9 @@ public void InvalidateMeasure()
// Use a non-virtual version of the RequestLayout method, for performance.
base.RequestLayout();
SetLayoutFlags(LayoutFlag.MeasureDirty);

// HACK: Android's implementation of measure/arrange is not accurate. See comments in LayouterElementExtensions.DoMeasure
(VisualTreeHelper.GetParent(this) as UIElement)?.InvalidateMeasure();
#elif __IOS__
SetNeedsLayout();
SetLayoutFlags(LayoutFlag.MeasureDirty);
Expand Down

0 comments on commit e5ec578

Please sign in to comment.