For our Vraag Eva app, we needed a stepper control that has a different design than the normal stepper control of Xamarin.
The normal stepper looks like this:
but we needed something like this.
To make this possible a custom stepper is developed. For easiness we used the Telerik button control for showing a background image. But this is also possible we the normal button control of Xamarin
using System;
using Telerik.XamarinForms.Input;
using Xamarin.Forms;
using Xamarin_Support.Behaviors;
using Xamarin_Support.Controls;
namespace VraagEva.Controls
{
public class CustomStepper : StackLayout
{
private RadButton PlusBtn;
private RadButton MinusBtn;
private CustomEntry Entry;
private Frame Frame;
public static readonly BindableProperty TextProperty =
BindableProperty.Create(propertyName: "Text",returnType: typeof(int),declaringType: typeof(CustomStepper),defaultValue: 1,defaultBindingMode: BindingMode.TwoWay);
public static readonly BindableProperty PlusButtonImageProperty =
BindableProperty.Create("PlusButtonImage", typeof(ImageSource), typeof(CustomStepper));
public static readonly BindableProperty MinusButtonImageProperty =
BindableProperty.Create("MinusButtonImage", typeof(ImageSource), typeof(CustomStepper));
public static readonly BindableProperty MinimumValueProperty =
BindableProperty.Create("MinimumValue", typeof(int), typeof(CustomStepper), defaultValue: 1);
public static readonly BindableProperty MaximumValueProperty =
BindableProperty.Create("MaximumValue", typeof(int), typeof(CustomStepper), defaultValue: 10);
public int Text
{
get { return (int)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public ImageSource PlusButtonImage
{
get { return (ImageSource)GetValue(PlusButtonImageProperty); }
set { SetValue(PlusButtonImageProperty, value); }
}
public ImageSource MinusButtonImage
{
get { return (ImageSource)GetValue(MinusButtonImageProperty); }
set { SetValue(MinusButtonImageProperty, value); }
}
public int MinimumValue
{
get { return (int)GetValue(MinimumValueProperty); }
set { SetValue(MinimumValueProperty, value); }
}
public int MaximumValue
{
get { return (int)GetValue(MaximumValueProperty); }
set { SetValue(MaximumValueProperty, value); }
}
public CustomStepper()
{
HorizontalOptions = LayoutOptions.Center;
Orientation = StackOrientation.Horizontal;
WidthRequest = 170;
PlusBtn = new RadButton { BackgroundImage = PlusButtonImage, WidthRequest = 45, HeightRequest = 40};
MinusBtn = new RadButton { BackgroundImage = MinusButtonImage, WidthRequest = 45, HeightRequest = 40 };
PlusBtn.Clicked += PlusBtn_Clicked;
MinusBtn.Clicked += MinusBtn_Clicked;
Frame = new Frame{ CornerRadius = 20, BackgroundColor = (Color)Application.Current.Resources["LightGreyColor"], Margin = 0, Padding = 0};
Entry = new CustomEntry
{ PlaceholderColor = Color.Gray, Keyboard = Keyboard.Numeric, WidthRequest = 70,
BackgroundColor = (Color)Application.Current.Resources["LightGreyColor"], HorizontalTextAlignment = TextAlignment.Center};
Entry.Behaviors.Add(new NumericValidationBehavior());
Entry.SetBinding(Xamarin.Forms.Entry.TextProperty, new Binding(nameof(Text), BindingMode.TwoWay, source: this));
Entry.TextChanged += Entry_TextChanged;
Frame.Content = Entry;
Children.Add(MinusBtn);
Children.Add(Frame);
Children.Add(PlusBtn);
}
protected override void OnParentSet()
{
base.OnParentSet();
PlusBtn.BackgroundImage = PlusButtonImage;
MinusBtn.BackgroundImage = MinusButtonImage;
}
private void Entry_TextChanged(object sender, TextChangedEventArgs e)
{
if (!string.IsNullOrEmpty(e.NewTextValue))
this.Text = int.Parse(e.NewTextValue);
}
private void MinusBtn_Clicked(object sender, EventArgs e)
{
if (Text > MinimumValue)
Text--;
}
private void PlusBtn_Clicked(object sender, EventArgs e)
{
if (Text < MaximumValue)
Text++;
}
}
}
In the Xaml page, you can use it like this:
<localctrl:CustomStepper PlusButtonImage="plus.png" MinusButtonImage="minus.png" HorizontalOptions="Center" MinimumValue="0" MaximumValue="9" Text="{Binding NumDaysStopWeek}" />