maui-linux/Xamarin.Forms.Platform.iOS/VisualElementPackager.cs

219 строки
5.0 KiB
C#

using System;
using Xamarin.Forms.Internals;
#if __MOBILE__
namespace Xamarin.Forms.Platform.iOS
#else
namespace Xamarin.Forms.Platform.MacOS
#endif
{
public class VisualElementPackager : IDisposable
{
VisualElement _element;
bool _isDisposed;
IElementController ElementController => _element;
public VisualElementPackager(IVisualElementRenderer renderer) : this(renderer, null)
{
}
VisualElementPackager(IVisualElementRenderer renderer, VisualElement element)
{
if (renderer == null)
throw new ArgumentNullException(nameof(renderer));
Renderer = renderer;
renderer.ElementChanged += OnRendererElementChanged;
SetElement(null, element ?? renderer.Element);
}
protected IVisualElementRenderer Renderer { get; set; }
public void Dispose()
{
Dispose(true);
}
public void Load()
{
for (var i = 0; i < ElementController.LogicalChildren.Count; i++)
{
var child = ElementController.LogicalChildren[i] as VisualElement;
if (child != null)
OnChildAdded(child);
}
}
protected virtual void Dispose(bool disposing)
{
if (_isDisposed)
return;
if (disposing)
{
if (ElementController != null)
{
for (var i = 0; i < ElementController.LogicalChildren.Count; i++)
{
var child = ElementController.LogicalChildren[i] as VisualElement;
if (child == null)
continue;
var childRenderer = Platform.GetRenderer(child);
if (childRenderer == null)
continue;
childRenderer.Dispose();
}
}
SetElement(_element, null);
if (Renderer != null)
{
Renderer.ElementChanged -= OnRendererElementChanged;
Renderer = null;
}
}
_isDisposed = true;
}
protected virtual void OnChildAdded(VisualElement view)
{
if (_isDisposed)
return;
Performance.Start(out string reference);
if (CompressedLayout.GetIsHeadless(view))
{
var packager = new VisualElementPackager(Renderer, view);
view.IsPlatformEnabled = true;
packager.Load();
}
else
{
var viewRenderer = Platform.CreateRenderer(view);
Platform.SetRenderer(view, viewRenderer);
var uiview = Renderer.NativeView;
uiview.AddSubview(viewRenderer.NativeView);
if (Renderer.ViewController != null && viewRenderer.ViewController != null)
Renderer.ViewController.AddChildViewController(viewRenderer.ViewController);
EnsureChildrenOrder();
}
Performance.Stop(reference);
}
protected virtual void OnChildRemoved(VisualElement view)
{
var viewRenderer = Platform.GetRenderer(view);
if (viewRenderer == null || viewRenderer.NativeView == null)
return;
viewRenderer.NativeView.RemoveFromSuperview();
if (Renderer.ViewController != null && viewRenderer.ViewController != null)
viewRenderer.ViewController.RemoveFromParentViewController();
viewRenderer.Dispose();
}
void EnsureChildrenOrder()
{
if (ElementController.LogicalChildren.Count == 0)
return;
for (var z = 0; z < ElementController.LogicalChildren.Count; z++)
{
var child = ElementController.LogicalChildren[z] as VisualElement;
if (child == null)
continue;
var childRenderer = Platform.GetRenderer(child);
if (childRenderer == null)
continue;
var nativeControl = childRenderer.NativeView;
#if __MOBILE__
Renderer.NativeView.BringSubviewToFront(nativeControl);
#endif
nativeControl.Layer.ZPosition = z * 1000;
}
}
void OnChildAdded(object sender, ElementEventArgs e)
{
var view = e.Element as VisualElement;
if (view != null)
OnChildAdded(view);
}
void OnChildRemoved(object sender, ElementEventArgs e)
{
var view = e.Element as VisualElement;
if (view != null)
OnChildRemoved(view);
}
void OnRendererElementChanged(object sender, VisualElementChangedEventArgs args)
{
if (args.NewElement == _element)
return;
SetElement(_element, args.NewElement);
}
void SetElement(VisualElement oldElement, VisualElement newElement)
{
if (oldElement == newElement)
return;
Performance.Start(out string reference);
_element = newElement;
if (oldElement != null)
{
oldElement.ChildAdded -= OnChildAdded;
oldElement.ChildRemoved -= OnChildRemoved;
oldElement.ChildrenReordered -= UpdateChildrenOrder;
if (newElement != null)
{
var pool = new RendererPool(Renderer, oldElement);
pool.UpdateNewElement(newElement);
EnsureChildrenOrder();
}
else
{
var elementController = ((IElementController)oldElement);
for (var i = 0; i < elementController.LogicalChildren.Count; i++)
{
var child = elementController.LogicalChildren[i] as VisualElement;
if (child != null)
OnChildRemoved(child);
}
}
}
if (newElement != null)
{
newElement.ChildAdded += OnChildAdded;
newElement.ChildRemoved += OnChildRemoved;
newElement.ChildrenReordered += UpdateChildrenOrder;
}
Performance.Stop(reference);
}
void UpdateChildrenOrder(object sender, EventArgs e)
{
EnsureChildrenOrder();
}
}
}