150 lines
5.7 KiB
C#
150 lines
5.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using Xamarin.Forms;
|
|
|
|
namespace Ooui.Forms
|
|
{
|
|
public sealed class RendererPool
|
|
{
|
|
readonly Dictionary<Type, Stack<IVisualElementRenderer>> _freeRenderers =
|
|
new Dictionary<Type, Stack<IVisualElementRenderer>> ();
|
|
|
|
readonly VisualElement _oldElement;
|
|
|
|
readonly IVisualElementRenderer _parent;
|
|
|
|
public RendererPool (IVisualElementRenderer renderer, VisualElement oldElement)
|
|
{
|
|
if (renderer == null)
|
|
throw new ArgumentNullException (nameof (renderer));
|
|
|
|
if (oldElement == null)
|
|
throw new ArgumentNullException (nameof (oldElement));
|
|
|
|
_oldElement = oldElement;
|
|
_parent = renderer;
|
|
}
|
|
|
|
public IVisualElementRenderer GetFreeRenderer (VisualElement view)
|
|
{
|
|
if (view == null)
|
|
throw new ArgumentNullException (nameof (view));
|
|
|
|
var rendererType = Xamarin.Forms.Internals.Registrar.Registered.GetHandlerType (view.GetType()) ?? typeof (Renderers.ViewRenderer);
|
|
|
|
Stack<IVisualElementRenderer> renderers;
|
|
if (!_freeRenderers.TryGetValue (rendererType, out renderers) || renderers.Count == 0)
|
|
return null;
|
|
|
|
var renderer = renderers.Pop ();
|
|
renderer.SetElement (view);
|
|
return renderer;
|
|
}
|
|
|
|
public void UpdateNewElement (VisualElement newElement)
|
|
{
|
|
if (newElement == null)
|
|
throw new ArgumentNullException ("newElement");
|
|
|
|
var sameChildrenTypes = true;
|
|
|
|
var oldChildren = ((IElementController)_oldElement).LogicalChildren;
|
|
var newChildren = ((IElementController)newElement).LogicalChildren;
|
|
|
|
if (oldChildren.Count == newChildren.Count) {
|
|
for (var i = 0; i < oldChildren.Count; i++) {
|
|
if (oldChildren[i].GetType () != newChildren[i].GetType ()) {
|
|
sameChildrenTypes = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
sameChildrenTypes = false;
|
|
|
|
if (!sameChildrenTypes) {
|
|
ClearRenderers (_parent);
|
|
FillChildrenWithRenderers (newElement);
|
|
}
|
|
else
|
|
UpdateRenderers (newElement);
|
|
}
|
|
|
|
void ClearRenderers (IVisualElementRenderer renderer)
|
|
{
|
|
if (renderer == null)
|
|
return;
|
|
|
|
var subviews = renderer.NativeView.Children;
|
|
for (var i = 0; i < subviews.Count; i++) {
|
|
var childRenderer = subviews[i] as IVisualElementRenderer;
|
|
if (childRenderer != null) {
|
|
PushRenderer (childRenderer);
|
|
|
|
// The ListView CalculateHeightForCell method can create renderers and dispose its child renderers before this is called.
|
|
// Thus, it is possible that this work is already completed.
|
|
if (childRenderer.Element != null && ReferenceEquals (childRenderer, Platform.GetRenderer (childRenderer.Element)))
|
|
childRenderer.Element.ClearValue (Platform.RendererProperty);
|
|
}
|
|
renderer.NativeView.RemoveChild (subviews[i]);
|
|
}
|
|
}
|
|
|
|
void FillChildrenWithRenderers (VisualElement element)
|
|
{
|
|
foreach (var logicalChild in ((IElementController)element).LogicalChildren) {
|
|
var child = logicalChild as VisualElement;
|
|
if (child != null) {
|
|
//if (CompressedLayout.GetIsHeadless (child)) {
|
|
// child.IsPlatformEnabled = true;
|
|
// FillChildrenWithRenderers (child);
|
|
//}
|
|
//else {
|
|
var renderer = GetFreeRenderer (child) ?? Platform.CreateRenderer (child);
|
|
Platform.SetRenderer (child, renderer);
|
|
_parent.NativeView.AppendChild (renderer.NativeView);
|
|
//}
|
|
}
|
|
}
|
|
}
|
|
|
|
void PushRenderer (IVisualElementRenderer renderer)
|
|
{
|
|
var reflectableType = renderer as System.Reflection.IReflectableType;
|
|
var rendererType = reflectableType != null ? reflectableType.GetTypeInfo ().AsType () : renderer.GetType ();
|
|
|
|
Stack<IVisualElementRenderer> renderers;
|
|
if (!_freeRenderers.TryGetValue (rendererType, out renderers))
|
|
_freeRenderers[rendererType] = renderers = new Stack<IVisualElementRenderer> ();
|
|
|
|
renderers.Push (renderer);
|
|
}
|
|
|
|
void UpdateRenderers (Xamarin.Forms.Element newElement)
|
|
{
|
|
var newElementController = (IElementController)newElement;
|
|
|
|
if (newElementController.LogicalChildren.Count == 0)
|
|
return;
|
|
|
|
var subviews = _parent.NativeView.Children;
|
|
for (var i = 0; i < subviews.Count; i++) {
|
|
var childRenderer = subviews[i] as IVisualElementRenderer;
|
|
if (childRenderer == null)
|
|
continue;
|
|
|
|
var x = (int)childRenderer.NativeView.Style.ZIndex / 1000;
|
|
var element = newElementController.LogicalChildren[x] as VisualElement;
|
|
if (element == null)
|
|
continue;
|
|
|
|
if (childRenderer.Element != null && ReferenceEquals (childRenderer, Platform.GetRenderer (childRenderer.Element)))
|
|
childRenderer.Element.ClearValue (Platform.RendererProperty);
|
|
|
|
childRenderer.SetElement (element);
|
|
Platform.SetRenderer (element, childRenderer);
|
|
}
|
|
}
|
|
}
|
|
}
|