From cf2950a80fe3d977ec638c7068ade26ff1eb344d Mon Sep 17 00:00:00 2001 From: Pat Date: Thu, 21 Apr 2016 18:50:32 -0500 Subject: [PATCH 1/2] vertical scrollbar option --- src/CustomLayouts/Controls/CarouselLayout.cs | 14 ++- src/CustomLayouts/HomePage.cs | 11 ++- src/CustomLayouts/SwitcherPage.cs | 19 +++- src/Droid/Renderers/CarouselLayoutRenderer.cs | 98 ++++++++++++++----- 4 files changed, 105 insertions(+), 37 deletions(-) diff --git a/src/CustomLayouts/Controls/CarouselLayout.cs b/src/CustomLayouts/Controls/CarouselLayout.cs index 58cc324..0a7ff9e 100644 --- a/src/CustomLayouts/Controls/CarouselLayout.cs +++ b/src/CustomLayouts/Controls/CarouselLayout.cs @@ -21,12 +21,12 @@ public enum IndicatorStyleEnum int _selectedIndex; - public CarouselLayout () + public CarouselLayout (ScrollOrientation scrollOrientation) { - Orientation = ScrollOrientation.Horizontal; + Orientation = scrollOrientation; _stack = new StackLayout { - Orientation = StackOrientation.Horizontal, + Orientation = Orientation == ScrollOrientation.Horizontal ? StackOrientation.Horizontal : StackOrientation.Vertical, Spacing = 0 }; @@ -55,7 +55,13 @@ protected override void LayoutChildren (double x, double y, double width, double if (_layingOutChildren) return; _layingOutChildren = true; - foreach (var child in Children) child.WidthRequest = width; + foreach (var child in Children) + { + child.WidthRequest = width; + + if (Orientation == ScrollOrientation.Vertical) + child.HeightRequest = height; + } _layingOutChildren = false; } diff --git a/src/CustomLayouts/HomePage.cs b/src/CustomLayouts/HomePage.cs index 46c584f..b3c2a60 100644 --- a/src/CustomLayouts/HomePage.cs +++ b/src/CustomLayouts/HomePage.cs @@ -18,10 +18,14 @@ public class HomePage : ContentPage SwitcherPageViewModel viewModel; - public HomePage(CarouselLayout.IndicatorStyleEnum indicatorStyle) + ScrollOrientation _scrollOrienation; + + public HomePage(CarouselLayout.IndicatorStyleEnum indicatorStyle, ScrollOrientation scrollOrientation) { _indicatorStyle = indicatorStyle; + _scrollOrienation = scrollOrientation; + viewModel = new SwitcherPageViewModel(); BindingContext = viewModel; @@ -44,7 +48,7 @@ public HomePage(CarouselLayout.IndicatorStyleEnum indicatorStyle) Constraint.RelativeToParent ((parent) => { return parent.X; }), Constraint.RelativeToParent ((parent) => { return parent.Y; }), Constraint.RelativeToParent ((parent) => { return parent.Width; }), - Constraint.RelativeToParent ((parent) => { return parent.Height/2; }) + Constraint.RelativeToParent((parent) => { return _scrollOrienation == ScrollOrientation.Vertical ? parent.Height : parent.Height / 2; }) ); relativeLayout.Children.Add (dots, @@ -86,7 +90,8 @@ public HomePage(CarouselLayout.IndicatorStyleEnum indicatorStyle) CarouselLayout CreatePagesCarousel () { - var carousel = new CarouselLayout { + var carousel = new CarouselLayout(_scrollOrienation) + { HorizontalOptions = LayoutOptions.FillAndExpand, VerticalOptions = LayoutOptions.FillAndExpand, IndicatorStyle = _indicatorStyle, diff --git a/src/CustomLayouts/SwitcherPage.cs b/src/CustomLayouts/SwitcherPage.cs index f5930bb..250070c 100644 --- a/src/CustomLayouts/SwitcherPage.cs +++ b/src/CustomLayouts/SwitcherPage.cs @@ -6,6 +6,8 @@ namespace CustomLayouts { public class SwitcherPage : ContentPage { + public SwitchCell scrollOrientationSwitch; + public SwitcherPage() { Title = "Pager Layout w/ Indicators"; @@ -13,17 +15,25 @@ public SwitcherPage() var none = new Button { HorizontalOptions = LayoutOptions.Center, Text = "No pager indicator", - Command = new Command((obj) => Navigation.PushAsync(new HomePage(CarouselLayout.IndicatorStyleEnum.None))) + Command = new Command((obj) => Navigation.PushAsync(new HomePage(CarouselLayout.IndicatorStyleEnum.None, scrollOrientationSwitch.On ? ScrollOrientation.Horizontal : ScrollOrientation.Vertical))) }; var dots = new Button { HorizontalOptions = LayoutOptions.Center, Text = "Dots", - Command = new Command((obj) => Navigation.PushAsync(new HomePage(CarouselLayout.IndicatorStyleEnum.Dots))) + Command = new Command((obj) => Navigation.PushAsync(new HomePage(CarouselLayout.IndicatorStyleEnum.Dots, scrollOrientationSwitch.On ? ScrollOrientation.Horizontal : ScrollOrientation.Vertical))) }; var tabs = new Button { HorizontalOptions = LayoutOptions.Center, Text = "Tabs", - Command = new Command((obj) => Navigation.PushAsync(new HomePage(CarouselLayout.IndicatorStyleEnum.Tabs))) + Command = new Command((obj) => Navigation.PushAsync(new HomePage(CarouselLayout.IndicatorStyleEnum.Tabs, scrollOrientationSwitch.On ? ScrollOrientation.Horizontal : ScrollOrientation.Vertical))) + }; + scrollOrientationSwitch = new SwitchCell() { Text = "Vertical/Horizontal", On = true }; + var table = new TableView(); + table.Intent = TableIntent.Settings; + table.Root = new TableRoot() { + new TableSection("Orientation") { + scrollOrientationSwitch + } }; Content = new StackLayout { Orientation = StackOrientation.Vertical, @@ -32,7 +42,8 @@ public SwitcherPage() Children = { none, dots, - tabs + tabs, + table } }; } diff --git a/src/Droid/Renderers/CarouselLayoutRenderer.cs b/src/Droid/Renderers/CarouselLayoutRenderer.cs index 0da7f41..75326a7 100644 --- a/src/Droid/Renderers/CarouselLayoutRenderer.cs +++ b/src/Droid/Renderers/CarouselLayoutRenderer.cs @@ -15,54 +15,74 @@ namespace CustomLayouts.Droid.Renderers { public class CarouselLayoutRenderer : ScrollViewRenderer { - int _prevScrollX; - int _deltaX; + int _prevScroll; + int _delta; bool _motionDown; - Timer _deltaXResetTimer; + Timer _deltaResetTimer; Timer _scrollStopTimer; + Android.Widget.ScrollView _verticalScrollView; HorizontalScrollView _scrollView; + bool _isVertical; protected override void OnElementChanged (VisualElementChangedEventArgs e) { base.OnElementChanged (e); if(e.NewElement == null) return; - _deltaXResetTimer = new Timer(100) { AutoReset = false }; - _deltaXResetTimer.Elapsed += (object sender, ElapsedEventArgs args) => _deltaX = 0; + _deltaResetTimer = new Timer(100) { AutoReset = false }; + _deltaResetTimer.Elapsed += (object sender, ElapsedEventArgs args) => _delta = 0; _scrollStopTimer = new Timer (200) { AutoReset = false }; _scrollStopTimer.Elapsed += (object sender, ElapsedEventArgs args2) => UpdateSelectedIndex (); + _isVertical = (((CarouselLayout)Element).Orientation == ScrollOrientation.Vertical); + e.NewElement.PropertyChanged += ElementPropertyChanged; } void ElementPropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "Renderer") { - _scrollView = (HorizontalScrollView)typeof(ScrollViewRenderer) - .GetField ("hScrollView", BindingFlags.NonPublic | BindingFlags.Instance) - .GetValue (this); - - _scrollView.HorizontalScrollBarEnabled = false; - _scrollView.Touch += HScrollViewTouch; + if (_isVertical) + { + _verticalScrollView = this; + _verticalScrollView.Touch += ScrollViewTouch; + } + else + { + _scrollView = (HorizontalScrollView)typeof(ScrollViewRenderer) + .GetField("hScrollView", BindingFlags.NonPublic | BindingFlags.Instance) + .GetValue(this); + + _scrollView.HorizontalScrollBarEnabled = false; + _scrollView.Touch += ScrollViewTouch; + } } if (e.PropertyName == CarouselLayout.SelectedIndexProperty.PropertyName && !_motionDown) { ScrollToIndex (((CarouselLayout)this.Element).SelectedIndex); } } - void HScrollViewTouch (object sender, TouchEventArgs e) + void ScrollViewTouch (object sender, TouchEventArgs e) { e.Handled = false; switch (e.Event.Action) { case MotionEventActions.Move: - _deltaXResetTimer.Stop (); - _deltaX = _scrollView.ScrollX - _prevScrollX; - _prevScrollX = _scrollView.ScrollX; + _deltaResetTimer.Stop(); + if (_isVertical) + { + _delta = _verticalScrollView.ScrollY - _prevScroll; + _prevScroll = _verticalScrollView.ScrollY; + } + else + { + _delta = _scrollView.ScrollX - _prevScroll; + _prevScroll = _scrollView.ScrollX; + } UpdateSelectedIndex (); - _deltaXResetTimer.Start (); + _deltaResetTimer.Start (); break; case MotionEventActions.Down: _motionDown = true; @@ -77,18 +97,31 @@ void HScrollViewTouch (object sender, TouchEventArgs e) } void UpdateSelectedIndex () { - var center = _scrollView.ScrollX + (_scrollView.Width / 2); var carouselLayout = (CarouselLayout)this.Element; - carouselLayout.SelectedIndex = (center / _scrollView.Width); + if (_isVertical) + { + var center = _verticalScrollView.ScrollY + (_verticalScrollView.Height / 2); + carouselLayout.SelectedIndex = (center / _verticalScrollView.Height); + } + else + { + var center = _scrollView.ScrollX + (_scrollView.Width / 2); + carouselLayout.SelectedIndex = (center / _scrollView.Width); + } } void SnapScroll () { - var roughIndex = (float)_scrollView.ScrollX / _scrollView.Width; + var roughIndex = 0.0; + + if (_isVertical) + roughIndex = (float)_verticalScrollView.ScrollY / _verticalScrollView.Height; + else + roughIndex = (float)_scrollView.ScrollX / _scrollView.Width; var targetIndex = - _deltaX < 0 ? Math.Floor (roughIndex) - : _deltaX > 0 ? Math.Ceil (roughIndex) + _delta < 0 ? Math.Floor (roughIndex) + : _delta > 0 ? Math.Ceil (roughIndex) : Math.Round (roughIndex); ScrollToIndex ((int)targetIndex); @@ -96,10 +129,20 @@ void SnapScroll () void ScrollToIndex (int targetIndex) { - var targetX = targetIndex * _scrollView.Width; - _scrollView.Post (new Runnable (() => { - _scrollView.SmoothScrollTo(targetX, 0); - })); + if (_isVertical) + { + var target = targetIndex * _verticalScrollView.Height; + _verticalScrollView.Post(new Runnable(() => { + _verticalScrollView.SmoothScrollTo(0, target); + })); + } + else + { + var target = targetIndex * _scrollView.Width; + _scrollView.Post(new Runnable(() => { + _scrollView.SmoothScrollTo(target, 0); + })); + } } bool _initialized = false; @@ -109,7 +152,10 @@ public override void Draw (Canvas canvas) if (_initialized) return; _initialized = true; var carouselLayout = (CarouselLayout)this.Element; - _scrollView.ScrollTo (carouselLayout.SelectedIndex * Width, 0); + if (_isVertical) + _verticalScrollView.ScrollTo(0, carouselLayout.SelectedIndex * Height); + else + _scrollView.ScrollTo (carouselLayout.SelectedIndex * Width, 0); } protected override void OnSizeChanged(int w, int h, int oldw, int oldh) From 5f0f0291ec7b6e4ba74788ddb67bd28865e56a57 Mon Sep 17 00:00:00 2001 From: Pat Date: Fri, 22 Apr 2016 19:14:16 -0500 Subject: [PATCH 2/2] default the scroll position in ctor --- src/CustomLayouts/Controls/CarouselLayout.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CustomLayouts/Controls/CarouselLayout.cs b/src/CustomLayouts/Controls/CarouselLayout.cs index 0a7ff9e..78a3ae8 100644 --- a/src/CustomLayouts/Controls/CarouselLayout.cs +++ b/src/CustomLayouts/Controls/CarouselLayout.cs @@ -21,7 +21,7 @@ public enum IndicatorStyleEnum int _selectedIndex; - public CarouselLayout (ScrollOrientation scrollOrientation) + public CarouselLayout (ScrollOrientation scrollOrientation = ScrollOrientation.Horizontal) { Orientation = scrollOrientation;