diff options
author | Samantha Houts <samhouts@users.noreply.github.com> | 2017-06-23 03:37:00 -0700 |
---|---|---|
committer | Rui Marinho <me@ruimarinho.net> | 2017-06-23 11:37:00 +0100 |
commit | a9f6acb87013e9da87340a41fe4571216144cf8c (patch) | |
tree | 66dc28a370b9528777ca6f2ad213d8a948e11aee /Xamarin.Forms.Platform.iOS | |
parent | 80b72ceda3ed017f62af45c5591a11c29f3fdd3d (diff) | |
download | xamarin-forms-a9f6acb87013e9da87340a41fe4571216144cf8c.tar.gz xamarin-forms-a9f6acb87013e9da87340a41fe4571216144cf8c.tar.bz2 xamarin-forms-a9f6acb87013e9da87340a41fe4571216144cf8c.zip |
[iOS] ListView with UnevenRows and Cell Heights will no longer be slow to load (#994)
* Add repro for 56896
* [iOS] Cached defined row heights for estimation
* [iOS] Null check source
Diffstat (limited to 'Xamarin.Forms.Platform.iOS')
-rw-r--r-- | Xamarin.Forms.Platform.iOS/Renderers/ListViewRenderer.cs | 59 |
1 files changed, 51 insertions, 8 deletions
diff --git a/Xamarin.Forms.Platform.iOS/Renderers/ListViewRenderer.cs b/Xamarin.Forms.Platform.iOS/Renderers/ListViewRenderer.cs index 84c0daa1..e52f6cc8 100644 --- a/Xamarin.Forms.Platform.iOS/Renderers/ListViewRenderer.cs +++ b/Xamarin.Forms.Platform.iOS/Renderers/ListViewRenderer.cs @@ -1,9 +1,11 @@ using System; using System.Collections; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using System.Linq; +using System.Threading.Tasks; using Foundation; using UIKit; using Xamarin.Forms.Internals; @@ -364,14 +366,16 @@ namespace Xamarin.Forms.Platform.iOS void UpdateEstimatedRowHeight() { - if (_estimatedRowHeight) - return; - var rowHeight = Element.RowHeight; if (Element.HasUnevenRows && rowHeight == -1) { var source = _dataSource as UnevenListViewDataSource; - if (_shouldEstimateRowHeight) + + // 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 (_shouldEstimateRowHeight && !_estimatedRowHeight) { if (source != null) { @@ -386,7 +390,7 @@ namespace Xamarin.Forms.Platform.iOS } } } - else + else if (!_estimatedRowHeight) { Control.EstimatedRowHeight = 0; _estimatedRowHeight = true; @@ -623,6 +627,9 @@ namespace Xamarin.Forms.Platform.iOS { IVisualElementRenderer _prototype; bool _disposed; + bool _useEstimatedRowHeight; + + ConcurrentDictionary<NSIndexPath, nfloat> _rowHeights = new ConcurrentDictionary<NSIndexPath, nfloat>(); public UnevenListViewDataSource(ListView list, FormsUITableViewController uiTableViewController) : base(list, uiTableViewController) { @@ -632,6 +639,24 @@ 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) @@ -656,21 +681,36 @@ namespace Xamarin.Forms.Platform.iOS if (firstCell.Height > 0 && !List.IsGroupingEnabled) { // Seems like we've got cells which already specify their height; since the heights are known, - // we don't need to use estimatedRowHeight at all; zero will disable it and use the known heights + // we don't need to use estimatedRowHeight at all; zero will disable it and use the known heights. + // However, not setting the EstimatedRowHeight will drastically degrade performance with large lists. + // In this case, we will cache the specified cell heights asynchronously, which will be returned one time on + // table load by EstimatedHeight. + return 0; } return CalculateHeightForCell(table, firstCell); } + public override nfloat EstimatedHeight(UITableView tableView, NSIndexPath indexPath) + { + if (_useEstimatedRowHeight) + return tableView.EstimatedRowHeight; + + // 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; + } + public override nfloat GetHeightForRow(UITableView tableView, NSIndexPath indexPath) { var cell = GetCellForPath(indexPath); if (List.RowHeight == -1 && cell.Height == -1 && cell is ViewCell) - { return UITableView.AutomaticDimension; - } var renderHeight = cell.RenderHeight; return renderHeight > 0 ? (nfloat)renderHeight : DefaultRowHeight; @@ -709,6 +749,9 @@ 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; return (nfloat)req.Request.Height; } |