summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Platform.iOS/Renderers/CarouselPageRenderer.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Xamarin.Forms.Platform.iOS/Renderers/CarouselPageRenderer.cs')
-rw-r--r--Xamarin.Forms.Platform.iOS/Renderers/CarouselPageRenderer.cs395
1 files changed, 395 insertions, 0 deletions
diff --git a/Xamarin.Forms.Platform.iOS/Renderers/CarouselPageRenderer.cs b/Xamarin.Forms.Platform.iOS/Renderers/CarouselPageRenderer.cs
new file mode 100644
index 00000000..16e97cd2
--- /dev/null
+++ b/Xamarin.Forms.Platform.iOS/Renderers/CarouselPageRenderer.cs
@@ -0,0 +1,395 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using System.Drawing;
+#if __UNIFIED__
+using UIKit;
+#else
+using MonoTouch.UIKit;
+#endif
+#if __UNIFIED__
+using RectangleF = CoreGraphics.CGRect;
+using SizeF = CoreGraphics.CGSize;
+using PointF = CoreGraphics.CGPoint;
+
+#else
+using nfloat = System.Single;
+using nint = System.Int32;
+using nuint = System.UInt32;
+#endif
+
+namespace Xamarin.Forms.Platform.iOS
+{
+ public class CarouselPageRenderer : UIViewController, IVisualElementRenderer
+ {
+ bool _appeared;
+ Dictionary<Page, UIView> _containerMap;
+ bool _disposed;
+ EventTracker _events;
+ bool _ignoreNativeScrolling;
+ UIScrollView _scrollView;
+ VisualElementTracker _tracker;
+
+ public CarouselPageRenderer()
+ {
+ if (!Forms.IsiOS7OrNewer)
+ WantsFullScreenLayout = true;
+ }
+
+ protected CarouselPage Carousel
+ {
+ get { return (CarouselPage)Element; }
+ }
+
+ protected int SelectedIndex
+ {
+ get { return (int)(_scrollView.ContentOffset.X / _scrollView.Frame.Width); }
+ set { ScrollToPage(value); }
+ }
+
+ public VisualElement Element { get; private set; }
+
+ public event EventHandler<VisualElementChangedEventArgs> ElementChanged;
+
+ public SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint)
+ {
+ return NativeView.GetSizeRequest(widthConstraint, heightConstraint);
+ }
+
+ public UIView NativeView
+ {
+ get { return View; }
+ }
+
+ public void SetElement(VisualElement element)
+ {
+ VisualElement oldElement = Element;
+ Element = element;
+ _containerMap = new Dictionary<Page, UIView>();
+
+ OnElementChanged(new VisualElementChangedEventArgs(oldElement, element));
+
+ if (element != null)
+ element.SendViewInitialized(NativeView);
+ }
+
+ public void SetElementSize(Size size)
+ {
+ Element.Layout(new Rectangle(Element.X, Element.Y, size.Width, size.Height));
+ }
+
+ public UIViewController ViewController
+ {
+ get { return this; }
+ }
+
+ public override void DidRotate(UIInterfaceOrientation fromInterfaceOrientation)
+ {
+ _ignoreNativeScrolling = false;
+ View.SetNeedsLayout();
+ }
+
+ public override void ViewDidAppear(bool animated)
+ {
+ base.ViewDidAppear(animated);
+
+ if (_appeared || _disposed)
+ return;
+
+ _appeared = true;
+ Carousel.SendAppearing();
+ }
+
+ public override void ViewDidDisappear(bool animated)
+ {
+ base.ViewDidDisappear(animated);
+
+ if (!_appeared || _disposed)
+ return;
+
+ _appeared = false;
+ Carousel.SendDisappearing();
+ }
+
+ public override void ViewDidLayoutSubviews()
+ {
+ base.ViewDidLayoutSubviews();
+
+ View.Frame = View.Superview.Bounds;
+ _scrollView.Frame = View.Bounds;
+
+ PositionChildren();
+ UpdateCurrentPage(false);
+ }
+
+ public override void ViewDidLoad()
+ {
+ base.ViewDidLoad();
+
+ _tracker = new VisualElementTracker(this);
+ _events = new EventTracker(this);
+ _events.LoadEvents(View);
+
+ _scrollView = new UIScrollView { ShowsHorizontalScrollIndicator = false };
+
+ _scrollView.DecelerationEnded += OnDecelerationEnded;
+
+ UpdateBackground();
+
+ View.Add(_scrollView);
+
+ for (var i = 0; i < Element.LogicalChildren.Count; i++)
+ {
+ Element element = Element.LogicalChildren[i];
+ var child = element as ContentPage;
+ if (child != null)
+ InsertPage(child, i);
+ }
+
+ PositionChildren();
+
+ Carousel.PropertyChanged += OnPropertyChanged;
+ Carousel.PagesChanged += OnPagesChanged;
+ }
+
+ public override void ViewDidUnload()
+ {
+ base.ViewDidUnload();
+
+ if (_scrollView != null)
+ _scrollView.DecelerationEnded -= OnDecelerationEnded;
+
+ if (Carousel != null)
+ {
+ Carousel.PropertyChanged -= OnPropertyChanged;
+ Carousel.PagesChanged -= OnPagesChanged;
+ }
+ }
+
+ public override void WillRotate(UIInterfaceOrientation toInterfaceOrientation, double duration)
+ {
+ _ignoreNativeScrolling = true;
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && !_disposed)
+ {
+ if (_scrollView != null)
+ _scrollView.DecelerationEnded -= OnDecelerationEnded;
+
+ if (Carousel != null)
+ {
+ Carousel.PropertyChanged -= OnPropertyChanged;
+ Carousel.PagesChanged -= OnPagesChanged;
+ }
+
+ Platform.SetRenderer(Element, null);
+
+ Clear();
+
+ if (_scrollView != null)
+ {
+ _scrollView.DecelerationEnded -= OnDecelerationEnded;
+ _scrollView.RemoveFromSuperview();
+ _scrollView = null;
+ }
+
+ if (_appeared)
+ {
+ _appeared = false;
+ Carousel.SendDisappearing();
+ }
+
+ if (_events != null)
+ {
+ _events.Dispose();
+ _events = null;
+ }
+
+ if (_tracker != null)
+ {
+ _tracker.Dispose();
+ _tracker = null;
+ }
+
+ Element = null;
+ _disposed = true;
+ }
+
+ base.Dispose(disposing);
+ }
+
+ protected virtual void OnElementChanged(VisualElementChangedEventArgs e)
+ {
+ EventHandler<VisualElementChangedEventArgs> changed = ElementChanged;
+ if (changed != null)
+ changed(this, e);
+ }
+
+ void Clear()
+ {
+ foreach (KeyValuePair<Page, UIView> kvp in _containerMap)
+ {
+ kvp.Value.RemoveFromSuperview();
+ IVisualElementRenderer renderer = Platform.GetRenderer(kvp.Key);
+ if (renderer != null)
+ {
+ renderer.ViewController.RemoveFromParentViewController();
+ renderer.NativeView.RemoveFromSuperview();
+ Platform.SetRenderer(kvp.Key, null);
+ }
+ }
+ _containerMap.Clear();
+ }
+
+ void InsertPage(ContentPage page, int index)
+ {
+ IVisualElementRenderer renderer = Platform.GetRenderer(page);
+ if (renderer == null)
+ {
+ renderer = Platform.CreateRenderer(page);
+ Platform.SetRenderer(page, renderer);
+ }
+
+ UIView container = new PageContainer(page);
+ container.AddSubview(renderer.NativeView);
+ _containerMap[page] = container;
+
+ AddChildViewController(renderer.ViewController);
+ _scrollView.InsertSubview(container, index);
+
+ if ((index == 0 && SelectedIndex == 0) || (index < SelectedIndex))
+ ScrollToPage(SelectedIndex + 1, false);
+ }
+
+ void OnDecelerationEnded(object sender, EventArgs eventArgs)
+ {
+ if (_ignoreNativeScrolling || SelectedIndex >= Element.LogicalChildren.Count)
+ return;
+
+ Carousel.CurrentPage = (ContentPage)Element.LogicalChildren[SelectedIndex];
+ }
+
+ void OnPagesChanged(object sender, NotifyCollectionChangedEventArgs e)
+ {
+ _ignoreNativeScrolling = true;
+
+ NotifyCollectionChangedAction action = e.Apply((o, i, c) => InsertPage((ContentPage)o, i), (o, i) => RemovePage((ContentPage)o, i), Reset);
+ PositionChildren();
+
+ _ignoreNativeScrolling = false;
+
+ if (action == NotifyCollectionChangedAction.Reset)
+ {
+ int index = Carousel.CurrentPage != null ? CarouselPage.GetIndex(Carousel.CurrentPage) : 0;
+ if (index < 0)
+ index = 0;
+
+ ScrollToPage(index);
+ }
+ }
+
+ void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == "CurrentPage")
+ UpdateCurrentPage();
+ else if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
+ UpdateBackground();
+ else if (e.PropertyName == Page.BackgroundImageProperty.PropertyName)
+ UpdateBackground();
+ }
+
+ void PositionChildren()
+ {
+ nfloat x = 0;
+ RectangleF bounds = View.Bounds;
+ foreach (ContentPage child in ((CarouselPage)Element).Children)
+ {
+ UIView container = _containerMap[child];
+
+ container.Frame = new RectangleF(x, bounds.Y, bounds.Width, bounds.Height);
+ x += bounds.Width;
+ }
+
+ _scrollView.PagingEnabled = true;
+ _scrollView.ContentSize = new SizeF(bounds.Width * ((CarouselPage)Element).Children.Count, bounds.Height);
+ }
+
+ void RemovePage(ContentPage page, int index)
+ {
+ UIView container = _containerMap[page];
+ container.RemoveFromSuperview();
+ _containerMap.Remove(page);
+
+ IVisualElementRenderer renderer = Platform.GetRenderer(page);
+ if (renderer == null)
+ return;
+
+ renderer.ViewController.RemoveFromParentViewController();
+ renderer.NativeView.RemoveFromSuperview();
+ }
+
+ void Reset()
+ {
+ Clear();
+
+ for (var i = 0; i < Element.LogicalChildren.Count; i++)
+ {
+ Element element = Element.LogicalChildren[i];
+ var child = element as ContentPage;
+ if (child != null)
+ InsertPage(child, i);
+ }
+ }
+
+ void ScrollToPage(int index, bool animated = true)
+ {
+ if (_scrollView.ContentOffset.X == index * _scrollView.Frame.Width)
+ return;
+
+ _scrollView.SetContentOffset(new PointF(index * _scrollView.Frame.Width, 0), animated);
+ }
+
+ void UpdateBackground()
+ {
+ string bgImage = ((Page)Element).BackgroundImage;
+ if (!string.IsNullOrEmpty(bgImage))
+ {
+ View.BackgroundColor = UIColor.FromPatternImage(UIImage.FromBundle(bgImage));
+ return;
+ }
+ Color bgColor = Element.BackgroundColor;
+ if (bgColor.IsDefault)
+ View.BackgroundColor = UIColor.White;
+ else
+ View.BackgroundColor = bgColor.ToUIColor();
+ }
+
+ void UpdateCurrentPage(bool animated = true)
+ {
+ ContentPage current = Carousel.CurrentPage;
+ if (current != null)
+ ScrollToPage(CarouselPage.GetIndex(current), animated);
+ }
+
+ class PageContainer : UIView
+ {
+ public PageContainer(VisualElement element)
+ {
+ Element = element;
+ }
+
+ public VisualElement Element { get; }
+
+ public override void LayoutSubviews()
+ {
+ base.LayoutSubviews();
+
+ if (Subviews.Length > 0)
+ Subviews[0].Frame = new RectangleF(0, 0, (float)Element.Width, (float)Element.Height);
+ }
+ }
+ }
+} \ No newline at end of file