Fix dynamic heights for iOS Flyout Item Templates (#8531) fixes #8290
authorShane Neuville <shneuvil@microsoft.com>
Thu, 5 Dec 2019 12:00:14 +0000 (05:00 -0700)
committerRui Marinho <me@ruimarinho.net>
Thu, 5 Dec 2019 12:00:14 +0000 (12:00 +0000)
* Fix dynamic heights for iOS Flyout

* - fix default height used

* Apply suggestions from code review

Xamarin.Forms.Controls/XamStore/StoreShell.xaml
Xamarin.Forms.Platform.iOS/Renderers/ShellFlyoutContentRenderer.cs
Xamarin.Forms.Platform.iOS/Renderers/ShellTableViewController.cs
Xamarin.Forms.Platform.iOS/Renderers/ShellTableViewSource.cs

index d5e1909..c478418 100644 (file)
                        <ContentView>
                                <Button Visual="Material" ImageSource="{Binding FlyoutIcon}" Text="{Binding Text}"  />
                        </ContentView>
-               </DataTemplate>
-               <DataTemplate x:Key="ShellItemTemplate">
+        </DataTemplate>
+        <DataTemplate x:Key="MenuItemTemplateWithHeight">
+            <StackLayout HeightRequest="200" BackgroundColor="Purple">
+                <Label Text="{Binding Text}"></Label>
+                <Label VerticalTextAlignment="End" VerticalOptions="EndAndExpand" Text="{Binding Text}"></Label>
+            </StackLayout>
+        </DataTemplate>
+        <DataTemplate x:Key="ShellItemTemplate">
                        <ContentView BackgroundColor="LightBlue">
                                <StackLayout Orientation="Horizontal">
                                        <Image Source="{Binding FlyoutIcon}"/>
                        <ShellContent Route="sharednotab" Title="No Tabs" ContentTemplate="{DataTemplate local:UpdatesPage}" />
                        <ShellContent Route="Notificationstabs" Shell.TabBarIsVisible="true" Title="Yes Tabs" ContentTemplate="{DataTemplate local:LibraryPage}" />
                </ShellSection>
-       </ShellItem>
+    </ShellItem>
+    <MenuItem Shell.MenuItemTemplate="{StaticResource MenuItemTemplateWithHeight}" Text="Height 200"/>
 </localTest:TestShell>
index 8bd9c90..98332fa 100644 (file)
@@ -18,16 +18,23 @@ namespace Xamarin.Forms.Platform.iOS
 
                public ShellFlyoutContentRenderer(IShellContext context)
                {
+                       _shellContext = context;
+
                        var header = ((IShellController)context.Shell).FlyoutHeader;
                        if (header != null)
                                _headerView = new UIContainerView(((IShellController)context.Shell).FlyoutHeader);
-                       _tableViewController = new ShellTableViewController(context, _headerView, OnElementSelected);
+
+                       _tableViewController = CreateShellTableViewController();
 
                        AddChildViewController(_tableViewController);
 
                        context.Shell.PropertyChanged += HandleShellPropertyChanged;
 
-                       _shellContext = context;
+               }
+
+               protected ShellTableViewController CreateShellTableViewController()
+               {
+                       return new ShellTableViewController(_shellContext, _headerView, OnElementSelected);
                }
 
                protected virtual void HandleShellPropertyChanged(object sender, PropertyChangedEventArgs e)
@@ -154,4 +161,4 @@ namespace Xamarin.Forms.Platform.iOS
                        ((IShellController)_shellContext.Shell).OnFlyoutItemSelected(element);
                }
        }
-}
\ No newline at end of file
+}
index b6a65bc..e01c838 100644 (file)
@@ -15,12 +15,14 @@ namespace Xamarin.Forms.Platform.iOS
                double _headerOffset = 0;
                double _headerSize;
                bool _isDisposed;
+               Action<Element> _onElementSelected;
 
                public ShellTableViewController(IShellContext context, UIContainerView headerView, Action<Element> onElementSelected)
                {
                        _context = context;
+                       _onElementSelected = onElementSelected;
                        _headerView = headerView;
-                       _source = new ShellTableViewSource(context, onElementSelected);
+                       _source = CreateShellTableViewSource();
                        _source.ScrolledEvent += OnScrolled;
                        if (_headerView != null)
                                _headerView.HeaderSizeChanged += OnHeaderSizeChanged;
@@ -29,6 +31,11 @@ namespace Xamarin.Forms.Platform.iOS
                        _context.Shell.PropertyChanged += OnShellPropertyChanged;
                }
 
