optimize: flow measure and layout
This commit is contained in:
parent
623410b47c
commit
7bb3c34fd5
@ -7,6 +7,7 @@ using Pixiview.Resources;
|
|||||||
using Pixiview.UI;
|
using Pixiview.UI;
|
||||||
using Pixiview.UI.Theme;
|
using Pixiview.UI.Theme;
|
||||||
using Pixiview.Utils;
|
using Pixiview.Utils;
|
||||||
|
using Xamarin.Essentials;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
|
|
||||||
namespace Pixiview.Illust
|
namespace Pixiview.Illust
|
||||||
@ -613,12 +614,13 @@ namespace Pixiview.Illust
|
|||||||
if (now == null)
|
if (now == null)
|
||||||
{
|
{
|
||||||
now = collection;
|
now = collection;
|
||||||
|
IllustCollection = now;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
now = new IllustCollection(now.Concat(collection));
|
//now = new IllustCollection(now.Concat(collection));
|
||||||
|
now.AddRange(collection);
|
||||||
}
|
}
|
||||||
IllustCollection = now;
|
|
||||||
return now;
|
return now;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -652,7 +654,7 @@ namespace Pixiview.Illust
|
|||||||
Down
|
Down
|
||||||
}
|
}
|
||||||
|
|
||||||
public class IllustCollection : List<IllustItem>
|
public class IllustCollection : List<IllustItem>, IIllustCollectionChanged
|
||||||
{
|
{
|
||||||
private static IllustCollection empty;
|
private static IllustCollection empty;
|
||||||
|
|
||||||
@ -668,6 +670,8 @@ namespace Pixiview.Illust
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public event EventHandler<CollectionChangedEventArgs> CollectionChanged;
|
||||||
|
|
||||||
public IllustCollection() : base()
|
public IllustCollection() : base()
|
||||||
{
|
{
|
||||||
running = true;
|
running = true;
|
||||||
@ -677,8 +681,28 @@ namespace Pixiview.Illust
|
|||||||
running = true;
|
running = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AddRange(List<IllustItem> items)
|
||||||
|
{
|
||||||
|
var e = new CollectionChangedEventArgs
|
||||||
|
{
|
||||||
|
NewStartingIndex = Count,
|
||||||
|
NewItems = items
|
||||||
|
};
|
||||||
|
base.AddRange(items);
|
||||||
|
if (MainThread.IsMainThread)
|
||||||
|
{
|
||||||
|
CollectionChanged?.Invoke(this, e);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MainThread.BeginInvokeOnMainThread(() =>
|
||||||
|
CollectionChanged?.Invoke(this, e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private readonly object sync = new object();
|
private readonly object sync = new object();
|
||||||
private volatile bool running;
|
private volatile bool running;
|
||||||
|
|
||||||
public bool Running
|
public bool Running
|
||||||
{
|
{
|
||||||
get => running;
|
get => running;
|
||||||
|
@ -307,10 +307,7 @@ namespace Pixiview.Illust
|
|||||||
|
|
||||||
private void FlowLayout_MaxHeightChanged(object sender, HeightEventArgs e)
|
private void FlowLayout_MaxHeightChanged(object sender, HeightEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.ContentHeight > 0)
|
SetOffset(e.ContentHeight - scrollView.Bounds.Height - SCROLL_OFFSET);
|
||||||
{
|
|
||||||
SetOffset(e.ContentHeight - scrollView.Bounds.Height - SCROLL_OFFSET);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool CheckRefresh()
|
protected override bool CheckRefresh()
|
||||||
|
@ -72,10 +72,7 @@ namespace Pixiview.Illust
|
|||||||
|
|
||||||
private void FlowLayout_MaxHeightChanged(object sender, HeightEventArgs e)
|
private void FlowLayout_MaxHeightChanged(object sender, HeightEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.ContentHeight > 0)
|
SetOffset(e.ContentHeight - scrollView.Bounds.Height - SCROLL_OFFSET);
|
||||||
{
|
|
||||||
SetOffset(e.ContentHeight - scrollView.Bounds.Height - SCROLL_OFFSET);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool CheckRefresh()
|
protected override bool CheckRefresh()
|
||||||
|
@ -82,10 +82,7 @@ namespace Pixiview.Illust
|
|||||||
|
|
||||||
private void FlowLayout_MaxHeightChanged(object sender, HeightEventArgs e)
|
private void FlowLayout_MaxHeightChanged(object sender, HeightEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.ContentHeight > 0)
|
SetOffset(e.ContentHeight - scrollView.Bounds.Height - SCROLL_OFFSET);
|
||||||
{
|
|
||||||
SetOffset(e.ContentHeight - scrollView.Bounds.Height - SCROLL_OFFSET);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool CheckRefresh()
|
protected override bool CheckRefresh()
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
|
|
||||||
@ -45,15 +45,27 @@ namespace Pixiview.UI
|
|||||||
|
|
||||||
public double ColumnWidth { get; private set; }
|
public double ColumnWidth { get; private set; }
|
||||||
|
|
||||||
|
private bool freezed;
|
||||||
private double maximumHeight;
|
private double maximumHeight;
|
||||||
|
private readonly Dictionary<View, Rectangle> cachedLayout = new Dictionary<View, Rectangle>();
|
||||||
|
|
||||||
protected override void LayoutChildren(double x, double y, double width, double height)
|
protected override void LayoutChildren(double x, double y, double width, double height)
|
||||||
{
|
{
|
||||||
|
if (freezed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
var column = Column;
|
var column = Column;
|
||||||
if (column <= 0)
|
if (column <= 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
var source = ItemsSource;
|
||||||
|
if (source == null || source.Count <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
App.DebugPrint($"layout children: ({x}, {y}, {width}, {height})");
|
||||||
var columnSpacing = ColumnSpacing;
|
var columnSpacing = ColumnSpacing;
|
||||||
var rowSpacing = RowSpacing;
|
var rowSpacing = RowSpacing;
|
||||||
|
|
||||||
@ -73,15 +85,31 @@ namespace Pixiview.UI
|
|||||||
col = i;
|
col = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
item.Layout(new Rectangle(
|
|
||||||
|
var rect = new Rectangle(
|
||||||
col * (columnWidth + columnSpacing),
|
col * (columnWidth + columnSpacing),
|
||||||
columnHeights[col],
|
columnHeights[col],
|
||||||
columnWidth,
|
columnWidth,
|
||||||
measured.Request.Height));
|
measured.Request.Height);
|
||||||
|
if (cachedLayout.TryGetValue(item, out var v))
|
||||||
|
{
|
||||||
|
if (v != rect)
|
||||||
|
{
|
||||||
|
item.Layout(rect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cachedLayout.Add(item, rect);
|
||||||
|
item.Layout(rect);
|
||||||
|
}
|
||||||
columnHeights[col] += measured.Request.Height + rowSpacing;
|
columnHeights[col] += measured.Request.Height + rowSpacing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private double lastWidth = -1;
|
||||||
|
private SizeRequest lastSizeRequest;
|
||||||
|
|
||||||
protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint)
|
protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint)
|
||||||
{
|
{
|
||||||
var column = Column;
|
var column = Column;
|
||||||
@ -89,6 +117,11 @@ namespace Pixiview.UI
|
|||||||
{
|
{
|
||||||
return base.OnMeasure(widthConstraint, heightConstraint);
|
return base.OnMeasure(widthConstraint, heightConstraint);
|
||||||
}
|
}
|
||||||
|
if (lastWidth == widthConstraint)
|
||||||
|
{
|
||||||
|
return lastSizeRequest;
|
||||||
|
}
|
||||||
|
lastWidth = widthConstraint;
|
||||||
var columnSpacing = ColumnSpacing;
|
var columnSpacing = ColumnSpacing;
|
||||||
var rowSpacing = RowSpacing;
|
var rowSpacing = RowSpacing;
|
||||||
|
|
||||||
@ -112,9 +145,13 @@ namespace Pixiview.UI
|
|||||||
}
|
}
|
||||||
maximumHeight = columnHeights.Max();
|
maximumHeight = columnHeights.Max();
|
||||||
|
|
||||||
MaxHeightChanged?.Invoke(this, new HeightEventArgs { ContentHeight = maximumHeight });
|
if (maximumHeight > 0)
|
||||||
|
{
|
||||||
|
MaxHeightChanged?.Invoke(this, new HeightEventArgs { ContentHeight = maximumHeight });
|
||||||
|
}
|
||||||
|
|
||||||
return new SizeRequest(new Size(widthConstraint, maximumHeight));
|
lastSizeRequest = new SizeRequest(new Size(widthConstraint, maximumHeight));
|
||||||
|
return lastSizeRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static readonly BindableProperty ItemTemplateProperty = BindableProperty.Create(
|
public static readonly BindableProperty ItemTemplateProperty = BindableProperty.Create(
|
||||||
@ -136,18 +173,21 @@ namespace Pixiview.UI
|
|||||||
private static void OnItemsSourcePropertyChanged(BindableObject obj, object oldValue, object newValue)
|
private static void OnItemsSourcePropertyChanged(BindableObject obj, object oldValue, object newValue)
|
||||||
{
|
{
|
||||||
var flowLayout = (FlowLayout)obj;
|
var flowLayout = (FlowLayout)obj;
|
||||||
if (oldValue is INotifyCollectionChanged oldNotify)
|
if (oldValue is IIllustCollectionChanged oldNotify)
|
||||||
{
|
{
|
||||||
oldNotify.CollectionChanged -= flowLayout.OnCollectionChanged;
|
oldNotify.CollectionChanged -= flowLayout.OnCollectionChanged;
|
||||||
}
|
}
|
||||||
|
flowLayout.lastWidth = -1;
|
||||||
if (newValue == null)
|
if (newValue == null)
|
||||||
{
|
{
|
||||||
|
flowLayout.cachedLayout.Clear();
|
||||||
flowLayout.Children.Clear();
|
flowLayout.Children.Clear();
|
||||||
//flowLayout.UpdateChildrenLayout();
|
flowLayout.InvalidateLayout();
|
||||||
//flowLayout.InvalidateLayout();
|
|
||||||
}
|
}
|
||||||
else if (newValue is IList newList)
|
else if (newValue is IList newList)
|
||||||
{
|
{
|
||||||
|
flowLayout.freezed = true;
|
||||||
|
flowLayout.cachedLayout.Clear();
|
||||||
flowLayout.Children.Clear();
|
flowLayout.Children.Clear();
|
||||||
for (var i = 0; i < newList.Count; i++)
|
for (var i = 0; i < newList.Count; i++)
|
||||||
{
|
{
|
||||||
@ -159,25 +199,30 @@ namespace Pixiview.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newValue is INotifyCollectionChanged newNotify)
|
if (newValue is IIllustCollectionChanged newNotify)
|
||||||
{
|
{
|
||||||
newNotify.CollectionChanged += flowLayout.OnCollectionChanged;
|
newNotify.CollectionChanged += flowLayout.OnCollectionChanged;
|
||||||
}
|
}
|
||||||
|
flowLayout.freezed = false;
|
||||||
|
|
||||||
flowLayout.UpdateChildrenLayout();
|
flowLayout.UpdateChildrenLayout();
|
||||||
flowLayout.InvalidateLayout();
|
flowLayout.InvalidateLayout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
private void OnCollectionChanged(object sender, CollectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
|
lastWidth = -1;
|
||||||
if (e.OldItems != null)
|
if (e.OldItems != null)
|
||||||
{
|
{
|
||||||
|
freezed = true;
|
||||||
|
cachedLayout.Clear();
|
||||||
var index = e.OldStartingIndex;
|
var index = e.OldStartingIndex;
|
||||||
for (var i = index + e.OldItems.Count - 1; i >= index; i--)
|
for (var i = index + e.OldItems.Count - 1; i >= index; i--)
|
||||||
{
|
{
|
||||||
Children.RemoveAt(i);
|
Children.RemoveAt(i);
|
||||||
}
|
}
|
||||||
|
freezed = false;
|
||||||
UpdateChildrenLayout();
|
UpdateChildrenLayout();
|
||||||
InvalidateLayout();
|
InvalidateLayout();
|
||||||
}
|
}
|
||||||
@ -187,6 +232,7 @@ namespace Pixiview.UI
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
freezed = true;
|
||||||
var start = e.NewStartingIndex;
|
var start = e.NewStartingIndex;
|
||||||
for (var i = 0; i < e.NewItems.Count; i++)
|
for (var i = 0; i < e.NewItems.Count; i++)
|
||||||
{
|
{
|
||||||
@ -197,12 +243,25 @@ namespace Pixiview.UI
|
|||||||
Children.Insert(start + i, view);
|
Children.Insert(start + i, view);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
freezed = false;
|
||||||
UpdateChildrenLayout();
|
UpdateChildrenLayout();
|
||||||
InvalidateLayout();
|
InvalidateLayout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface IIllustCollectionChanged
|
||||||
|
{
|
||||||
|
event EventHandler<CollectionChangedEventArgs> CollectionChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CollectionChangedEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
public int OldStartingIndex { get; set; }
|
||||||
|
public IList OldItems { get; set; }
|
||||||
|
public int NewStartingIndex { get; set; }
|
||||||
|
public IList NewItems { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public class HeightEventArgs : EventArgs
|
public class HeightEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public double ContentHeight { get; set; }
|
public double ContentHeight { get; set; }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user