Skip to content

Commit

Permalink
feat: ListView - allow WASM/MacOS implementation to be tested on iOS/…
Browse files Browse the repository at this point in the history
…Android

Allow the managed list implementation to run on platforms where it can be debugged with Visual Studio (for Windows), to be able to add new features more easily.
  • Loading branch information
davidjohnoliver committed Mar 18, 2020
1 parent 3c5e339 commit c22a951
Show file tree
Hide file tree
Showing 8 changed files with 286 additions and 24 deletions.
32 changes: 32 additions & 0 deletions src/Uno.UI/Extensions/ViewExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#if __IOS__
using UIKit;
using _View = UIKit.UIView;
#elif __MACOS__
using AppKit;
using _View = AppKit.NSView;
#elif __ANDROID__
using _View = Android.Views.ViewGroup;
#else
using _View = Windows.UI.Xaml.UIElement;
#endif

using System.Collections.Generic;

namespace Uno.UI.Extensions
{
public static partial class ViewExtensions
{
/// <summary>
/// Get all ancestor views of <paramref name="view"/>, in order from its immediate parent to the root of the visual tree.
/// </summary>
public static IEnumerable<_View> GetVisualAncestry(this _View view)
{
var ancestor = view.GetVisualTreeParent();
while (ancestor != null)
{
yield return ancestor;
ancestor = ancestor.GetVisualTreeParent();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
#if __WASM__ || __MACOS__
using System;
using System;
using System.Collections.Generic;
using System.Text;
using Uno.UI.DataBinding;
using Windows.Foundation;

#if __IOS__ || __ANDROID__
namespace Uno.UI.Controls
{
public partial class ManagedItemsStackPanel
#else
namespace Windows.UI.Xaml.Controls
{
public partial class ItemsStackPanel
#endif
{
protected override Size MeasureOverride(Size availableSize) => _layout.MeasureOverride(availableSize);

protected override Size ArrangeOverride(Size finalSize) => _layout.ArrangeOverride(finalSize);
}
}
#endif
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
#if __WASM__ || __MACOS__
using System;
using System;
using System.Collections.Generic;
using System.Text;
using Uno.UI;
using Windows.UI.Xaml.Controls.Primitives;

namespace Windows.UI.Xaml.Controls
{
#if __ANDROID__ || __IOS__
public partial class ManagedItemsStackPanelLayout : ManagedVirtualizingPanelLayout
#else
partial class ItemsStackPanelLayout
#endif
{
#if __ANDROID__ || __IOS__
public override Orientation ScrollOrientation => Orientation;
#endif

protected override Line CreateLine(GeneratorDirection fillDirection, double extentOffset, double availableBreadth, IndexPath nextVisibleItem)
{
var item = GetFlatItemIndex(nextVisibleItem);
Expand All @@ -22,4 +29,3 @@ protected override Line CreateLine(GeneratorDirection fillDirection, double exte
protected override int GetItemsPerLine() => 1;
}
}
#endif
104 changes: 104 additions & 0 deletions src/Uno.UI/UI/Xaml/Controls/ItemsStackPanel/ManagedItemsStackPanel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#if __ANDROID__ || __IOS__
using System;
using System.Collections.Generic;
using System.Text;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace Uno.UI.Controls
{
/// <summary>
/// An ItemsStackPanel implementation which doesn't rely on high-level native list controls.
/// </summary>
/// <remarks>For now this panel mainly exists for testing purposes, to be able to debug the WASM/MacOS implementation on Android or iOS.</remarks>
public partial class ManagedItemsStackPanel : Panel
{
ManagedVirtualizingPanelLayout _layout;

internal bool ShouldInterceptInvalidate { get; set; }

public ManagedItemsStackPanel()
{
CreateLayoutIfNeeded();
_layout.Initialize(this);
}

private ManagedVirtualizingPanelLayout GetLayouter()
{
CreateLayoutIfNeeded();
return _layout;
}

private void CreateLayoutIfNeeded()
{
if (_layout == null)
{
_layout = new ManagedItemsStackPanelLayout();
_layout.BindToEquivalentProperty(this, nameof(Orientation));
// _layout.BindToEquivalentProperty(this, nameof(AreStickyGroupHeadersEnabled));
// _layout.BindToEquivalentProperty(this, nameof(GroupHeaderPlacement));
// _layout.BindToEquivalentProperty(this, nameof(GroupPadding));
//#if !XAMARIN_IOS
// _layout.BindToEquivalentProperty(this, nameof(CacheLength));
//#endif
}
}

#region Orientation DependencyProperty

public Orientation Orientation
{
get { return (Orientation)this.GetValue(OrientationProperty); }
set { this.SetValue(OrientationProperty, value); }
}

public static readonly DependencyProperty OrientationProperty =
DependencyProperty.Register(
"Orientation",
typeof(Orientation),
typeof(ManagedItemsStackPanel),
new FrameworkPropertyMetadata(
defaultValue: (Orientation)Orientation.Vertical,
options: FrameworkPropertyMetadataOptions.None,
propertyChangedCallback: (s, e) => ((ManagedItemsStackPanel)s)?.OnOrientationChanged((Orientation)e.OldValue, (Orientation)e.NewValue)
)
);

protected virtual void OnOrientationChanged(Orientation oldOrientation, Orientation newOrientation)
{
OnOrientationChangedPartial(oldOrientation, newOrientation);
OnOrientationChangedPartialNative(oldOrientation, newOrientation);
}

partial void OnOrientationChangedPartial(Orientation oldOrientation, Orientation newOrientation);
partial void OnOrientationChangedPartialNative(Orientation oldOrientation, Orientation newOrientation);

#endregion
#if __IOS__
public override void SetSuperviewNeedsLayout()
{
if (ShouldInterceptInvalidate)
{
return;
}

base.SetSuperviewNeedsLayout();
}
#elif __ANDROID__
protected override bool NativeRequestLayout()
{
if (ShouldInterceptInvalidate)
{
ForceLayout();
return false;
}
else
{
return base.NativeRequestLayout();
}
}
#endif
}
}

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#if __ANDROID__ || __IOS__
using System;
using System.Collections.Generic;
using System.Text;
using Uno.UI;
using Windows.UI.Xaml.Controls.Primitives;

namespace Windows.UI.Xaml.Controls
{
abstract partial class ManagedVirtualizingPanelLayout : DependencyObject
{
// Copied from VirtualizingPanelLayout.cs

/// <summary>
/// The direction of scroll.
/// </summary>
public abstract Orientation ScrollOrientation { get; }

/// <summary>
/// Whether the content should be stretched in breadth (ie perpendicular to the direction of scroll).
/// </summary>
public bool ShouldBreadthStretch
{
get
{
if (XamlParent == null)
{
return true;
}

if (IsInsidePopup)
{
return false;
}

if (ScrollOrientation == Orientation.Vertical)
{
return XamlParent.HorizontalAlignment == HorizontalAlignment.Stretch;
}
else
{
return XamlParent.VerticalAlignment == VerticalAlignment.Stretch;
}
}
}
/// <summary>
/// Determines if the owner Panel is inside a popup. Used to determine
/// if the computation of the breadth should be using the parent's stretch
/// modes.
/// Related: https://github.com/unoplatform/uno/issues/135
/// </summary>
private bool IsInsidePopup { get; set; }

/// <summary>
/// Get the index of the next item that has not yet been materialized in the nominated fill direction. Returns null if there are no more available items in the source.
/// </summary>
protected IndexPath? GetNextUnmaterializedItem(GeneratorDirection fillDirection, IndexPath? currentMaterializedItem)
{
return XamlParent?.GetNextItemIndex(currentMaterializedItem, fillDirection == GeneratorDirection.Forward ? 1 : -1);
}

public Orientation Orientation
{
get { return (Orientation)GetValue(OrientationProperty); }
set { SetValue(OrientationProperty, value); }
}

public static readonly DependencyProperty OrientationProperty =
DependencyProperty.Register("Orientation", typeof(Orientation), typeof(ManagedVirtualizingPanelLayout), new PropertyMetadata(Orientation.Vertical, (o, e) => ((ManagedVirtualizingPanelLayout)o).OnOrientationChanged((Orientation)e.NewValue)));

#region CacheLength DependencyProperty

public double CacheLength
{
get { return (double)this.GetValue(CacheLengthProperty); }
set { this.SetValue(CacheLengthProperty, value); }
}

public static readonly DependencyProperty CacheLengthProperty =
DependencyProperty.Register(
"CacheLength",
typeof(double),
typeof(ManagedVirtualizingPanelLayout),
new FrameworkPropertyMetadata(
defaultValue: (double)4.0,
options: FrameworkPropertyMetadataOptions.None,
propertyChangedCallback: (s, e) => ((ManagedVirtualizingPanelLayout)s)?.OnCacheLengthChanged((double)e.OldValue, (double)e.NewValue)
)
);

protected virtual void OnCacheLengthChanged(double oldCacheLength, double newCacheLength)
{
OnCacheLengthChangedPartial(oldCacheLength, newCacheLength);
OnCacheLengthChangedPartialNative(oldCacheLength, newCacheLength);
}

partial void OnCacheLengthChangedPartial(double oldCacheLength, double newCacheLength);
partial void OnCacheLengthChangedPartialNative(double oldCacheLength, double newCacheLength);

#endregion
}
}
#endif
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
#if __WASM__ || __MACOS__
using System;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
using Microsoft.Extensions.Logging;
using Uno.Extensions;
#if __ANDROID__ || __IOS__
using _VirtualizingPanelLayout = Windows.UI.Xaml.Controls.ManagedVirtualizingPanelLayout;
#else
using _VirtualizingPanelLayout = Windows.UI.Xaml.Controls.VirtualizingPanelLayout;
#endif

namespace Windows.UI.Xaml.Controls
{
Expand All @@ -15,7 +19,7 @@ internal class VirtualizingPanelGenerator
{
private const int CacheLimit = 10;
private const int NoTemplateItemId = -1;
private readonly VirtualizingPanelLayout _owner;
private readonly _VirtualizingPanelLayout _owner;
private readonly Dictionary<int, Stack<FrameworkElement>> _itemContainerCache = new Dictionary<int, Stack<FrameworkElement>>();
/// <summary>
/// Caching the id is more efficient, and also important in the case of the ItemsSource changing, when the (former) item may no longer be in the new collection.
Expand All @@ -29,7 +33,7 @@ internal class VirtualizingPanelGenerator

private ItemsControl ItemsControl => _owner.ItemsControl;

public VirtualizingPanelGenerator(VirtualizingPanelLayout owner)
public VirtualizingPanelGenerator(_VirtualizingPanelLayout owner)
{
_owner = owner;
}
Expand Down Expand Up @@ -196,4 +200,3 @@ internal void ClearIdCache()
}
}
}
#endif
Loading

0 comments on commit c22a951

Please sign in to comment.