diff --git a/Xamarin.Forms.ControlGallery.Android/Xamarin.Forms.ControlGallery.Android.csproj b/Xamarin.Forms.ControlGallery.Android/Xamarin.Forms.ControlGallery.Android.csproj
index 4c10dbd7bf6..75378353f33 100644
--- a/Xamarin.Forms.ControlGallery.Android/Xamarin.Forms.ControlGallery.Android.csproj
+++ b/Xamarin.Forms.ControlGallery.Android/Xamarin.Forms.ControlGallery.Android.csproj
@@ -395,7 +395,7 @@
-
+
\ No newline at end of file
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/HeaderFooterShellFlyout.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/HeaderFooterShellFlyout.cs
index 4879e02e781..f7eff9cf47a 100644
--- a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/HeaderFooterShellFlyout.cs
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/HeaderFooterShellFlyout.cs
@@ -150,11 +150,47 @@ protected override void Init()
}),
AutomationId = "ResizeHeaderFooter"
});
+
+ if (Device.RuntimePlatform == Device.iOS)
+ {
+ Items.Add(new MenuItem()
+ {
+ Text = "Zero Margin Header Test",
+ Command = new Command(() =>
+ {
+ FlyoutHeader =
+ new StackLayout()
+ {
+ AutomationId = "ZeroMarginLayout",
+ Margin = 0,
+ Children =
+ {
+ new Label() { Text = "Header View" }
+ }
+ };
+
+ FlyoutHeaderTemplate = null;
+ FlyoutBehavior = FlyoutBehavior.Locked;
+ }),
+ AutomationId = "ZeroMarginHeader"
+ });
+ }
}
#if UITEST
+#if __IOS__
+ [Test]
+ public void FlyoutHeaderWithZeroMarginShouldHaveNoY()
+ {
+ RunningApp.WaitForElement("PageLoaded");
+ this.TapInFlyout("ZeroMarginHeader", makeSureFlyoutStaysOpen: true);
+ var layout = RunningApp.WaitForElement("ZeroMarginLayout")[0].Rect.Y;
+ Assert.AreEqual(0, layout);
+ }
+#endif
+
[Test]
public void FlyoutTests()
{
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue12429.xaml b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue12429.xaml
new file mode 100644
index 00000000000..0f7e8d419af
--- /dev/null
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue12429.xaml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue12429.xaml.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue12429.xaml.cs
new file mode 100644
index 00000000000..d6cf79d7349
--- /dev/null
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue12429.xaml.cs
@@ -0,0 +1,150 @@
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Xamarin.Forms.CustomAttributes;
+using Xamarin.Forms.Internals;
+#if UITEST
+using Xamarin.UITest;
+using NUnit.Framework;
+using Xamarin.Forms.Core.UITests;
+#endif
+
+
+namespace Xamarin.Forms.Controls.Issues
+{
+ [Preserve(AllMembers = true)]
+ [Issue(IssueTracker.Github, 12429, "[Bug] Shell flyout items have a minimum height", PlatformAffected.iOS)]
+#if UITEST
+ [NUnit.Framework.Category(UITestCategories.Shell)]
+#endif
+ public partial class Issue12429 : TestShell
+ {
+ public double SmallFlyoutItem { get; }
+ public double SizeToModifyBy { get; }
+
+ public Issue12429()
+ {
+ SmallFlyoutItem = 35d;
+ SizeToModifyBy = 20d;
+
+#if APP
+ InitializeComponent();
+
+
+ if (Device.RuntimePlatform == Device.Android)
+ SmallFlyoutItem = SmallFlyoutItem / Device.info.ScalingFactor;
+
+ if (Device.RuntimePlatform == Device.Android)
+ SizeToModifyBy = SizeToModifyBy / Device.info.ScalingFactor;
+#endif
+
+
+ this.BindingContext = this;
+ }
+
+ protected override void Init()
+ {
+ }
+
+ void ResizeFlyoutItem(System.Object sender, System.EventArgs e)
+ {
+ ((sender as Element).Parent as VisualElement).HeightRequest += SizeToModifyBy;
+ }
+
+ void ResizeFlyoutItemDown(System.Object sender, System.EventArgs e)
+ {
+ ((sender as Element).Parent as VisualElement).HeightRequest -= SizeToModifyBy;
+ }
+
+#if UITEST
+ [Test]
+ public void FlyoutItemSizesToExplicitHeight()
+ {
+ RunningApp.WaitForElement("PageLoaded");
+ this.ShowFlyout();
+ var height = RunningApp.WaitForElement("SmallFlyoutItem")[0].Rect.Height;
+ Assert.That(height, Is.EqualTo(SmallFlyoutItem).Within(1));
+ }
+
+
+ [Test]
+ public void FlyoutItemHeightAndWidthIncreaseAndDecreaseCorrectly()
+ {
+ RunningApp.WaitForElement("PageLoaded");
+ this.ShowFlyout();
+ var initialHeight = RunningApp.WaitForElement("ResizeMe")[0].Rect.Height;
+
+ TapInFlyout("ResizeFlyoutItem", makeSureFlyoutStaysOpen: true);
+ var newHeight = RunningApp.WaitForElement("ResizeMe")[0].Rect.Height;
+ Assert.That(newHeight - initialHeight, Is.EqualTo(SizeToModifyBy).Within(1));
+
+ TapInFlyout("ResizeFlyoutItemDown", makeSureFlyoutStaysOpen: true);
+ newHeight = RunningApp.WaitForElement("ResizeMe")[0].Rect.Height;
+ Assert.That(initialHeight, Is.EqualTo(newHeight).Within(1));
+
+ TapInFlyout("ResizeFlyoutItemDown", makeSureFlyoutStaysOpen: true);
+ newHeight = RunningApp.WaitForElement("ResizeMe")[0].Rect.Height;
+ Assert.That(initialHeight - newHeight, Is.EqualTo(SizeToModifyBy).Within(1));
+
+ }
+#endif
+
+ }
+
+
+ [Preserve(AllMembers = true)]
+ public class Issue12429Page : ContentPage
+ {
+ public Issue12429Page()
+ {
+ Background = SolidColorBrush.White;
+ var label = new Label
+ {
+ Text = "Flyout Item 1: Explicit Height of 35, Flyout Item 2: will grow and shrink when you click the buttons, Flyout Item 3: doesn't exist, and Flyout Item 4: uses the default platform sizes.",
+ VerticalTextAlignment = TextAlignment.Center,
+ TextColor = Color.Black,
+ AutomationId = "PageLoaded"
+ };
+
+ Content = new StackLayout()
+ {
+ Children =
+ {
+ new Label
+ {
+ Text = "Flyout Item 1: Explicit Height of 35.",
+ VerticalTextAlignment = TextAlignment.Center,
+ TextColor = Color.Black,
+ AutomationId = "PageLoaded"
+ },
+ new Label
+ {
+ Text = "Flyout Item 2: Height sizes to the content.",
+ VerticalTextAlignment = TextAlignment.Center,
+ TextColor = Color.Black
+ },
+ new Label
+ {
+ Text = "Flyout Item 3: will grow and shrink when you click the buttons.",
+ VerticalTextAlignment = TextAlignment.Center,
+ TextColor = Color.Black
+ },
+ new Label
+ {
+ Text = "Flyout Item 4: doesn't exist. You should only see 4 Flyout Items",
+ VerticalTextAlignment = TextAlignment.Center,
+ TextColor = Color.Black
+ },
+ new Label
+ {
+ Text = "Flyout Item 5: uses the default height if no templates are used.",
+ VerticalTextAlignment = TextAlignment.Center,
+ TextColor = Color.Black
+ }
+ }
+ };
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
index c20e43abc09..67fce122d35 100644
--- a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
@@ -55,6 +55,10 @@
Issue12344.xaml
+
+ Issue12429.xaml
+ Code
+
@@ -2566,9 +2570,13 @@
Designer
MSBuild:UpdateDesignTimeXaml
+
+ Designer
+ MSBuild:UpdateDesignTimeXaml
+
Designer
MSBuild:UpdateDesignTimeXaml
-
\ No newline at end of file
+
diff --git a/Xamarin.Forms.Core/Shell/BaseShellItem.cs b/Xamarin.Forms.Core/Shell/BaseShellItem.cs
index 3429dae3c4c..70e2564dc6c 100644
--- a/Xamarin.Forms.Core/Shell/BaseShellItem.cs
+++ b/Xamarin.Forms.Core/Shell/BaseShellItem.cs
@@ -394,6 +394,9 @@ internal static DataTemplate CreateDefaultFlyoutItemCell(string textBinding, str
if (Device.RuntimePlatform == Device.Android)
defaultGridClass.Setters.Add(new Setter { Property = Grid.HeightRequestProperty, Value = 50 });
+ else
+ defaultGridClass.Setters.Add(new Setter { Property = Grid.HeightRequestProperty, Value = 44 });
+
ColumnDefinitionCollection columnDefinitions = new ColumnDefinitionCollection();
diff --git a/Xamarin.Forms.Platform.Android/Renderers/ContainerView.cs b/Xamarin.Forms.Platform.Android/Renderers/ContainerView.cs
index 953665e1b35..9fc382c417f 100644
--- a/Xamarin.Forms.Platform.Android/Renderers/ContainerView.cs
+++ b/Xamarin.Forms.Platform.Android/Renderers/ContainerView.cs
@@ -8,9 +8,8 @@ namespace Xamarin.Forms.Platform.Android
{
public class ContainerView : ViewGroup
{
- IVisualElementRenderer _renderer;
View _view;
-
+ ShellViewRenderer _shellViewRenderer;
public ContainerView(Context context, View view) : base(context)
{
View = view;
@@ -51,22 +50,20 @@ protected override void Dispose(bool disposing)
if (disposing)
{
- _renderer?.Dispose();
- _renderer = null;
+ _shellViewRenderer?.TearDown();
_view = null;
}
}
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
- if (_renderer == null)
+ if (_shellViewRenderer == null)
return;
var width = Context.FromPixels(r - l);
var height = Context.FromPixels(b - t);
- LayoutView(0, 0, width, height);
- _renderer.UpdateLayout();
+ _shellViewRenderer.LayoutView(width, height);
}
protected virtual void LayoutView(double x, double y, double width, double height)
@@ -81,9 +78,12 @@ protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
SetMeasuredDimension(0, 0);
return;
}
-
- // chain on down
- _renderer.View.Measure(widthMeasureSpec, heightMeasureSpec);
+ if (!View.IsVisible)
+ {
+ View.Measure(0, 0);
+ SetMeasuredDimension(0, 0);
+ return;
+ }
var width = MeasureSpecFactory.GetSize(widthMeasureSpec);
var height = MeasureSpecFactory.GetSize(heightMeasureSpec);
@@ -91,41 +91,21 @@ protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
var measureWidth = width > 0 ? Context.FromPixels(width) : double.PositiveInfinity;
var measureHeight = height > 0 ? Context.FromPixels(height) : double.PositiveInfinity;
- var sizeReq = View.Measure(measureWidth, measureHeight);
+ _shellViewRenderer.LayoutView(measureWidth, measureHeight);
- SetMeasuredDimension((MatchWidth && width != 0) ? width : (int)Context.ToPixels(sizeReq.Request.Width),
- (MatchHeight && height != 0) ? height : (int)Context.ToPixels(sizeReq.Request.Height));
+ SetMeasuredDimension((MatchWidth && width != 0) ? width : (int)Context.ToPixels(View.Width),
+ (MatchHeight && height != 0) ? height : (int)Context.ToPixels(View.Height));
}
protected virtual void OnViewSet(View view)
{
- if (_renderer != null)
- {
- _renderer.Element.MeasureInvalidated -= ElementMeasureInvalidated;
- _renderer.View.RemoveFromParent();
- _renderer.Dispose();
- _renderer = null;
- }
+ if (_shellViewRenderer == null)
+ _shellViewRenderer = new ShellViewRenderer(this.Context, view);
+ else
+ _shellViewRenderer.OnViewSet(view);
- if (view != null)
- {
- _renderer = Platform.CreateRenderer(view, Context);
- Platform.SetRenderer(view, _renderer);
- AddView(_renderer.View);
- view.MeasureInvalidated += ElementMeasureInvalidated;
- }
- }
-
- void ElementMeasureInvalidated(object sender, EventArgs e)
- {
- if (this.IsAlive())
- {
- RequestLayout();
- }
- else if (sender is VisualElement ve)
- {
- ve.MeasureInvalidated -= ElementMeasureInvalidated;
- }
+ if (_shellViewRenderer.NativeView != null)
+ AddView(_shellViewRenderer.NativeView);
}
}
-}
\ No newline at end of file
+}
diff --git a/Xamarin.Forms.Platform.Android/Renderers/ShellViewRenderer.cs b/Xamarin.Forms.Platform.Android/Renderers/ShellViewRenderer.cs
index 2aab584afbe..c35a8097bda 100644
--- a/Xamarin.Forms.Platform.Android/Renderers/ShellViewRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/Renderers/ShellViewRenderer.cs
@@ -137,4 +137,4 @@ public AView NativeView
private set;
}
}
-}
\ No newline at end of file
+}
diff --git a/Xamarin.Forms.Platform.UAP/Shell/ShellFlyoutItemRenderer.cs b/Xamarin.Forms.Platform.UAP/Shell/ShellFlyoutItemRenderer.cs
index 40496df13a4..4c8239bb732 100644
--- a/Xamarin.Forms.Platform.UAP/Shell/ShellFlyoutItemRenderer.cs
+++ b/Xamarin.Forms.Platform.UAP/Shell/ShellFlyoutItemRenderer.cs
@@ -6,6 +6,7 @@
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Media;
using WRect = Windows.Foundation.Rect;
namespace Xamarin.Forms.Platform.UWP
@@ -22,6 +23,7 @@ public class ShellFlyoutItemRenderer : ContentControl
public ShellFlyoutItemRenderer()
{
this.DataContextChanged += OnDataContextChanged;
+ this.LayoutUpdated += OnLayoutUpdated;
}
public bool IsSelected
@@ -34,7 +36,7 @@ void OnDataContextChanged(Windows.UI.Xaml.FrameworkElement sender, Windows.UI.Xa
{
if (_content != null)
{
- if(_content.BindingContext is INotifyPropertyChanged inpc)
+ if (_content.BindingContext is INotifyPropertyChanged inpc)
inpc.PropertyChanged -= ShellElementPropertyChanged;
_content.Cleanup();
@@ -49,10 +51,10 @@ void OnDataContextChanged(Windows.UI.Xaml.FrameworkElement sender, Windows.UI.Xa
var shell = element?.FindParent();
DataTemplate dataTemplate = (shell as IShellController)?.GetFlyoutItemDataTemplate(bo);
- if(bo != null)
+ if (bo != null)
bo.PropertyChanged += ShellElementPropertyChanged;
- if(dataTemplate != null)
+ if (dataTemplate != null)
{
_content = (View)dataTemplate.CreateContent();
_content.BindingContext = bo;
@@ -78,9 +80,6 @@ void OnFrameworkElementLoaded(object _, RoutedEventArgs __)
UpdateVisualState();
OnMeasureInvalidated();
-
- if (renderer.ContainerElement != null)
- renderer.ContainerElement.SetAutomationPropertiesAutomationId(element.AutomationId);
}
}
@@ -88,7 +87,7 @@ void ShellElementPropertyChanged(object sender, System.ComponentModel.PropertyCh
{
if (e.Is(BaseShellItem.IsCheckedProperty))
UpdateVisualState();
-
+
}
void OnMeasureInvalidated(object sender, EventArgs e)
@@ -96,9 +95,43 @@ void OnMeasureInvalidated(object sender, EventArgs e)
OnMeasureInvalidated();
}
+ protected override Windows.Foundation.Size MeasureOverride(Windows.Foundation.Size availableSize)
+ {
+ return base.MeasureOverride(availableSize);
+ }
+
+ double _previousWidth;
+ private void OnLayoutUpdated(object sender, object e)
+ {
+ if (this.ActualWidth > 0 && this.ActualWidth != _content.Width && _previousWidth != this.ActualWidth)
+ {
+ _previousWidth = this.ActualWidth;
+ OnMeasureInvalidated();
+ }
+ }
+
void OnMeasureInvalidated()
{
- Size request = _content.Measure(double.PositiveInfinity, double.PositiveInfinity, MeasureFlags.IncludeMargins).Request;
+ if (this.ActualWidth <= 0)
+ return;
+
+ if (Parent is FrameworkElement fe)
+ {
+ if (!_content.IsVisible)
+ {
+ fe.Visibility = Visibility.Collapsed;
+ }
+ else
+ {
+ fe.Visibility = Visibility.Visible;
+ }
+ }
+
+
+ double height = (_content.HeightRequest < -1) ? _content.HeightRequest : double.PositiveInfinity;
+ double width = this.ActualWidth;
+
+ Size request = _content.Measure(width, height, MeasureFlags.IncludeMargins).Request;
var minSize = (double)Windows.UI.Xaml.Application.Current.Resources["NavigationViewItemOnLeftMinHeight"];
@@ -111,6 +144,7 @@ void OnMeasureInvalidated()
request.Width = this.ActualWidth;
Layout.LayoutChildIntoBoundingRegion(_content, new Rectangle(0, 0, request.Width, request.Height));
+ Clip = new RectangleGeometry { Rect = new WRect(0, 0, request.Width, request.Height) };
}
void UpdateVisualState()
diff --git a/Xamarin.Forms.Platform.UAP/Shell/ShellRenderer.cs b/Xamarin.Forms.Platform.UAP/Shell/ShellRenderer.cs
index 5979a5bee49..a6c48053125 100644
--- a/Xamarin.Forms.Platform.UAP/Shell/ShellRenderer.cs
+++ b/Xamarin.Forms.Platform.UAP/Shell/ShellRenderer.cs
@@ -42,7 +42,7 @@ public ShellRenderer()
IsPaneOpen = false;
Content = ItemRenderer = CreateShellItemRenderer();
MenuItemTemplateSelector = CreateShellFlyoutTemplateSelector();
- Style = Windows.UI.Xaml.Application.Current.Resources["ShellNavigationView"] as Windows.UI.Xaml.Style;
+ Style = (Windows.UI.Xaml.Style)Windows.UI.Xaml.Application.Current.Resources["ShellNavigationView"];
}
async void OnBackRequested(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewBackRequestedEventArgs args)
@@ -193,7 +193,7 @@ public void SetElement(VisualElement element)
}
#endregion IVisualElementRenderer
- ShellSplitView ShellSplitView => (ShellSplitView)GetTemplateChild("RootSplitView");
+ ShellSplitView ShellSplitView => GetTemplateChild("RootSplitView") as ShellSplitView;
ScrollViewer ShellLeftNavScrollViewer => (ScrollViewer)GetTemplateChild("LeftNavScrollViewer");
protected internal Shell Element { get; set; }
@@ -257,7 +257,7 @@ void UpdateFlyoutPosition()
{
splitView.SetFlyoutSizes(_flyoutHeight, _flyoutWidth);
if (IsPaneOpen)
- ShellSplitView.RefreshFlyoutPosition();
+ ShellSplitView?.RefreshFlyoutPosition();
}
}
@@ -271,7 +271,7 @@ void UpdateFlyoutBackdrop()
{
splitView.FlyoutBackdrop = _flyoutBackdrop;
if (IsPaneOpen)
- ShellSplitView.RefreshFlyoutBackdrop();
+ ShellSplitView?.RefreshFlyoutBackdrop();
}
}
diff --git a/Xamarin.Forms.Platform.UAP/Shell/ShellStyles.xaml b/Xamarin.Forms.Platform.UAP/Shell/ShellStyles.xaml
index 457494529c8..f8da71c4dc3 100644
--- a/Xamarin.Forms.Platform.UAP/Shell/ShellStyles.xaml
+++ b/Xamarin.Forms.Platform.UAP/Shell/ShellStyles.xaml
@@ -8,13 +8,14 @@
xmlns:contract7NotPresent="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractNotPresent(Windows.Foundation.UniversalApiContract,7)"
xmlns:primitiveContract7Present="using:Microsoft.UI.Xaml.Controls.Primitives?IsApiContractPresent(Windows.Foundation.UniversalApiContract,7)"
xmlns:xf="using:Xamarin.Forms.Platform.UWP">
+ 0
-
+
-
+
@@ -49,6 +50,9 @@
+
+ 0
+
@@ -552,7 +556,4 @@
-
-
-
diff --git a/Xamarin.Forms.Platform.iOS/Renderers/ShellTableViewController.cs b/Xamarin.Forms.Platform.iOS/Renderers/ShellTableViewController.cs
index 51377619a71..e97d6f23a2f 100644
--- a/Xamarin.Forms.Platform.iOS/Renderers/ShellTableViewController.cs
+++ b/Xamarin.Forms.Platform.iOS/Renderers/ShellTableViewController.cs
@@ -131,7 +131,7 @@ public void LayoutParallax()
TableView.Frame =
new CGRect(parent.Bounds.X, HeaderTopMargin, parent.Bounds.Width, parent.Bounds.Height - HeaderTopMargin - footerHeight);
- if (HeaderView != null)
+ if (HeaderView != null && !double.IsNaN(_headerSize))
{
var margin = HeaderView.Margin;
var leftMargin = margin.Left - margin.Right;
diff --git a/Xamarin.Forms.Platform.iOS/Renderers/ShellTableViewSource.cs b/Xamarin.Forms.Platform.iOS/Renderers/ShellTableViewSource.cs
index 378559751e2..65a45621998 100644
--- a/Xamarin.Forms.Platform.iOS/Renderers/ShellTableViewSource.cs
+++ b/Xamarin.Forms.Platform.iOS/Renderers/ShellTableViewSource.cs
@@ -11,7 +11,7 @@ public class ShellTableViewSource : UITableViewSource
readonly IShellContext _context;
readonly Action _onElementSelected;
List> _groups;
- Dictionary _views;
+ Dictionary _cells;
IShellController ShellController => (IShellController)_context.Shell;
@@ -30,7 +30,14 @@ public List> Groups
if (_groups == null)
{
_groups = ((IShellController)_context.Shell).GenerateFlyoutGrouping();
- _views = new Dictionary();
+
+ if (_cells != null)
+ {
+ foreach (var cell in _cells.Values)
+ cell.Disconnect();
+ }
+
+ _cells = new Dictionary();
}
return _groups;
@@ -48,7 +55,12 @@ public void ClearCache()
if(newGroups != _groups)
{
_groups = newGroups;
- _views = new Dictionary();
+ if (_cells != null)
+ {
+ foreach (var cell in _cells.Values)
+ cell.Disconnect();
+ }
+ _cells = new Dictionary();
}
}
@@ -57,19 +69,21 @@ public override nfloat GetHeightForRow(UITableView tableView, NSIndexPath indexP
int section = indexPath.Section;
int row = indexPath.Row;
var context = Groups[section][row];
- View view;
- if (!_views.TryGetValue(context, out view))
+ if (!_cells.TryGetValue(context, out var view))
return UITableView.AutomaticDimension;
- nfloat defaultHeight = tableView.EstimatedRowHeight == -1 ? 44 : tableView.EstimatedRowHeight;
+ if (!view.View.IsVisible)
+ return 0;
+
+ nfloat defaultHeight = tableView.EstimatedRowHeight == -1 ? 0 : tableView.EstimatedRowHeight;
nfloat height = -1;
- if (view.HeightRequest >= 0)
- height = (float)view.HeightRequest;
+ if (view.View.HeightRequest >= 0)
+ height = (float)view.View.HeightRequest;
else
{
- var request = view.Measure(tableView.Bounds.Width, double.PositiveInfinity, MeasureFlags.None);
+ var request = view.View.Measure(tableView.Bounds.Width, double.PositiveInfinity, MeasureFlags.None);
if (request.Request.Height > defaultHeight)
height = (float)request.Request.Height;
@@ -103,28 +117,39 @@ public override UITableViewCell GetCell(UITableView tableView, NSIndexPath index
var cellId = ((IDataTemplateController)template.SelectDataTemplate(context, _context.Shell)).IdString;
- var cell = (UIContainerCell)tableView.DequeueReusableCell(cellId);
-
- if (cell == null)
+ UIContainerCell cell;
+ if (!_cells.TryGetValue(context, out cell))
{
var view = (View)template.CreateContent(context, _context.Shell);
cell = new UIContainerCell(cellId, view);
-
+
// Set Parent after binding context so parent binding context doesn't propagate to view
cell.BindingContext = context;
view.Parent = _context.Shell;
}
else
{
+ var view = _cells[context].View;
+ cell.Disconnect();
+ cell = new UIContainerCell(cellId, view);
cell.BindingContext = context;
}
cell.SetAccessibilityProperties(context);
- _views[context] = cell.View;
+ _cells[context] = cell;
+ cell.TableView = tableView;
+ cell.IndexPath = indexPath;
+ cell.ViewMeasureInvalidated += OnViewMeasureInvalidated;
+
return cell;
}
+ void OnViewMeasureInvalidated(UIContainerCell cell)
+ {
+ cell.ReloadRow();
+ }
+
public override nfloat GetHeightForFooter(UITableView tableView, nint section)
{
if (section < Groups.Count - 1)
diff --git a/Xamarin.Forms.Platform.iOS/Renderers/UIContainerCell.cs b/Xamarin.Forms.Platform.iOS/Renderers/UIContainerCell.cs
index 45164abd45b..19fd6ef6297 100644
--- a/Xamarin.Forms.Platform.iOS/Renderers/UIContainerCell.cs
+++ b/Xamarin.Forms.Platform.iOS/Renderers/UIContainerCell.cs
@@ -1,4 +1,6 @@
-using UIKit;
+using System;
+using Foundation;
+using UIKit;
namespace Xamarin.Forms.Platform.iOS
{
@@ -6,20 +8,51 @@ public class UIContainerCell : UITableViewCell
{
IVisualElementRenderer _renderer;
object _bindingContext;
+ internal Action ViewMeasureInvalidated { get; set; }
+ internal NSIndexPath IndexPath { get; set; }
+ internal UITableView TableView { get; set; }
public UIContainerCell(string cellId, View view) : base(UITableViewCellStyle.Default, cellId)
{
View = view;
-
+ View.MeasureInvalidated += MeasureInvalidated;
SelectionStyle = UITableViewCellSelectionStyle.None;
_renderer = Platform.CreateRenderer(view);
Platform.SetRenderer(view, _renderer);
- AddSubview(_renderer.NativeView);
+ ContentView.AddSubview(_renderer.NativeView);
+ _renderer.NativeView.ClipsToBounds = true;
+ ContentView.ClipsToBounds = true;
+ }
+
+ void MeasureInvalidated(object sender, System.EventArgs e)
+ {
+ if (View == null || TableView == null)
+ return;
+
+ ViewMeasureInvalidated?.Invoke(this);
+ }
+
+ internal void ReloadRow()
+ {
+ TableView.ReloadRows(new[] { IndexPath }, UITableViewRowAnimation.Automatic);
+ }
+
+ internal void Disconnect()
+ {
+ ViewMeasureInvalidated = null;
+ View.MeasureInvalidated -= MeasureInvalidated;
+ if (_bindingContext != null && _bindingContext is BaseShellItem baseShell)
+ baseShell.PropertyChanged -= OnElementPropertyChanged;
+
+ _bindingContext = null;
+ Platform.SetRenderer(View, null);
+ View = null;
+ TableView = null;
}
- public View View { get; }
+ public View View { get; private set; }
public object BindingContext
{
@@ -46,7 +79,8 @@ public object BindingContext
public override void LayoutSubviews()
{
base.LayoutSubviews();
- View.Layout(Bounds.ToRectangle());
+ if(View != null)
+ View.Layout(Bounds.ToRectangle());
}
void UpdateVisualState()