Showing posts with label xamarin android. Show all posts
Showing posts with label xamarin android. Show all posts

Vertical slider in Xamarin Forms

A slider offers a way to get continuously values from the user within a given range of values. There are various type of sliders seen across different apps and can be roughly categorised into horizontal sliders , vertical sliders and circular slider based on its appearance. It can have continuous or discrete values based on the purpose of the slider within the application.

In most applications we customise the sliders to get the look and feel we desire. Most common customisations include changing the height, colour and orientation of the slider.

Today we will be looking into creating vertical sliders in xamarin forms application.We will also look at how to increase the height of the slider and colour of the slider.


How to create a vertical slider :

In Xamarin forms to create a vertical slider, you just have to rotate the slider by - 90 degrees.


   <Slider Rotation="-90" Minimum="0" Maximum="80" Value="0" AbsoluteLayout.LayoutBounds=".5,.5,500,90" AbsoluteLayout.LayoutFlags="PositionProportional"/>


This works seamlessly in both android as well as iOS platform.


How to increase the height and change the colour of the slider:

To increase the height  of the slider we need to add custom renderers in both the platforms.

Step 1: Create custom slider class in Xamarin forms.


using System;
using Xamarin.Forms;

namespace VerticalSlider
{
    public class CustomSlider:Slider 
    {
        public CustomSlider()
        {
        }
    }
}


Step 2: Create a custom renderer for the slider control on each platform. i.e; iOS and Android


[assembly: ExportRenderer(typeof(CustomSlider), typeof(CustomSliderRenderer))]
namespace VerticalSlider.iOS
{
    public class CustomSliderRenderer:SliderRenderer
    {
        public CustomSliderRenderer()
        {
        }

        protected override void OnElementChanged(ElementChangedEventArgs<Slider> e)
        {
            SetNativeControl(new MySlideriOS());
            base.OnElementChanged(e);
        }

    }

}


Step 3: Create a custom slider class

public class MySlideriOS : UISlider
    {
        public MySlideriOS()
        {
        }
   }

Step 4: Override Track Rect For Bounds method to change the height of the slider.
In this method you could return the desired rect for the bounds of the slider.


   public class MySlideriOS : UISlider
    {
        public MySlideriOS()
        {
            
        }

        public override CGRect TrackRectForBounds(CGRect forBounds)
        {
            CGRect rect = base.TrackRectForBounds(forBounds);
            return new CGRect(rect.X, rect.Y, rect.Width, 20);
        }
}

Step 5: When changing the height of the slider in iOS, the most common issue faced is that it loses its rounded corners when the thumb reaches the extreme ends.

To overcome this issue we need to provide the minimum and maximum track images to the slider.

If in case, you are using a custom image you can provide the images to the slider. Otherwise you could just create an image out of a colour and provide it to the slider.

Here is the method to create image from a colour.


        public UIImage GetImage(CGRect recttoDraw)
        {
            CGRect rect = recttoDraw;

            CALayer layer = new CALayer();
            layer.Frame = recttoDraw;
            layer.CornerRadius = (System.nfloat)( (0.35 * this.Frame.Height));
            layer.BackgroundColor = UIColor.Red.CGColor;
            UIGraphics.BeginImageContext(layer.Frame.Size);
            layer.RenderInContext(UIGraphics.GetCurrentContext());
            UIImage image = UIGraphics.GetImageFromCurrentImageContext();
            UIGraphics.EndImageContext();
            return image;

        }

Step 6: Change the maximum track image in the custom slider constructor


        public MySlideriOS()
        {
            this.MaximumTrackTintColor = UIColor.Gray;

            UIImage img = GetImage(new CGRect(0, 0, 400, 400));

            this.SetMinTrackImage(img.CreateResizableImage(new UIEdgeInsets(13, 15, 15, 14)), UIControlState.Normal);
            this.SetMinTrackImage(img.CreateResizableImage(new UIEdgeInsets(13, 15, 15, 14)), UIControlState.Selected);

        }

Step 7: In the custom renderer's  overridden  On element changed method replace the control with the custom slider.


 protected override void OnElementChanged(ElementChangedEventArgs<Slider> e)
        {
            SetNativeControl(new MySlideriOS());
            base.OnElementChanged(e);
        }

Here is how the custom slider renderer should look at the end


using System;
using CoreAnimation;
using CoreGraphics;
using UIKit;
using VerticalSlider;
using VerticalSlider.iOS;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(CustomSlider), typeof(CustomSliderRenderer))]
namespace VerticalSlider.iOS
{
    public class CustomSliderRenderer:SliderRenderer
    {
        public CustomSliderRenderer()
        {
        }

        protected override void OnElementChanged(ElementChangedEventArgs<Slider> e)
        {
            SetNativeControl(new MySlideriOS());
            base.OnElementChanged(e);
        }

    }

