summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Platform.Android/VisualElementPackager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Xamarin.Forms.Platform.Android/VisualElementPackager.cs')
-rw-r--r--Xamarin.Forms.Platform.Android/VisualElementPackager.cs217
1 files changed, 217 insertions, 0 deletions
diff --git a/Xamarin.Forms.Platform.Android/VisualElementPackager.cs b/Xamarin.Forms.Platform.Android/VisualElementPackager.cs
new file mode 100644
index 00000000..e7e6ab6f
--- /dev/null
+++ b/Xamarin.Forms.Platform.Android/VisualElementPackager.cs
@@ -0,0 +1,217 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using AView = Android.Views.View;
+
+namespace Xamarin.Forms.Platform.Android
+{
+ public class VisualElementPackager : IDisposable
+ {
+ readonly EventHandler<ElementEventArgs> _childAddedHandler;
+ readonly EventHandler<ElementEventArgs> _childRemovedHandler;
+ readonly EventHandler _childReorderedHandler;
+ List<IVisualElementRenderer> _childViews;
+
+ bool _disposed;
+
+ IVisualElementRenderer _renderer;
+
+ public VisualElementPackager(IVisualElementRenderer renderer)
+ {
+ if (renderer == null)
+ throw new ArgumentNullException("renderer");
+
+ _childAddedHandler = OnChildAdded;
+ _childRemovedHandler = OnChildRemoved;
+ _childReorderedHandler = OnChildrenReordered;
+
+ _renderer = renderer;
+ _renderer.ElementChanged += (sender, args) => SetElement(args.OldElement, args.NewElement);
+ }
+
+ public void Dispose()
+ {
+ if (_disposed)
+ return;
+ _disposed = true;
+
+ if (_renderer != null)
+ {
+ if (_childViews != null)
+ {
+ _childViews.Clear();
+ _childViews = null;
+ }
+
+ _renderer.Element.ChildAdded -= _childAddedHandler;
+ _renderer.Element.ChildRemoved -= _childRemovedHandler;
+
+ _renderer.Element.ChildrenReordered -= _childReorderedHandler;
+ _renderer = null;
+ }
+ }
+
+ public void Load()
+ {
+ SetElement(null, _renderer.Element);
+ }
+
+ void AddChild(VisualElement view, IVisualElementRenderer oldRenderer = null, RendererPool pool = null, bool sameChildren = false)
+ {
+ Performance.Start();
+
+ if (_childViews == null)
+ _childViews = new List<IVisualElementRenderer>();
+
+ IVisualElementRenderer renderer = oldRenderer;
+ if (pool != null)
+ renderer = pool.GetFreeRenderer(view);
+ if (renderer == null)
+ {
+ Performance.Start("New renderer");
+ renderer = Platform.CreateRenderer(view);
+ Performance.Stop("New renderer");
+ }
+
+ if (renderer == oldRenderer)
+ {
+ Platform.SetRenderer(renderer.Element, null);
+ renderer.SetElement(view);
+ }
+
+ Performance.Start("Set renderer");
+ Platform.SetRenderer(view, renderer);
+ Performance.Stop("Set renderer");
+
+ Performance.Start("Add view");
+ if (!sameChildren)
+ {
+ _renderer.ViewGroup.AddView(renderer.ViewGroup);
+ _childViews.Add(renderer);
+ }
+ Performance.Stop("Add view");
+
+ Performance.Stop();
+ }
+
+ void EnsureChildOrder()
+ {
+ for (var i = 0; i < _renderer.Element.LogicalChildren.Count; i++)
+ {
+ Element child = _renderer.Element.LogicalChildren[i];
+ var element = (VisualElement)child;
+ if (element != null)
+ {
+ IVisualElementRenderer r = Platform.GetRenderer(element);
+ _renderer.ViewGroup.BringChildToFront(r.ViewGroup);
+ }
+ }
+ }
+
+ void OnChildAdded(object sender, ElementEventArgs e)
+ {
+ var view = e.Element as VisualElement;
+ if (view != null)
+ AddChild(view);
+ if (_renderer.Element.LogicalChildren[_renderer.Element.LogicalChildren.Count - 1] != view)
+ EnsureChildOrder();
+ }
+
+ void OnChildRemoved(object sender, ElementEventArgs e)
+ {
+ Performance.Start();
+ var view = e.Element as VisualElement;
+ if (view != null)
+ RemoveChild(view);
+
+ Performance.Stop();
+ }
+
+ void OnChildrenReordered(object sender, EventArgs e)
+ {
+ EnsureChildOrder();
+ }
+
+ void RemoveChild(VisualElement view)
+ {
+ IVisualElementRenderer renderer = Platform.GetRenderer(view);
+ _childViews.Remove(renderer);
+ renderer.ViewGroup.RemoveFromParent();
+ renderer.Dispose();
+ }
+
+ void SetElement(VisualElement oldElement, VisualElement newElement)
+ {
+ Performance.Start();
+
+ var sameChildrenTypes = false;
+
+ ReadOnlyCollection<Element> newChildren = null, oldChildren = null;
+
+ RendererPool pool = null;
+ if (oldElement != null)
+ {
+ if (newElement != null)
+ {
+ sameChildrenTypes = true;
+
+ oldChildren = oldElement.LogicalChildren;
+ 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;
+ }
+
+ oldElement.ChildAdded -= _childAddedHandler;
+ oldElement.ChildRemoved -= _childRemovedHandler;
+
+ oldElement.ChildrenReordered -= _childReorderedHandler;
+
+ if (!sameChildrenTypes)
+ {
+ _childViews = new List<IVisualElementRenderer>();
+ pool = new RendererPool(_renderer, oldElement);
+ pool.ClearChildrenRenderers();
+ }
+ }
+
+ if (newElement != null)
+ {
+ Performance.Start("Setup");
+ newElement.ChildAdded += _childAddedHandler;
+ newElement.ChildRemoved += _childRemovedHandler;
+
+ newElement.ChildrenReordered += _childReorderedHandler;
+
+ newChildren = newChildren ?? newElement.LogicalChildren;
+
+ for (var i = 0; i < newChildren.Count; i++)
+ {
+ IVisualElementRenderer oldRenderer = null;
+ if (oldChildren != null && sameChildrenTypes)
+ oldRenderer = _childViews[i];
+
+ AddChild((VisualElement)newChildren[i], oldRenderer, pool, sameChildrenTypes);
+ }
+
+#if DEBUG
+ //if (renderer.Element.LogicalChildren.Any() && renderer.ViewGroup.ChildCount != renderer.Element.LogicalChildren.Count)
+ // throw new InvalidOperationException ("SetElement did not create the correct number of children");
+#endif
+ Performance.Stop("Setup");
+ }
+
+ Performance.Stop();
+ }
+ }
+} \ No newline at end of file