summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Platform.WP8/ScrollViewRenderer.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Xamarin.Forms.Platform.WP8/ScrollViewRenderer.cs')
-rw-r--r--Xamarin.Forms.Platform.WP8/ScrollViewRenderer.cs194
1 files changed, 194 insertions, 0 deletions
diff --git a/Xamarin.Forms.Platform.WP8/ScrollViewRenderer.cs b/Xamarin.Forms.Platform.WP8/ScrollViewRenderer.cs
new file mode 100644
index 00000000..6e19d8c4
--- /dev/null
+++ b/Xamarin.Forms.Platform.WP8/ScrollViewRenderer.cs
@@ -0,0 +1,194 @@
+using System;
+using System.ComponentModel;
+using System.Windows;
+using System.Windows.Controls;
+
+namespace Xamarin.Forms.Platform.WinPhone
+{
+ public class ScrollViewRenderer : ViewRenderer<ScrollView, ScrollViewer>
+ {
+ Animatable _animatable;
+
+ public ScrollViewRenderer()
+ {
+ AutoPackage = false;
+ }
+
+ protected IScrollViewController Controller
+ {
+ get { return Element; }
+ }
+
+ public override SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint)
+ {
+ SizeRequest result = base.GetDesiredSize(widthConstraint, heightConstraint);
+ result.Minimum = new Size(40, 40);
+ return result;
+ }
+
+ protected override System.Windows.Size ArrangeOverride(System.Windows.Size finalSize)
+ {
+ if (Element == null)
+ return finalSize;
+
+ Element.IsInNativeLayout = true;
+
+ if (Control != null)
+ {
+ Control.Measure(finalSize);
+ Control.Arrange(new Rect(0, 0, finalSize.Width, finalSize.Height));
+ }
+
+ Element.IsInNativeLayout = false;
+
+ return finalSize;
+ }
+
+ protected override System.Windows.Size MeasureOverride(System.Windows.Size availableSize)
+ {
+ if (Element == null)
+ return new System.Windows.Size(0, 0);
+
+ double width = Math.Max(0, Element.Width);
+ double height = Math.Max(0, Element.Height);
+ return new System.Windows.Size(width, height);
+ }
+
+ protected override void OnElementChanged(ElementChangedEventArgs<ScrollView> e)
+ {
+ base.OnElementChanged(e);
+
+ if (e.OldElement != null)
+ ((IScrollViewController)e.OldElement).ScrollToRequested -= OnScrollToRequested;
+
+ if (e.NewElement != null)
+ {
+ if (Control == null)
+ {
+ SetNativeControl(new ScrollViewer { ManipulationMode = ManipulationMode.Control });
+ Control.LayoutUpdated += (sender, args) => { UpdateScrollPosition(); };
+ }
+ ((IScrollViewController)e.NewElement).ScrollToRequested += OnScrollToRequested;
+ }
+
+ SizeChanged += (sender, args) =>
+ {
+ Control.Width = ActualWidth;
+ Control.Height = ActualHeight;
+ };
+
+ UpdateOrientation();
+
+ LoadContent();
+ }
+
+ protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ base.OnElementPropertyChanged(sender, e);
+
+ if (e.PropertyName == "Content")
+ LoadContent();
+ else if (e.PropertyName == Layout.PaddingProperty.PropertyName)
+ UpdateMargins();
+ else if (e.PropertyName == ScrollView.OrientationProperty.PropertyName)
+ UpdateOrientation();
+ }
+
+ static double GetDistance(double start, double position, double v)
+ {
+ return start + (position - start) * v;
+ }
+
+ void LoadContent()
+ {
+ var lastContent = Control.Content as FrameworkElement;
+ if (lastContent != null)
+ lastContent.Margin = new System.Windows.Thickness(); //undo any damage we may have done to this renderer
+
+ View view = Element.Content;
+
+ if (view != null)
+ Platform.SetRenderer(view, Platform.CreateRenderer(view));
+
+ Control.Content = view != null ? Platform.GetRenderer(view) : null;
+
+ UpdateMargins();
+ }
+
+ void OnScrollToRequested(object sender, ScrollToRequestedEventArgs e)
+ {
+ if (_animatable == null && e.ShouldAnimate)
+ _animatable = new Animatable();
+
+ ScrollToPosition position = e.Position;
+ double x = e.ScrollX;
+ double y = e.ScrollY;
+
+ if (e.Mode == ScrollToMode.Element)
+ {
+ Point itemPosition = Controller.GetScrollPositionForElement(e.Element as VisualElement, e.Position);
+ x = itemPosition.X;
+ y = itemPosition.Y;
+ }
+
+ if (Control.VerticalOffset == y && Control.HorizontalOffset == x)
+ return;
+
+ if (e.ShouldAnimate)
+ {
+ var animation = new Animation(v => { UpdateScrollOffset(GetDistance(Control.ViewportWidth, x, v), GetDistance(Control.ViewportHeight, y, v)); });
+
+ animation.Commit(_animatable, "ScrollTo", length: 500, easing: Easing.CubicInOut, finished: (v, d) =>
+ {
+ UpdateScrollOffset(x, y);
+ Controller.SendScrollFinished();
+ });
+ }
+ else
+ {
+ UpdateScrollOffset(x, y);
+ Controller.SendScrollFinished();
+ }
+ }
+
+ void UpdateMargins()
+ {
+ var element = Control.Content as FrameworkElement;
+ if (element == null)
+ return;
+
+ if (Element.Orientation == ScrollOrientation.Horizontal)
+ {
+ // need to add left/right margins
+ element.Margin = new System.Windows.Thickness(Element.Padding.Left, 0, Element.Padding.Right, 0);
+ }
+ else
+ {
+ // need to add top/bottom margins
+ element.Margin = new System.Windows.Thickness(0, Element.Padding.Top, 0, Element.Padding.Bottom);
+ }
+ }
+
+ void UpdateOrientation()
+ {
+ if (Element.Orientation == ScrollOrientation.Horizontal)
+ Control.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
+ else
+ Control.HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled;
+ }
+
+ void UpdateScrollOffset(double x, double y)
+ {
+ if (Element.Orientation == ScrollOrientation.Horizontal)
+ Control.ScrollToHorizontalOffset(x);
+ else
+ Control.ScrollToVerticalOffset(y);
+ }
+
+ void UpdateScrollPosition()
+ {
+ if (Element != null)
+ Controller.SetScrolledPosition(Control.HorizontalOffset, Control.VerticalOffset);
+ }
+ }
+} \ No newline at end of file