diff options
Diffstat (limited to 'Xamarin.Forms.Platform.iOS/RendererPool.cs')
-rw-r--r-- | Xamarin.Forms.Platform.iOS/RendererPool.cs | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/Xamarin.Forms.Platform.iOS/RendererPool.cs b/Xamarin.Forms.Platform.iOS/RendererPool.cs new file mode 100644 index 00000000..25df358d --- /dev/null +++ b/Xamarin.Forms.Platform.iOS/RendererPool.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections.Generic; +using System.Linq; +#if __UNIFIED__ +using UIKit; + +#else +using MonoTouch.UIKit; +#endif + +namespace Xamarin.Forms.Platform.iOS +{ + 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("renderer"); + + if (oldElement == null) + throw new ArgumentNullException("oldElement"); + + _oldElement = oldElement; + _parent = renderer; + } + + public IVisualElementRenderer GetFreeRenderer(VisualElement view) + { + if (view == null) + throw new ArgumentNullException("view"); + + var rendererType = Registrar.Registered.GetHandlerType(view.GetType()) ?? typeof(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 = _oldElement.LogicalChildren; + var newChildren = 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.Subviews; + for (var i = 0; i < subviews.Length; i++) + { + var childRenderer = subviews[i] as IVisualElementRenderer; + if (childRenderer != null) + { + PushRenderer(childRenderer); + + if (ReferenceEquals(childRenderer, Platform.GetRenderer(childRenderer.Element))) + childRenderer.Element.ClearValue(Platform.RendererProperty); + } + + subviews[i].RemoveFromSuperview(); + } + } + + void FillChildrenWithRenderers(VisualElement element) + { + foreach (var logicalChild in element.LogicalChildren) + { + var child = logicalChild as VisualElement; + if (child != null) + { + var renderer = GetFreeRenderer(child) ?? Platform.CreateRenderer(child); + Platform.SetRenderer(child, renderer); + + _parent.NativeView.AddSubview(renderer.NativeView); + } + } + } + + void PushRenderer(IVisualElementRenderer renderer) + { + var rendererType = renderer.GetType(); + + Stack<IVisualElementRenderer> renderers; + if (!_freeRenderers.TryGetValue(rendererType, out renderers)) + _freeRenderers[rendererType] = renderers = new Stack<IVisualElementRenderer>(); + + renderers.Push(renderer); + } + + void UpdateRenderers(Element newElement) + { + if (newElement.LogicalChildren.Count == 0) + return; + + var subviews = _parent.NativeView.Subviews; + for (var i = 0; i < subviews.Length; i++) + { + var childRenderer = subviews[i] as IVisualElementRenderer; + if (childRenderer == null) + continue; + + var x = (int)childRenderer.NativeView.Layer.ZPosition / 1000; + var element = newElement.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); + } + } + } +}
\ No newline at end of file |