Vertical Slider

R_CR_C USMember
edited June 2016 in Xamarin.Forms

Hey Guys thanks in advance!
So I need a vertical slider. I only found this option but can't apply it on my Xamarin.forms slider! Please help.
https://forums.xamarin.com/discussion/3007/custom-vertical-uislider-example-anywhere

What I tried:
Step1: Rotation - Does not work because the slider will take the width of the Layoutbox anyway!
Step2: Stacklayout.Orientation - Does strange things.
Step3: CustomSlider - But there are not enough exposed settings achieve what I want!

class CustomSlider : Slider
    {
        public CustomSlider()
        {
            this.BackgroundColor = Color.Red;
            //this.Rotation = -90;
            //this.AnchorX = 0.5;
            //this.AnchorY = 0.5;

            System.Diagnostics.Debug.WriteLine(" ");
            System.Diagnostics.Debug.WriteLine(" ");
            System.Diagnostics.Debug.WriteLine(" ");
            System.Diagnostics.Debug.WriteLine(">> CUSTOM SLIDER: ID " + this.Id);
            System.Diagnostics.Debug.WriteLine(">> CUSTOM SLIDER: Bounds " + this.Bounds.ToString());
            System.Diagnostics.Debug.WriteLine(">> CUSTOM SLIDER: AnchorX " + this.AnchorX.ToString());
            System.Diagnostics.Debug.WriteLine(">> CUSTOM SLIDER: AnchorY " + this.AnchorY.ToString());
            System.Diagnostics.Debug.WriteLine(">> ");
            System.Diagnostics.Debug.WriteLine(">> CUSTOM SLIDER: RequestH " + this.HeightRequest);
            System.Diagnostics.Debug.WriteLine(">> CUSTOM SLIDER: RequestW " + this.WidthRequest);
            System.Diagnostics.Debug.WriteLine(">> CUSTOM SLIDER: Height " + this.Height);
            System.Diagnostics.Debug.WriteLine(">> CUSTOM SLIDER: Width " + this.Width);
            System.Diagnostics.Debug.WriteLine(">> ");
            System.Diagnostics.Debug.WriteLine(">> CUSTOM SLIDER: VOptionsA " + this.VerticalOptions.Alignment);
            System.Diagnostics.Debug.WriteLine(">> CUSTOM SLIDER: HOptionsA " + this.HorizontalOptions.Alignment);
            System.Diagnostics.Debug.WriteLine(">> ");
            System.Diagnostics.Debug.WriteLine(">> CUSTOM SLIDER: VOptionsE " + this.VerticalOptions.Expands);
            System.Diagnostics.Debug.WriteLine(">> CUSTOM SLIDER: HOptionsE " + this.HorizontalOptions.Expands);
            System.Diagnostics.Debug.WriteLine(">> ");
            System.Diagnostics.Debug.WriteLine(">> CUSTOM SLIDER: Scale " + this.Scale);
            System.Diagnostics.Debug.WriteLine(">> CUSTOM SLIDER: RotX " + this.RotationX);
            System.Diagnostics.Debug.WriteLine(">> CUSTOM SLIDER: RotY " + this.RotationY);
            System.Diagnostics.Debug.WriteLine(">> CUSTOM SLIDER: RotZ " + this.Rotation);
            System.Diagnostics.Debug.WriteLine(">> ");
            System.Diagnostics.Debug.WriteLine(">> CUSTOM SLIDER: TransX " + this.TranslationX);
            System.Diagnostics.Debug.WriteLine(">> CUSTOM SLIDER: TransY " + this.TranslationY);
            System.Diagnostics.Debug.WriteLine(">> CUSTOM SLIDER: XPos " + this.X);
            System.Diagnostics.Debug.WriteLine(">> CUSTOM SLIDER: YPos " + this.Y);
            System.Diagnostics.Debug.WriteLine(" ");
            System.Diagnostics.Debug.WriteLine(" ");
            System.Diagnostics.Debug.WriteLine(" ");
        }
    }

How can I make myself a slider that can be vertical from bottom to top, filling my Layout-Grid-Cell?
Or has someone an example? The XLabs ExtendedSlider does not have a vertical setting as well if I am correct.

