diff options
Diffstat (limited to 'Xamarin.Forms.Platform.iOS/Renderers/ListViewRenderer.cs')
-rw-r--r-- | Xamarin.Forms.Platform.iOS/Renderers/ListViewRenderer.cs | 151 |
1 files changed, 86 insertions, 65 deletions
diff --git a/Xamarin.Forms.Platform.iOS/Renderers/ListViewRenderer.cs b/Xamarin.Forms.Platform.iOS/Renderers/ListViewRenderer.cs index 7fd68cc0..f6cccd54 100644 --- a/Xamarin.Forms.Platform.iOS/Renderers/ListViewRenderer.cs +++ b/Xamarin.Forms.Platform.iOS/Renderers/ListViewRenderer.cs @@ -25,7 +25,6 @@ namespace Xamarin.Forms.Platform.iOS KeyboardInsetTracker _insetTracker; RectangleF _previousFrame; ScrollToRequestedEventArgs _requestedScroll; - bool _shouldEstimateRowHeight = true; FormsUITableViewController _tableViewController; ListView ListView => Element; @@ -212,7 +211,6 @@ namespace Xamarin.Forms.Platform.iOS Control.SetContentOffset(offset, true); }); } - _shouldEstimateRowHeight = true; var listView = e.NewElement; @@ -366,35 +364,36 @@ namespace Xamarin.Forms.Platform.iOS void UpdateEstimatedRowHeight() { - var rowHeight = Element.RowHeight; - if (Element.HasUnevenRows && rowHeight == -1) - { - var source = _dataSource as UnevenListViewDataSource; - - // We want to make sure we reset the cached defined row heights whenever this is called. - // Failing to do this will regress Bugzilla 43313 (strange animation when adding rows with uneven heights) - source?.CacheDefinedRowHeights(); + if (_estimatedRowHeight) + return; - if (_shouldEstimateRowHeight && !_estimatedRowHeight) - { - if (source != null) - { - Control.EstimatedRowHeight = source.GetEstimatedRowHeight(Control); - _estimatedRowHeight = true; - } - else - { - //We need to set a default estimated row height, because re-setting it later(when we have items on the TIL) - //will cause the UITableView to reload, and throw an Exception - Control.EstimatedRowHeight = DefaultRowHeight; - } - } - } - else if (!_estimatedRowHeight) + // if even rows OR uneven rows but user specified a row height anyway... + if (!Element.HasUnevenRows || Element.RowHeight != -1) { Control.EstimatedRowHeight = 0; _estimatedRowHeight = true; + return; } + + var source = _dataSource as UnevenListViewDataSource; + + // We want to make sure we reset the cached defined row heights whenever this is called. + // Failing to do this will regress Bugzilla 43313 + // (strange animation when adding rows with uneven heights) + //source?.CacheDefinedRowHeights(); + + if (source == null) + { + // We need to set a default estimated row height, + // because re-setting it later(when we have items on the TIL) + // will cause the UITableView to reload, and throw an Exception + Control.EstimatedRowHeight = DefaultRowHeight; + return; + } + + Control.EstimatedRowHeight = source.GetEstimatedRowHeight(Control); + _estimatedRowHeight = true; + return; } void UpdateFooter() @@ -627,9 +626,7 @@ namespace Xamarin.Forms.Platform.iOS { IVisualElementRenderer _prototype; bool _disposed; - bool _useEstimatedRowHeight; - - ConcurrentDictionary<NSIndexPath, nfloat> _rowHeights = new ConcurrentDictionary<NSIndexPath, nfloat>(); + Dictionary<object, Cell> _prototypicalCellByTypeOrDataTemplate = new Dictionary<object, Cell>(); public UnevenListViewDataSource(ListView list, FormsUITableViewController uiTableViewController) : base(list, uiTableViewController) { @@ -639,24 +636,6 @@ namespace Xamarin.Forms.Platform.iOS { } - internal void CacheDefinedRowHeights() - { - Task.Run(() => - { - var templatedItems = TemplatedItemsView.TemplatedItems; - - foreach (var cell in templatedItems) - { - if (_disposed) - return; - - double? cellRenderHeight = cell?.RenderHeight; - if (cellRenderHeight > 0) - _rowHeights[cell.GetIndexPath()] = (nfloat)cellRenderHeight; - } - }); - } - internal nfloat GetEstimatedRowHeight(UITableView table) { if (List.RowHeight != -1) @@ -692,22 +671,42 @@ namespace Xamarin.Forms.Platform.iOS return CalculateHeightForCell(table, firstCell); } - public override nfloat EstimatedHeight(UITableView tableView, NSIndexPath indexPath) + internal override void InvalidatePrototypicalCellCache() + { + _prototypicalCellByTypeOrDataTemplate.Clear(); + } + + internal Cell GetPrototypicalCell(NSIndexPath indexPath) { - if (_useEstimatedRowHeight) - return tableView.EstimatedRowHeight; + var itemTypeOrDataTemplate = default(object); + + var cachingStrategy = List.CachingStrategy; + if (cachingStrategy == ListViewCachingStrategy.RecycleElement) + itemTypeOrDataTemplate = GetDataTemplateForPath(indexPath); + + else if (cachingStrategy == ListViewCachingStrategy.RecycleElementAndDataTemplate) + itemTypeOrDataTemplate = GetItemTypeForPath(indexPath); + + else // ListViewCachingStrategy.RetainElement + return GetCellForPath(indexPath); - // Note: It is *not* an optimization to first check if the array has any values. - nfloat specifiedRowHeight; - if (_rowHeights.TryGetValue(indexPath, out specifiedRowHeight) && specifiedRowHeight > 0) - return specifiedRowHeight; - return UITableView.AutomaticDimension; + Cell protoCell; + if (!_prototypicalCellByTypeOrDataTemplate.TryGetValue(itemTypeOrDataTemplate, out protoCell)) + { + // cache prototypical cell by item type; Items of the same Type share + // the same DataTemplate (this is enforced by RecycleElementAndDataTemplate) + protoCell = GetCellForPath(indexPath); + _prototypicalCellByTypeOrDataTemplate[itemTypeOrDataTemplate] = protoCell; + } + + var templatedItems = GetTemplatedItemsListForPath(indexPath); + return templatedItems.UpdateContent(protoCell, indexPath.Row); } public override nfloat GetHeightForRow(UITableView tableView, NSIndexPath indexPath) { - var cell = GetCellForPath(indexPath); + var cell = GetPrototypicalCell(indexPath); if (List.RowHeight == -1 && cell.Height == -1 && cell is ViewCell) return UITableView.AutomaticDimension; @@ -745,7 +744,7 @@ namespace Xamarin.Forms.Platform.iOS // Let the EstimatedHeight method know to use this value. // Much more efficient than checking the value each time. - _useEstimatedRowHeight = true; + //_useEstimatedRowHeight = true; return (nfloat)req.Request.Height; } @@ -818,6 +817,10 @@ namespace Xamarin.Forms.Platform.iOS get { return UIColor.Clear; } } + internal virtual void InvalidatePrototypicalCellCache() + { + } + public override void DraggingEnded(UIScrollView scrollView, bool willDecelerate) { _isDragging = false; @@ -840,13 +843,14 @@ namespace Xamarin.Forms.Platform.iOS cell = GetCellForPath(indexPath); nativeCell = CellTableViewCell.GetNativeCell(tableView, cell); } - else if (cachingStrategy == ListViewCachingStrategy.RecycleElement) + else if ((cachingStrategy & ListViewCachingStrategy.RecycleElement) != 0) { var id = TemplateIdForPath(indexPath); nativeCell = tableView.DequeueReusableCell(ContextActionsCell.Key + id); if (nativeCell == null) { cell = GetCellForPath(indexPath); + nativeCell = CellTableViewCell.GetNativeCell(tableView, cell, true, id.ToString()); } else @@ -966,7 +970,7 @@ namespace Xamarin.Forms.Platform.iOS return; Cell formsCell = null; - if (List.CachingStrategy == ListViewCachingStrategy.RecycleElement) + if ((List.CachingStrategy & ListViewCachingStrategy.RecycleElement) != 0) formsCell = (Cell)((INativeElementView)cell).Element; SetCellBackgroundColor(cell, UIColor.Clear); @@ -1035,12 +1039,32 @@ namespace Xamarin.Forms.Platform.iOS _uiTableView.ReloadData(); } - protected Cell GetCellForPath(NSIndexPath indexPath) + protected ITemplatedItemsList<Cell> GetTemplatedItemsListForPath(NSIndexPath indexPath) { var templatedItems = TemplatedItemsView.TemplatedItems; if (List.IsGroupingEnabled) - templatedItems = (TemplatedItemsList<ItemsView<Cell>, Cell>)((IList)templatedItems)[indexPath.Section]; + templatedItems = (ITemplatedItemsList<Cell>)((IList)templatedItems)[indexPath.Section]; + return templatedItems; + } + + protected DataTemplate GetDataTemplateForPath(NSIndexPath indexPath) + { + var templatedList = GetTemplatedItemsListForPath(indexPath); + var item = templatedList.ListProxy[indexPath.Row]; + return templatedList.SelectDataTemplate(item); + } + + protected Type GetItemTypeForPath(NSIndexPath indexPath) + { + var templatedList = GetTemplatedItemsListForPath(indexPath); + var item = templatedList.ListProxy[indexPath.Row]; + return item.GetType(); + } + + protected Cell GetCellForPath(NSIndexPath indexPath) + { + var templatedItems = GetTemplatedItemsListForPath(indexPath); var cell = templatedItems[indexPath.Row]; return cell; } @@ -1086,10 +1110,7 @@ namespace Xamarin.Forms.Platform.iOS if (selector == null) return DefaultItemTemplateId; - var templatedList = TemplatedItemsView.TemplatedItems; - if (List.IsGroupingEnabled) - templatedList = (TemplatedItemsList<ItemsView<Cell>, Cell>)((IList)templatedList)[indexPath.Section]; - + var templatedList = GetTemplatedItemsListForPath(indexPath); var item = templatedList.ListProxy[indexPath.Row]; itemTemplate = selector.SelectTemplate(item, List); |