From 0d96f165f4ea499536a7e9b4027aa9612fcb9aa5 Mon Sep 17 00:00:00 2001 From: Vitaly Knyazev Date: Fri, 20 Dec 2024 20:02:34 +0000 Subject: [PATCH 1/5] Fixed issue 26769 - crash when iOS app is running on MacOS and "More" item is clicked in ListView context menu. Checking PopoverPresentationController for null, it seems to be null checked already in all other places. --- .../Core/src/iOS/ContextActionCell.cs | 9 ++++++--- src/Compatibility/Core/src/iOS/Platform.cs | 15 +++++++++++---- .../Handlers/ListView/iOS/ContextActionCell.cs | 9 ++++++--- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/Compatibility/Core/src/iOS/ContextActionCell.cs b/src/Compatibility/Core/src/iOS/ContextActionCell.cs index e91587cd126b..784d79427244 100644 --- a/src/Compatibility/Core/src/iOS/ContextActionCell.cs +++ b/src/Compatibility/Core/src/iOS/ContextActionCell.cs @@ -345,15 +345,18 @@ void ActivateMore() if (controller == null) throw new InvalidOperationException("No UIViewController found to present."); - if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone) + if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone || (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad && actionSheet.PopoverPresentationController == null)) { var cancel = UIAlertAction.Create(StringResources.Cancel, UIAlertActionStyle.Cancel, null); actionSheet.AddAction(cancel); } else { - actionSheet.PopoverPresentationController.SourceView = _tableView; - actionSheet.PopoverPresentationController.SourceRect = sourceRect; + if (actionSheet.PopoverPresentationController != null) + { + actionSheet.PopoverPresentationController.SourceView = _tableView; + actionSheet.PopoverPresentationController.SourceRect = sourceRect; + } } controller.PresentViewController(actionSheet, true, null); diff --git a/src/Compatibility/Core/src/iOS/Platform.cs b/src/Compatibility/Core/src/iOS/Platform.cs index 37ccdfe94be4..d1503c2929c2 100644 --- a/src/Compatibility/Core/src/iOS/Platform.cs +++ b/src/Compatibility/Core/src/iOS/Platform.cs @@ -518,7 +518,11 @@ static void PresentPopUp(UIWindow window, UIAlertController alert, ActionSheetAr { UIDevice.CurrentDevice.BeginGeneratingDeviceOrientationNotifications(); var observer = NSNotificationCenter.DefaultCenter.AddObserver(UIDevice.OrientationDidChangeNotification, - n => { alert.PopoverPresentationController.SourceRect = window.RootViewController.View.Bounds; }); + n => + { + if (alert.PopoverPresentationController != null) + alert.PopoverPresentationController.SourceRect = window.RootViewController.View.Bounds; + }); arguments.Result.Task.ContinueWith(t => { @@ -526,9 +530,12 @@ static void PresentPopUp(UIWindow window, UIAlertController alert, ActionSheetAr UIDevice.CurrentDevice.EndGeneratingDeviceOrientationNotifications(); }, TaskScheduler.FromCurrentSynchronizationContext()); - alert.PopoverPresentationController.SourceView = window.RootViewController.View; - alert.PopoverPresentationController.SourceRect = window.RootViewController.View.Bounds; - alert.PopoverPresentationController.PermittedArrowDirections = 0; // No arrow + if (alert.PopoverPresentationController != null) + { + alert.PopoverPresentationController.SourceView = window.RootViewController.View; + alert.PopoverPresentationController.SourceRect = window.RootViewController.View.Bounds; + alert.PopoverPresentationController.PermittedArrowDirections = 0; // No arrow + } } window.RootViewController.PresentViewController(alert, true, null); diff --git a/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/ContextActionCell.cs b/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/ContextActionCell.cs index 47c16b8d96b4..589788cd4bfb 100644 --- a/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/ContextActionCell.cs +++ b/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/ContextActionCell.cs @@ -340,15 +340,18 @@ void ActivateMore() if (controller == null) throw new InvalidOperationException("No UIViewController found to present."); - if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone) + if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone || (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad && actionSheet.PopoverPresentationController == null)) { var cancel = UIAlertAction.Create(StringResources.Cancel, UIAlertActionStyle.Cancel, null); actionSheet.AddAction(cancel); } else { - actionSheet.PopoverPresentationController.SourceView = _tableView; - actionSheet.PopoverPresentationController.SourceRect = sourceRect; + if (actionSheet.PopoverPresentationController != null) + { + actionSheet.PopoverPresentationController.SourceView = _tableView; + actionSheet.PopoverPresentationController.SourceRect = sourceRect; + } } controller.PresentViewController(actionSheet, true, null); From 6773f1ab7e9f5c73e9cd3ab87e7d7170724bb34a Mon Sep 17 00:00:00 2001 From: Vitaly Knyazev Date: Fri, 28 Mar 2025 14:54:45 +0000 Subject: [PATCH 2/5] Fixed iOS cell resizing issue #23319, CellRenderer.GetCell may not be called when overridden in derived class --- .../Core/Compatibility/Handlers/ListView/iOS/CellRenderer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/CellRenderer.cs b/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/CellRenderer.cs index 1d34dcddd347..460b565bb996 100644 --- a/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/CellRenderer.cs +++ b/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/CellRenderer.cs @@ -32,12 +32,12 @@ protected override UITableViewCell CreatePlatformElement() var tv = VirtualView.TableView; VirtualView.ReusableCell = null; VirtualView.TableView = null; + _tableView = new(tv); return GetCell(VirtualView, reusableCell, tv); } public virtual UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv) { - _tableView = new(tv); Performance.Start(out string reference); var tvc = reusableCell as CellTableViewCell ?? new CellTableViewCell(UITableViewCellStyle.Default, item.GetType().FullName); From 5355600c8c756a15001f7f00bda65c02ee314849 Mon Sep 17 00:00:00 2001 From: Vitaly Knyazev Date: Thu, 10 Apr 2025 14:44:58 +0100 Subject: [PATCH 3/5] Fixed potential NRE probably due to copy/paste bug --- .../Handlers/NavigationPage/iOS/NavigationRenderer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Controls/src/Core/Compatibility/Handlers/NavigationPage/iOS/NavigationRenderer.cs b/src/Controls/src/Core/Compatibility/Handlers/NavigationPage/iOS/NavigationRenderer.cs index bd2e54e64115..0028910266f6 100644 --- a/src/Controls/src/Core/Compatibility/Handlers/NavigationPage/iOS/NavigationRenderer.cs +++ b/src/Controls/src/Core/Compatibility/Handlers/NavigationPage/iOS/NavigationRenderer.cs @@ -1655,7 +1655,7 @@ void UpdateNavigationBarVisibility(bool animated) return; var hasNavBar = NavigationPage.GetHasNavigationBar(current); - if (!_navigation.TryGetTarget(out NavigationRenderer navigationRenderer)) + if (_navigation.TryGetTarget(out NavigationRenderer navigationRenderer)) { navigationRenderer._hasNavigationBar = hasNavBar; } From 2e9e7b0f50a4f59b978f4e66ee0d95f948516e1e Mon Sep 17 00:00:00 2001 From: Vitaly Knyazev Date: Thu, 10 Apr 2025 14:46:17 +0100 Subject: [PATCH 4/5] Fixed #28912 by hiding context menu buttons only if user ever swiped left --- .../Handlers/ListView/iOS/ContextScrollViewDelegate.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/ContextScrollViewDelegate.cs b/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/ContextScrollViewDelegate.cs index c783b67fcc25..2c83a216c3e1 100644 --- a/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/ContextScrollViewDelegate.cs +++ b/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/ContextScrollViewDelegate.cs @@ -48,6 +48,7 @@ internal sealed class ContextScrollViewDelegate : UIScrollViewDelegate bool _isDisposed; static WeakReference s_scrollViewBeingScrolled; + bool _wasPositive; UITableView _table; public ContextScrollViewDelegate(UIView container, List buttons, bool isOpen) @@ -104,6 +105,9 @@ public override void Scrolled(UIScrollView scrollView) var count = _buttons.Count; var ioffset = scrollView.ContentOffset.X / (float)count; + if (ioffset > 0f) + _wasPositive = true; + if (ioffset > width) width = ioffset + 1; @@ -114,13 +118,14 @@ public override void Scrolled(UIScrollView scrollView) b.Frame = new RectangleF(scrollView.Frame.Width + (count - (i + 1)) * ioffset, 0, width, rect.Height); } - if (scrollView.ContentOffset.X == 0) + if (_wasPositive && scrollView.ContentOffset.X == 0) { IsOpen = false; SetButtonsShowing(false); RestoreHighlight(scrollView); s_scrollViewBeingScrolled = null; + _wasPositive = false; ClearCloserRecognizer(GetContextCell(scrollView)); ClosedCallback?.Invoke(); } From 354572a172bfd84f3628e665349d3d42d0cd6d06 Mon Sep 17 00:00:00 2001 From: Vitaly Knyazev Date: Thu, 10 Apr 2025 15:55:29 +0100 Subject: [PATCH 5/5] Better fix for #28912 --- .../ListView/iOS/ContextScrollViewDelegate.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/ContextScrollViewDelegate.cs b/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/ContextScrollViewDelegate.cs index 2c83a216c3e1..af4dcfd475f5 100644 --- a/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/ContextScrollViewDelegate.cs +++ b/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/ContextScrollViewDelegate.cs @@ -48,7 +48,7 @@ internal sealed class ContextScrollViewDelegate : UIScrollViewDelegate bool _isDisposed; static WeakReference s_scrollViewBeingScrolled; - bool _wasPositive; + bool _draggingEnded; UITableView _table; public ContextScrollViewDelegate(UIView container, List buttons, bool isOpen) @@ -91,6 +91,11 @@ public override void DraggingStarted(UIScrollView scrollView) RemoveHighlight(scrollView); } + public override void DraggingEnded(UIScrollView scrollView, bool willDecelerate) + { + _draggingEnded = true; + } + public void PrepareForDeselect(UIScrollView scrollView) { RestoreHighlight(scrollView); @@ -105,9 +110,6 @@ public override void Scrolled(UIScrollView scrollView) var count = _buttons.Count; var ioffset = scrollView.ContentOffset.X / (float)count; - if (ioffset > 0f) - _wasPositive = true; - if (ioffset > width) width = ioffset + 1; @@ -118,14 +120,14 @@ public override void Scrolled(UIScrollView scrollView) b.Frame = new RectangleF(scrollView.Frame.Width + (count - (i + 1)) * ioffset, 0, width, rect.Height); } - if (_wasPositive && scrollView.ContentOffset.X == 0) + if (_draggingEnded && scrollView.ContentOffset.X == 0) { IsOpen = false; SetButtonsShowing(false); RestoreHighlight(scrollView); s_scrollViewBeingScrolled = null; - _wasPositive = false; + _draggingEnded = false; ClearCloserRecognizer(GetContextCell(scrollView)); ClosedCallback?.Invoke(); }