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.Theme;
|
||||
using Pixiview.Utils;
|
||||
using Xamarin.Essentials;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Pixiview.Illust
|
||||
@ -613,12 +614,13 @@ namespace Pixiview.Illust
|
||||
if (now == null)
|
||||
{
|
||||
now = collection;
|
||||
IllustCollection = now;
|
||||
}
|
||||
else
|
||||
{
|
||||
now = new IllustCollection(now.Concat(collection));
|
||||
//now = new IllustCollection(now.Concat(collection));
|
||||
now.AddRange(collection);
|
||||
}
|
||||
IllustCollection = now;
|
||||
return now;
|
||||
}
|
||||
|
||||
@ -652,7 +654,7 @@ namespace Pixiview.Illust
|
||||
Down
|
||||
}
|
||||
|
||||
public class IllustCollection : List<IllustItem>
|
||||
public class IllustCollection : List<IllustItem>, IIllustCollectionChanged
|
||||
{
|
||||
private static IllustCollection empty;
|
||||
|
||||
@ -668,6 +670,8 @@ namespace Pixiview.Illust
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<CollectionChangedEventArgs> CollectionChanged;
|
||||
|
||||
public IllustCollection() : base()
|
||||
{
|
||||
running = true;
|
||||
@ -677,8 +681,28 @@ namespace Pixiview.Illust
|
||||
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 volatile bool running;
|
||||
|
||||
public bool Running
|
||||
{
|
||||
get => running;
|
||||
|
@ -307,10 +307,7 @@ namespace Pixiview.Illust
|
||||
|
||||
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()
|
||||
|
@ -72,10 +72,7 @@ namespace Pixiview.Illust
|
||||
|
||||
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()
|
||||
|
@ -82,10 +82,7 @@ namespace Pixiview.Illust
|
||||
|
||||
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()
|
||||
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Xamarin.Forms;
|
||||
|
||||
@ -45,15 +45,27 @@ namespace Pixiview.UI
|
||||
|
||||
public double ColumnWidth { get; private set; }
|
||||
|
||||
private bool freezed;
|
||||
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)
|
||||
{
|
||||
if (freezed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var column = Column;
|
||||
if (column <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var source = ItemsSource;
|
||||
if (source == null || source.Count <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
App.DebugPrint($"layout children: ({x}, {y}, {width}, {height})");
|
||||
var columnSpacing = ColumnSpacing;
|
||||
var rowSpacing = RowSpacing;
|
||||
|
||||
@ -73,15 +85,31 @@ namespace Pixiview.UI
|
||||
col = i;
|
||||
}
|
||||
}
|
||||
item.Layout(new Rectangle(
|
||||
|
||||
var rect = new Rectangle(
|
||||
col * (columnWidth + columnSpacing),
|
||||
columnHeights[col],
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
private double lastWidth = -1;
|
||||
private SizeRequest lastSizeRequest;
|
||||
|
||||
protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint)
|
||||
{
|
||||
var column = Column;
|
||||
@ -89,6 +117,11 @@ namespace Pixiview.UI
|
||||
{
|
||||
return base.OnMeasure(widthConstraint, heightConstraint);
|
||||
}
|
||||
if (lastWidth == widthConstraint)
|
||||
{
|
||||
return lastSizeRequest;
|
||||
}
|
||||
lastWidth = widthConstraint;
|
||||
var columnSpacing = ColumnSpacing;
|
||||
var rowSpacing = RowSpacing;
|
||||
|
||||
@ -112,9 +145,13 @@ namespace Pixiview.UI
|
||||
}
|
||||
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(
|
||||
@ -136,18 +173,21 @@ namespace Pixiview.UI
|
||||
private static void OnItemsSourcePropertyChanged(BindableObject obj, object oldValue, object newValue)
|
||||
{
|
||||
var flowLayout = (FlowLayout)obj;
|
||||
if (oldValue is INotifyCollectionChanged oldNotify)
|
||||
if (oldValue is IIllustCollectionChanged oldNotify)
|
||||
{
|
||||
oldNotify.CollectionChanged -= flowLayout.OnCollectionChanged;
|
||||
}
|
||||
flowLayout.lastWidth = -1;
|
||||
if (newValue == null)
|
||||
{
|
||||
flowLayout.cachedLayout.Clear();
|
||||
flowLayout.Children.Clear();
|
||||
//flowLayout.UpdateChildrenLayout();
|
||||
//flowLayout.InvalidateLayout();
|
||||
flowLayout.InvalidateLayout();
|
||||
}
|
||||
else if (newValue is IList newList)
|
||||
{
|
||||
flowLayout.freezed = true;
|
||||
flowLayout.cachedLayout.Clear();
|
||||
flowLayout.Children.Clear();
|
||||
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;
|
||||
}
|
||||
flowLayout.freezed = false;
|
||||
|
||||
flowLayout.UpdateChildrenLayout();
|
||||
flowLayout.InvalidateLayout();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
private void OnCollectionChanged(object sender, CollectionChangedEventArgs e)
|
||||
{
|
||||
lastWidth = -1;
|
||||
if (e.OldItems != null)
|
||||
{
|
||||
freezed = true;
|
||||
cachedLayout.Clear();
|
||||
var index = e.OldStartingIndex;
|
||||
for (var i = index + e.OldItems.Count - 1; i >= index; i--)
|
||||
{
|
||||
Children.RemoveAt(i);
|
||||
}
|
||||
freezed = false;
|
||||
UpdateChildrenLayout();
|
||||
InvalidateLayout();
|
||||
}
|
||||
@ -187,6 +232,7 @@ namespace Pixiview.UI
|
||||
return;
|
||||
}
|
||||
|
||||
freezed = true;
|
||||
var start = e.NewStartingIndex;
|
||||
for (var i = 0; i < e.NewItems.Count; i++)
|
||||
{
|
||||
@ -197,12 +243,25 @@ namespace Pixiview.UI
|
||||
Children.Insert(start + i, view);
|
||||
}
|
||||
}
|
||||
|
||||
freezed = false;
|
||||
UpdateChildrenLayout();
|
||||
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 double ContentHeight { get; set; }
|
||||
|
Loading…
x
Reference in New Issue
Block a user