Posts

  • R_CR_C USMember

    I will keep this thread up to date with everything I find and post my solution later on.
    https://forums.xamarin.com/discussion/933/custom-vertical-seekbar-height-not-being-set-correctly

  • R_CR_C USMember

    So I got my vertical slider for Android with some help of the posts above. ;)
    But somehow I fail to update the Value of my BindableProperty. Well I work on it and when I fix this I will post the solution later! (Also I will post the custom iOS and custom UWP renderers too when they are done).

    View:
    using System;
    using Xamarin.Forms;

    namespace xxx
    {
        public class CustomSliderFromView : View
        {
            //reference from online script
            public static readonly BindableProperty ValueProperty = BindableProperty.Create<CustomSliderFromView, int>(p => p.Value, 0);
    
            public int Value
            {
                get
                {
                    return (int)GetValue(ValueProperty);
                }
    
                set
                {
                    this.SetValue(ValueProperty, value);
                    //if (Command != null) { Command.Execute(this.CommandParameter); }
                }
            }
        }
    }
    

    CustomSliderRendererAndroid:

    [assembly: ExportRenderer (typeof(CustomSliderFromView), typeof(CustomSliderRenderer))]
    namespace xxx.Droid
    {
        class CustomSliderRenderer : ViewRenderer<CustomSliderFromView, VerticalSlider>
        {
            VerticalSlider UIVerticalSlider;
    
            protected override void OnElementChanged(ElementChangedEventArgs<CustomSliderFromView> _E)
            {
                base.OnElementChanged(_E);
    
                if (this.Control != null && Element != null)
                {
                    System.Diagnostics.Debug.WriteLine(">  Control Found: " + Element.Value + "   " + Control.Progress);
                }
    
                if (this.Control == null)
                {
                    // Instantiate the native control and assign it to the Control property with
                    // the SetNativeControl method
                    UIVerticalSlider = new VerticalSlider(this.Context);
                    this.SetNativeControl(UIVerticalSlider);
                }
    
                if (_E.OldElement != null)
                {
                    // Unsubscribe from event handlers and cleanup any resources
                    System.Diagnostics.Debug.WriteLine(">  OldElement: " + Element.Value);
                    _E.OldElement.PropertyChanged -= ElementOnPropertyChanged;
                }
    
                if (_E.NewElement != null)
                {
                    // Configure the control and subscribe to event handlers
                    Control.Progress = _E.NewElement.Value;
                    System.Diagnostics.Debug.WriteLine(">  New Element: " + Element.Value);
                    _E.NewElement.PropertyChanged += ElementOnPropertyChanged;
                }
            }
    
            void ElementOnPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
            {
                Control.Progress = Element.Value;
            }
        }
    }
    

    CustomSeekBar from Android:
    namespace xxx.Droid
    {
    public delegate void VerticalSeekBarStartTrackingTouchEventHandler(object sender, SeekBar.StartTrackingTouchEventArgs args);
    public delegate void VerticalSeekBarStopTrackingTouchEventHandler(object sender, SeekBar.StopTrackingTouchEventArgs args);

        /// <summary>
        /// Loosely based on implementation from http://stackoverflow.com/questions/4892179/how-can-i-get-a-working-vertical-seekbar-in-android
        /// </summary>
        public class VerticalSlider : SeekBar
        {
            #region ctor
    
            protected VerticalSlider(IntPtr javaReference, JniHandleOwnership transfer) 
                : base(javaReference, transfer)
            { }
    
            public VerticalSlider(Context context) 
                : base(context)
            { }
    
            public VerticalSlider(Context context, IAttributeSet attrs) 
                : base(context, attrs)
            { }
    
            public VerticalSlider(Context context, IAttributeSet attrs, int defStyle) 
                : base(context, attrs, defStyle)
            { }
    
            #endregion
    
            #region fields
    
            private int _min;
    
            #endregion
    
            #region properties
    
            public int Min
            {
                get { return _min; }
                set
                {
                    if (Min > Progress)
                        Progress = Min;
                    _min = value;
                    OnSizeChanged(Width, Height, 0, 0);
                }
            }
    
            public override int Progress
            {
                get
                {
                    return base.Progress <= Min ? Min : base.Progress;
                }
                set
                {
                    if (value <= Min)
                        base.Progress = Min;
                    else if (value >= Max)
                        base.Progress = Max;
                    else
                        base.Progress = value;
    
                    OnSizeChanged(Width, Height, 0, 0);
                }
            }
    
            #endregion
    
            #region events
    
            public new event VerticalSeekBarStartTrackingTouchEventHandler StartTrackingTouch;
            public new event VerticalSeekBarStopTrackingTouchEventHandler StopTrackingTouch;
    
            #endregion
    
            public override void Draw(Android.Graphics.Canvas canvas)
            {
                canvas.Rotate(-90);
                canvas.Translate(-Height, 0);
                base.OnDraw(canvas);
            }
    
            protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
            {
                base.OnMeasure(heightMeasureSpec, widthMeasureSpec);
                SetMeasuredDimension(MeasuredHeight, MeasuredWidth);
            }
    
            protected override void OnSizeChanged(int w, int h, int oldw, int oldh)
            {
                base.OnSizeChanged(h, w, oldh, oldw);
            }
    
            public override bool OnTouchEvent(MotionEvent e)
            {
                if (!Enabled)
                    return false;
    
                switch (e.Action)
                {
                    case MotionEventActions.Down:
                        if (null != StartTrackingTouch)
                            StartTrackingTouch(this, new StartTrackingTouchEventArgs(this));
                        Selected = true;
                        Pressed = true;
                        Progress = Max - (int)(Max * e.GetY() / Height);
                        System.Diagnostics.Debug.WriteLine(">  Down: " + Progress);
                        break;
                    case MotionEventActions.Move:
                        Progress = Max - (int)(Max * e.GetY() / Height);
                    System.Diagnostics.Debug.WriteLine(">  Move: " + Progress);
                        break;
                    case MotionEventActions.Up:
                        if (null != StopTrackingTouch)
                            StopTrackingTouch(this, new StopTrackingTouchEventArgs(this));
                        Selected = false;
                        Pressed = false;
                        Progress = Max - (int)(Max * e.GetY() / Height);
                    System.Diagnostics.Debug.WriteLine(">  Up: " + Progress);
                        break;
                    case MotionEventActions.Cancel:
                        Selected = false;
                        Pressed = false;
                    System.Diagnostics.Debug.WriteLine(">  Cancel: " + Progress);
                        break;
                }
    
                return true;
            }
        }
    }
    
  • R_CR_C USMember

    Special thanks @Cheesebaron for his VerticalSlider : Seekbar!

  • R_CR_C USMember

    Update: DIrty fix for start

    if (this.Control == null)
                {
                    // Instantiate the native control and assign it to the Control property with
                    // the SetNativeControl method
                    UIVerticalSlider = new VerticalSlider(this.Context);
                    this.SetNativeControl(UIVerticalSlider);
                    this.Control.ProgressChanged += ElementOnPropertyChanged;
                }
    

    Subscribed:

    void ElementOnPropertyChanged(object sender, SeekBar.ProgressChangedEventArgs e)
            {
                System.Diagnostics.Debug.WriteLine(">  Event subscribe fire!: " + Element.Value + "   " + Control.Progress);
                Element.Value = Control.Progress;
            }
    
  • R_CR_C USMember

    Update: Changed the Customslider from View <- because I want to rework everything to work well with Xamarin.forms

    public class CustomSliderFromView : View
    {
    /// <summary>
    /// The ValueChanged event is fired when the Value property changes.
    /// </summary>
    public event EventHandler<ValueChangedEventArgs> ValueChanged;
    /// <summary>
    /// The MaximumChanged event is fired when the Maximum of the slider changes!
    /// </summary>
    public event EventHandler<ValueChangedEventArgs> MaximumChanged;
    /// <summary>
    /// The MinimumChanged event is fired when the Minimum of the slider changes!
    /// </summary>
    public event EventHandler<ValueChangedEventArgs> MinimumChanged;
    /// <summary>
    /// Value of the Slider ranging between Maximum and Minimum. This is a bindable property.
    /// </summary>
    public static readonly BindableProperty ValueProperty = BindableProperty.Create<CustomSliderFromView, int>(p => p.Value, 0);
    /// <summary>
    /// Identifies the Maximum bindable property.
    /// </summary>
    public static readonly BindableProperty MaximumProperty = BindableProperty.Create<CustomSliderFromView, int>(p => p.Maximum, 100);
    /// <summary>
    /// Identifies the Minimum bindable property.
    /// </summary>
    public static readonly BindableProperty MinimumProperty = BindableProperty.Create<CustomSliderFromView, int>(p => p.Minimum, 0);
    
            public int Value
            {
                get
                {
                    return (int)GetValue(ValueProperty);
                }
    
                set
                {
                    if (ValueChanged != null)
                        ValueChanged(this, new ValueChangedEventArgs((int)GetValue(ValueProperty), value));
                    this.SetValue(ValueProperty, value);
                }
            }
    
            /// <summary>
            /// Gets or sets the maximum selectable value for the Slider. This is a bindable property.
            /// </summary>
            public int Maximum
            {
                get
                {
                    return (int)GetValue(MaximumProperty);
                }
    
                set
                {
                    if (MaximumChanged != null)
                        MaximumChanged(this, new ValueChangedEventArgs((int)GetValue(MaximumProperty), value));
                    this.SetValue(MaximumProperty, value);
                }
            }
    
            /// <summary>
            /// Gets or sets the minimum selectable value for the Slider. This is a bindable property.
            /// </summary>
            public int Minimum
            {
                get
                {
                    return (int)GetValue(MinimumProperty);
                }
    
                set
                {
                    if (MinimumChanged != null)
                        MinimumChanged(this, new ValueChangedEventArgs((int)GetValue(MinimumProperty), value));
                    this.SetValue(MinimumProperty, value);
                }
            }
        }
    

    PS: Wanted to say that I only work with xamarin since 2 weeks and if I do something fundamentaly wrong please reply! :smile:

  • poojakamath.0720poojakamath.0720 ✭✭ USMember ✭✭
Sign In or Register to comment.