    public class MySlideriOS : UISlider
    {
        public MySlideriOS()
        {
            this.MaximumTrackTintColor = UIColor.Gray;

            UIImage img = GetImage(new CGRect(0, 0, 400, 400));

            this.SetMinTrackImage(img.CreateResizableImage(new UIEdgeInsets(13, 15, 15, 14)), UIControlState.Normal);
            this.SetMinTrackImage(img.CreateResizableImage(new UIEdgeInsets(13, 15, 15, 14)), UIControlState.Selected);

        }

        public override CGRect TrackRectForBounds(CGRect forBounds)
        {
            CGRect rect = base.TrackRectForBounds(forBounds);
            return new CGRect(rect.X, rect.Y, rect.Width, 20);
        }

        public UIImage GetImage(CGRect recttoDraw)
        {
            CGRect rect = recttoDraw;

            CALayer layer = new CALayer();
            layer.Frame = recttoDraw;
            layer.CornerRadius = (System.nfloat)( (0.35 * this.Frame.Height));
            layer.BackgroundColor = UIColor.Red.CGColor;
            UIGraphics.BeginImageContext(layer.Frame.Size);
            layer.RenderInContext(UIGraphics.GetCurrentContext());
            UIImage image = UIGraphics.GetImageFromCurrentImageContext();
            UIGraphics.EndImageContext();
            return image;

        }
    }
}

Also don't forget to use the custom slider control in the xamarin forms axml file


<local:CustomSlider Rotation="-90" Minimum="0" Maximum="80" Value="0" 
        AbsoluteLayout.LayoutBounds=".5,.5,500,90" AbsoluteLayout.LayoutFlags="PositionProportional"/>


Here is how the slider is going to look at the end.



I hope you enjoyed this blog ...You can find the complete source code here

https://github.com/pooja-kamath/VerticalSlider.git

I would been soon posting  a blog on how to change the height of the slider in android. Stay tuned..

How to add tick marks on sliders in Xamarin Forms


Discrete sliders can use evenly spaced tick marks along the slider track, and the thumb will snap to them. Each tick mark should change the setting in increments that are discernible to the user.


However to achieve this in Xamarin Forms, one would have to add custom renderer in iOS and Android platforms, but here is a simple way of achieving it, without needing to add custom renderer. 


Step 1: Add a slider and a stack layout within  a grid.

<Grid Padding="0,0,0,0" WidthRequest="365">
<StackLayout WidthRequest ="364" x:Name="stack" ></StackLayout>
<Slider x:Name="slider" WidthRequest ="364"/>
</Grid> 
Step 2 : Declare constants 


private readonly int SliderMaxValue = 150;
private readonly int SliderMinValue = 0;
private readonly int SliderStepSize = 5;
private readonly int SliderTickWidth = 2;
private readonly int SliderTickHeight = 2;
Step 3 : Set slider Min and Max values

  slider.Maximum = SliderMaxValue;

  slider.Minimum = SliderMinValue;
Step 4:Set Stack view orientation  based on slider orientation.

           If the slider is horizontal add stack orientation horizontal.
           This stack view will contain the tick marks behind the slider.
   stack.Orientation = StackOrientation.Horizontal;
Step 5: Add the method to get the buffer offset based on thumb size and tick width.

private double GetOffsetFor(int index)
        {
            if (index == 0)
                return 0.0;
            else if (GetSeries().Contains(index))
                return 3.5;
            else
                return 2.5;
        }

        private int[] GetSeries()
        {
            int[] series = new int[13];
            int[] buffer = new[] {0, 0, 1, 1, 1, 2, 2, 1, 2, 3, 3, 3, 3};
            for (int i = 0; i <= 12; i++)
            {
                series[i] = 2 * i + buffer[i];
            }

            return series;
        }
Step 6: Add the ticks to the stack view 

public void AddTickMarksForSlider( StackLayout view)
        {
            int ticksDivider = SliderStepSize;
            int ticks = (int)slider.Maximum / ticksDivider;
          
            view.BackgroundColor = Color.Transparent;
         
            // make a UIImageView with tick for each tick in the slider
            for (int i = 0; i <= ticks; i++)
            {

                Label tick = new Label();
                tick.WidthRequest = SliderTickWidth;
                tick.HeightRequest = SliderTickHeight;

                view.Padding = new Thickness(15,0,14,0);

                tick.Margin = new Thickness(GetOffsetFor(i),0,0,0);

                tick.BackgroundColor =Color.Red;

                view.Children.Add(tick);

            }
        }


Step 7 : Make the slider steps discrete.

slider.ValueChanged += (sender, e) =>
            {
                double StepValue = SliderStepSize;

                var newStep = Math.Round(e.NewValue / StepValue);

                slider.Value = newStep * StepValue;
            };
This is how its going to look at the end.



I hope you enjoyed this blog... Please feel free to download the sample project from here

Popular Posts