+               protected ShellTableViewSource CreateShellTableViewSource()
+               {
+                       return new ShellTableViewSource(_context, _onElementSelected);
+               }
+
                void OnShellPropertyChanged(object sender, PropertyChangedEventArgs e)
                {
                        if (e.PropertyName == Shell.FlyoutHeaderBehaviorProperty.PropertyName)
@@ -59,22 +66,16 @@ namespace Xamarin.Forms.Platform.iOS
                        switch (_context.Shell.FlyoutVerticalScrollMode)
                        {
                                case ScrollMode.Auto:
-                                       var pathToFirstRow = Foundation.NSIndexPath.FromRowSection(0, 0);
-                                       var firstCellRect = TableView.RectForRowAtIndexPath(pathToFirstRow);
-                                       var firstCellIsVisible = TableView.Bounds.Contains(firstCellRect);
-
-                                       var lastRowIndex = NMath.Max(0, TableView.NumberOfRowsInSection(0) - 1);
-                                       var pathToLastRow = Foundation.NSIndexPath.FromRowSection(lastRowIndex, 0);
-                                       var cellRect = TableView.RectForRowAtIndexPath(pathToLastRow);
-                                       var lastCellIsVisible = TableView.Bounds.Contains(cellRect);
-
-                                       TableView.ScrollEnabled = !firstCellIsVisible || !lastCellIsVisible;
+                                       TableView.ScrollEnabled = true;
+                                       TableView.AlwaysBounceVertical = false;
                                        break;
                                case ScrollMode.Enabled:
                                        TableView.ScrollEnabled = true;
+                                       TableView.AlwaysBounceVertical = true;
                                        break;
                                case ScrollMode.Disabled:
                                        TableView.ScrollEnabled = false;
+                                       TableView.AlwaysBounceVertical = false;
                                        break;
                        }
                }
@@ -152,8 +153,11 @@ namespace Xamarin.Forms.Platform.iOS
                                        _headerView.HeaderSizeChanged -= OnHeaderSizeChanged;
 
                                _context.Shell.PropertyChanged -= OnShellPropertyChanged;
+
+                               _onElementSelected = null;
                        }
 
+                       
                        _isDisposed = true;
                        base.Dispose(disposing);
                }
index bf74f4e..8540f56 100644 (file)
@@ -13,6 +13,7 @@ namespace Xamarin.Forms.Platform.iOS
                DataTemplate _defaultItemTemplate;
                DataTemplate _defaultMenuItemTemplate;
                List<List<Element>> _groups;
+               Dictionary<Element, View> _views;
 
                public ShellTableViewSource(IShellContext context, Action<Element> onElementSelected)
                {
@@ -29,6 +30,7 @@ namespace Xamarin.Forms.Platform.iOS
                                if (_groups == null)
                                {
                                        _groups = ((IShellController)_context.Shell).GenerateFlyoutGrouping();
+                                       _views = new Dictionary<Element, View>();
                                }
                                return _groups;
                        }
@@ -43,6 +45,38 @@ namespace Xamarin.Forms.Platform.iOS
                public void ClearCache()
                {
                        _groups = null;
+                       _views = null;
+               }
+
+               public override nfloat GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
+               {
+                       int section = indexPath.Section;
+                       int row = indexPath.Row;
+                       var context = Groups[section][row];
+                       View view;
+
+                       if (!_views.TryGetValue(context, out view))
+                               return UITableView.AutomaticDimension;
+
+                       nfloat defaultHeight = tableView.EstimatedRowHeight == -1 ? 44 : tableView.EstimatedRowHeight;
+                       nfloat height = -1;
+
+                       if (view.HeightRequest >= 0)
+                               height = (float)view.HeightRequest;
+                       else
+                       {
+                               var request = view.Measure(tableView.Bounds.Width, double.PositiveInfinity, MeasureFlags.None);
+
+                               if(request.Request.Height > defaultHeight)
+                                       height = (float)request.Request.Height;
+                               else
+                                       height = defaultHeight;
+                       }
+
+                       if (height == -1)
+                               height = defaultHeight;
+
+                       return height;
                }
 
                public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
@@ -77,6 +111,7 @@ namespace Xamarin.Forms.Platform.iOS
                                cell.BindingContext = context;
                        }
 
+                       _views[context] = cell.View;
                        return cell;
                }