Skip to content

Commit

Permalink
fix(ComboBox): flyout placement in ios SheetPage
Browse files Browse the repository at this point in the history
Co-Authored-By: Andres Pineda <pineda.andres@gmail.com>
  • Loading branch information
Xiaoy312 and ajpinedam committed Apr 30, 2023
1 parent 64fb74e commit af92831
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 12 deletions.
2 changes: 1 addition & 1 deletion src/Uno.UI/Extensions/UIViewExtensions.iOSmacOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ public static _Controller FindViewController(this _View view)
// Sometimes, a view is not part of the visual tree (or doesn't have a next responder) but is part of the logical tree.
// Here, we substitute the view with the first logical parent that's part of the visual tree (or has a next responder).
view = (view as DependencyObject)
.GetParents()
?.GetParents()
.OfType<_View>()
.Where(parent => parent.NextResponder != null)
.FirstOrDefault();
Expand Down
4 changes: 2 additions & 2 deletions src/Uno.UI/UI/Xaml/UIElement.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ internal static GeneralTransform TransformToVisual(View element, View visual)
/// Note: Offsets are only an approximation which does not take in consideration possible transformations
/// applied by a 'ViewGroup' between this element and its parent UIElement.
/// </summary>
private bool TryGetParentUIElementForTransformToVisual(out UIElement parentElement, ref double offsetX, ref double offsetY)
private bool TryGetParentUIElementForTransformToVisual(out UIElement parentElement, ref double offsetX, ref double offsetY, ref TransformToVisualContext context)
{
var parent = this.GetVisualTreeParent();
switch (parent)
Expand Down Expand Up @@ -271,7 +271,7 @@ private bool TryGetParentUIElementForTransformToVisual(out UIElement parentEleme
offsetY += offset.Y;

// We return the parent of the ScrollViewer, so we bypass the <Horizontal|Vertical>Offset (and the Scale) handling in shared code.
return sv.TryGetParentUIElementForTransformToVisual(out parentElement, ref offsetX, ref offsetY);
return sv.TryGetParentUIElementForTransformToVisual(out parentElement, ref offsetX, ref offsetY, ref context);

case View view: // Android.View and Android.IViewParent
var windowToFirstParent = new int[2];
Expand Down
26 changes: 20 additions & 6 deletions src/Uno.UI/UI/Xaml/UIElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,9 @@ protected virtual void OnVisibilityChanged(Visibility oldValue, Visibility newVi

internal AutomationPeer OnCreateAutomationPeerInternal() => OnCreateAutomationPeer();

internal static Matrix3x2 GetTransform(UIElement from, UIElement to)
internal static Matrix3x2 GetTransform(UIElement from, UIElement to) => GetTransform(from, to, new());

private static Matrix3x2 GetTransform(UIElement from, UIElement to, TransformToVisualContext context)
{
var logInfoString = from.Log().IsEnabled(LogLevel.Debug) ? new StringBuilder() : null;
logInfoString?.Append($"{nameof(GetTransform)}(from: {from}, to: {to?.ToString() ?? "<null>"}) Offsets: [");
Expand Down Expand Up @@ -525,7 +527,7 @@ internal static Matrix3x2 GetTransform(UIElement from, UIElement to)
#endif

logInfoString?.Append($"{elt}: ({offsetX}, {offsetY}), ");
} while (elt.TryGetParentUIElementForTransformToVisual(out elt, ref offsetX, ref offsetY) && elt != to); // If possible we stop as soon as we reach 'to'
} while (elt.TryGetParentUIElementForTransformToVisual(out elt, ref offsetX, ref offsetY, ref context) && elt != to); // If possible we stop as soon as we reach 'to'

matrix *= Matrix3x2.CreateTranslation((float)offsetX, (float)offsetY);

Expand All @@ -534,10 +536,20 @@ internal static Matrix3x2 GetTransform(UIElement from, UIElement to)
// Unfortunately we didn't find the 'to' in the parent hierarchy,
// so matrix == fromToRoot and we now have to compute the transform 'toToRoot'.
// Note: We do not propagate the 'intermediatesSelector' as cached transforms would be irrelevant
var toToRoot = GetTransform(to, null);
var rootToTo = toToRoot.Inverse();
var toContext = new TransformToVisualContext();
var toToRoot = GetTransform(to, null, toContext);

matrix *= rootToTo;
#if __IOS__
// On iOS, the `from` and `to` may be coming different ViewController.
// In such case, their coordinates should not be "added" together, since they are from different coordinates space.
if (context?.ViewController is { } vc1 &&
toContext?.ViewController is { } vc2 &&
vc1 == vc2)
#endif
{
var rootToTo = toToRoot.Inverse();
matrix *= rootToTo;
}
}

if (logInfoString != null)
Expand All @@ -553,7 +565,7 @@ internal static Matrix3x2 GetTransform(UIElement from, UIElement to)
/// Note: Offsets are only an approximation which does not take in consideration possible transformations
/// applied by a 'UIView' between this element and its parent UIElement.
/// </summary>
private bool TryGetParentUIElementForTransformToVisual(out UIElement parentElement, ref double offsetX, ref double offsetY)
private bool TryGetParentUIElementForTransformToVisual(out UIElement parentElement, ref double offsetX, ref double offsetY, ref TransformToVisualContext context)
{
var parent = VisualTreeHelper.GetParent(this);
switch (parent)
Expand Down Expand Up @@ -1132,5 +1144,7 @@ public UI.Input.InputCursor ProtectedCursor
set;
}
#endif

private partial class TransformToVisualContext { }
}
}
14 changes: 12 additions & 2 deletions src/Uno.UI/UI/Xaml/UIElement.iOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ internal Windows.Foundation.Point GetPosition(Point position, global::Windows.UI
/// Note: Offsets are only an approximation which does not take in consideration possible transformations
/// applied by a 'UIView' between this element and its parent UIElement.
/// </summary>
private bool TryGetParentUIElementForTransformToVisual(out UIElement parentElement, ref double offsetX, ref double offsetY)
private bool TryGetParentUIElementForTransformToVisual(out UIElement parentElement, ref double offsetX, ref double offsetY, ref TransformToVisualContext context)
{
var parent = this.GetVisualTreeParent();
switch (parent)
Expand Down Expand Up @@ -222,18 +222,28 @@ private bool TryGetParentUIElementForTransformToVisual(out UIElement parentEleme
case null:
// We reached the top of the window without any UIElement in the hierarchy,
// so we adjust offsets using the X/Y position of the original 'view' in the window.

offset = view.ConvertRectToView(default, null).Location;

parentElement = null;
offsetX += offset.X;
offsetY += offset.Y;

if (this.FindViewController() is { } vc)
{
context.ViewController = vc;
}

return false;
}
} while (true);
}
}

partial class TransformToVisualContext
{
public UIViewController ViewController { get; set; }
}

#if DEBUG
public static Predicate<UIView> ViewOfInterestSelector { get; set; } = v => (v as FrameworkElement)?.Name == "TargetView";

Expand Down
2 changes: 1 addition & 1 deletion src/Uno.UI/UI/Xaml/UIElement.macOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ private protected override void OnNativeFlagsChanged(NSEvent evt)

private bool CheckFlagKeyDown(NSEventModifierMask flag, NSEventModifierMask newMask) => !_lastFlags.HasFlag(flag) && newMask.HasFlag(flag);

private bool TryGetParentUIElementForTransformToVisual(out UIElement parentElement, ref double offsetX, ref double offsetY)
private bool TryGetParentUIElementForTransformToVisual(out UIElement parentElement, ref double offsetX, ref double offsetY, ref TransformToVisualContext context)
{
var parent = this.GetVisualTreeParent();
switch (parent)
Expand Down

0 comments on commit af92831

Please sign in to comment.