Vapolia.WheelPicker
5.0.1-pre7
Prefix Reserved
See the version list below for details.
dotnet add package Vapolia.WheelPicker --version 5.0.1-pre7
NuGet\Install-Package Vapolia.WheelPicker -Version 5.0.1-pre7
<PackageReference Include="Vapolia.WheelPicker" Version="5.0.1-pre7" />
paket add Vapolia.WheelPicker --version 5.0.1-pre7
#r "nuget: Vapolia.WheelPicker, 5.0.1-pre7"
// Install Vapolia.WheelPicker as a Cake Addin #addin nuget:?package=Vapolia.WheelPicker&version=5.0.1-pre7&prerelease // Install Vapolia.WheelPicker as a Cake Tool #tool nuget:?package=Vapolia.WheelPicker&version=5.0.1-pre7&prerelease
Xamarin.Forms (iOS, Android) | Xamarin.Android, Xamarin.iOS |
---|---|
Wheel Picker
From Apple:
Wheel Picker: a view that uses a spinning-wheel or slot-machine metaphor to show one or more sets of values.
Enterprise support available: contact
Source code available: contact
Maui .NET8+ & Xamarin Forms (Android,iOS): WheelPicker
Native Android: vapolia.WheelPicker
& iOS: UIPickerViewModel
Overview
This control brings the Wheel Picker view to Xamarin Forms on Android and iOS (it also supports native Xamarin Android and iOS). It mimics a slot-machine user interface on Android, while on iOS it makes easy to use multi wheel pickers.
Quick start
Install the nuget package
dotnet add package Vapolia.WheelPicker
Add the WheelPicker control
- Add
xmlns:wp="clr-namespace:Vapolia.WheelPickerForms;assembly=Vapolia.WheelPicker"
to the root tag of a view. - Add a minimal wheel:
<wp:WheelPicker ItemsSourceSimple="{Binding MyListProperty}">
<wp:WheelDefinition Width="Auto" HorizontalOptions="Left" Alignment="Center" />
</wp:WheelPicker>
Anatomy of the control
The WheelPicker is made of 2 parts:
- the outside container
<wp:WheelPicker> ... </wp:WheelPicker>
- a list of one or more
wp:WheelDefinition
, each representing a vertical wheel. You can have 1 or more wheels in the same container.
Important note:wp:WheelDefinition
contains a customizable template to display its content.
The WheelPicker is bound to a single data source through ItemsSource="{Binding SomeProperty}"
. The type of SomeProperty
can be:
when there is only 1 wheel:
- a list of items
IReadOnlyCollection<T>
. - Ex:
List<string>
- a list of items
when there are more than 1 wheel:
- a list of list of items
IReadOnlyCollection<IReadOnlyCollection<T>>
. - Ex:
List<List<string>>
. - Each inner list is bound to a wheel.
The outer list must have a number of items equal to the number of
wp:WheelDefinition
.
- a list of list of items
Full page example
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:wp="clr-namespace:Vapolia.WheelPickerForms;assembly=Vapolia.WheelPicker"
x:Class="WheelPickerDemo.Forms.MainPage">
<VerticalStackLayout>
<wp:WheelPicker HorizontalOptions="Fill" SelectedItemsIndex="0"
ItemsSource="{Binding Days}"
Command="{Binding ItemSelectedCommand}">
<wp:WheelDefinition Width="Auto" HorizontalOptions="Left" Alignment="Center" />
</wp:WheelPicker>
</VerticalStackLayout>
</ContentPage>
<br/>In the code behind, set the binding context to your view model containing the items to display.
<br/>In the code below, ItemsSource
is bound to a list of strings.
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
BindingContext = new MainPageModel();
}
}
public class MainPageModel
{
public List<string> Days { get; } = new () { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
public Command ItemSelectedCommand { get; }
public MainPageModel()
{
//Component is the index of the wheel triggering the command.
//Row is the index of the currently displayed item at the center of the wheel for this Component.
//ItemIndexes are the current indexes of all wheels of the WheelPicker control
ItemSelectedCommand = new Command<(int Component, int Row, IList<int> ItemIndexes)>(tuple =>
{
var selectedValue = Days[tuple.Row];
//...
});
}
}
Using custom templates
You can customize how each item is rendered by using custom templates.
By default the control converts all items to strings and render those strings with the specified style.
But you can fully customize the style and content of the items with one constraint: there is only one template per wheel, which renders all items of that wheel. If you have multiple wheels in the same WheelPicker, you can set one template per wheel.
Example below: a templated picker with 3 wheels. All properties are bindable and can be dynamically changed.
Note how SelectedItemsIndex
is used to initialize the position of the 3 wheels to the specified item indexes.
<wp:WheelPicker x:Name="SlotPicker" ItemsSource="{Binding Slot.ItemsSource}"
SelectedItemsIndex="1 10 7"
Command="{Binding Slot.ItemSelectedCommand}"
ItemTextSelectedColor="Lime"
ItemTextFont="Italic"
HorizontalOptions="Fill"
SelectionLinesColor="Aquamarine">
<wp:WheelDefinition Width="*" HorizontalOptions="Left" Alignment="Center" IsCircular="True">
<DataTemplate>
<Label Text="{Binding .}" TextColor="Black" FontSize="30" />
</DataTemplate>
</wp:WheelDefinition>
<wp:WheelDefinition Width="*" HorizontalOptions="Left" Alignment="Center" IsCircular="True" RowHeight="100">
<DataTemplate>
<Image Source="{Binding .}" HeightRequest="100" Aspect="AspectFit" />
</DataTemplate>
</wp:WheelDefinition>
<wp:WheelDefinition Width="*" HorizontalOptions="Left" Alignment="Center" IsCircular="True" RowHeight="100">
<DataTemplate>
<Image Source="{Binding .}" HeightRequest="100" Aspect="AspectFit" />
</DataTemplate>
</wp:WheelDefinition>
</wp:WheelPicker>
Some examples
Those examples are extracted from the demo projects in this repository.
A simple picker with one wheel:
<wp:WheelPicker ItemsSource="{Binding DayPicker.ItemsSource}">
<wp:WheelDefinition Width="Auto" HorizontalOptions="Left" Alignment="Center" />
</wp:WheelPicker>
A templated picker with one wheel:
<wp:WheelPicker ItemsSource="{Binding DayPicker.ItemsSource}">
<wp:WheelDefinition Width="*" HorizontalOptions="Left" Alignment="Center" IsCircular="True" RowHeight="48">
<DataTemplate>
<Image Source="{Binding .}" HeightRequest="48" Aspect="AspectFill" />
</DataTemplate>
</wp:WheelDefinition>
</wp:WheelPicker>
Note that the tag wp:WheelDefinition.ItemTemplate
is optional as it is the content property.
A picker with 3 wheels:
The center wheel's width is computed automatically. Items are aligned differently inside each wheel.
<wp:WheelPicker SelectionLinesColor="Navy"
HorizontalSpaceBetweenWheels="40"
ItemsSource="{Binding DatePicker.ItemsSource}"
SelectedItemsIndex="0,0,0"
Command="{Binding DatePicker.ItemSelectedCommand}"
HorizontalOptions="Fill">
<wp:WheelDefinition Width="*" HorizontalOptions="Right" />
<wp:WheelDefinition Width="Auto" HorizontalOptions="Left" />
<wp:WheelDefinition Width="*" HorizontalOptions="Left" />
</wp:WheelPicker>
A templated picker with 3 wheels:
All properties are bindable and can be dynamically changed.
<wp:WheelPicker x:Name="SlotPicker" ItemsSource="{Binding Slot.ItemsSource}"
SelectedItemsIndex="0 0 0"
Command="{Binding Slot.ItemSelectedCommand}"
ItemTextSelectedColor="Lime"
ItemTextFont="Italic"
HorizontalOptions="Fill"
SelectionLinesColor="Aquamarine">
<wp:WheelDefinition Width="*" HorizontalOptions="Left" Alignment="Center" IsCircular="True" RowHeight="100">
<DataTemplate>
<Image Source="{Binding .}" HeightRequest="100" Aspect="AspectFit" />
</DataTemplate>
</wp:WheelDefinition>
<wp:WheelDefinition Width="*" HorizontalOptions="Left" Alignment="Center" IsCircular="True" RowHeight="100">
<DataTemplate>
<Image Source="{Binding .}" HeightRequest="100" Aspect="AspectFit" />
</DataTemplate>
</wp:WheelDefinition>
<wp:WheelDefinition Width="*" HorizontalOptions="Left" Alignment="Center" IsCircular="True" RowHeight="100">
<DataTemplate>
<Image Source="{Binding .}" HeightRequest="100" Aspect="AspectFit" />
</DataTemplate>
</wp:WheelDefinition>
</wp:WheelPicker>
Reference (Maui & Xamarin Forms)
<details><summary>Click to expand</summary>
WheelPicker
Definition
IList<WheelDefinition>
WheelDefinitions
Default Contentobject
ItemsSource
Accepts bothIReadOnlyCollection<T>
andIReadOnlyCollection<IReadOnlyCollection<T>>
Appearance
double
HorizontalSpaceBetweenWheels
Color
SelectionLinesColor
Item appearance (used by the default item template, when no custom item template is specified)
Font
ItemTextFont
Color
ItemTextColor
Color
ItemTextSelectedColor
Selection
IList<int>
SelectedItemsIndex
One index per wheel.ICommand
Command
Triggered when any of the wheel's index has changedEventHandler<WheelChangedEventArgs>
SelectedItemIndexChanged
Triggered when any of the wheel's index has changedvoid
Spin
(int items, int wheelIndex = 0)
items: the number of item to spin
SelectedItemsIndex
is a list of integer. Each integer represents the selected index inside a wheel. In XAML, you can use a space or comma separated string of integers.
WheelDefinition
GridLength
Width
WheelItemAlign
HorizontalOptions
WheelItemAlign
Alignment
bool
IsCircular
DataTemplate
ImageItemTemplate
double
RowHeight
When a wheel's Width
is set to Auto
, the control computes the max width of all strings in the data source (if object are strings). When set to *
(star), the wheel's width will be proportional to the remaining space. See the Xamarin Forms Grid
control for more information about GridLength
.
HorizontalOptions
is used to align a wheel inside the available WheelPicker's width, if it is larger than the wheel's width.
Alignment
is used to align the items inside a wheel.
</details>
Reference (net8-android & Xamarin.Android)
<details><summary>Click to expand</summary>
Sample usage in axml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<vapolia.WheelPicker
android:id="@+id/wheelView"
app:itemWidths="* Auto *"
app:itemAligns="Right Left Left"
app:itemHeights="15dp 15dp 15dp"
app:selectedItemTextColor="#ff228b22"
app:wp_itemTextColor="#ffffb6c1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFFFFF" />
</LinearLayout>
var wheelView = FindViewById<WheelPicker>(Resource.Id.wheelView);
wheelView.SelectedItemIndexChanged += (sender, args) =>
{
var text = $"Wheel {args.WheelIndex} selection changed to item index {args.SelectedItemIndex}";
};
wheelView.ItemsSource = new List<string> { "Monday", "Tuesday", "Wednesday" };
wheelView.SelectedItemsIndex = new [] { 0 };
vapolia.WheelPicker
Definition
- object ItemsSource (either IReadOnlyCollection<T> or IReadOnlyCollection<IReadOnlyCollection<T>>)
- IReadOnlyCollection<T> ItemsSourceSimple (shortcut for ItemsSourceMulti with one wheel)
- IReadOnlyCollection<IReadOnlyCollection<T>> ItemsSourceMulti
- int VisibleItemCount
WheelPicker Appearance
- float HorizontalSpaceBetweenWheels
- float VerticalSpaceBetweenItems
- float ItemTextSize
- Typeface ItemTextTypeface
- Color ItemTextColor
- Color ItemTextSelectedColor
- bool ShowSelectionLines
- float SelectionLinesThickness
- Color SelectionLinesColor
- bool HasFadingItems
- bool IsCurved
Appearance of a wheel (a picker can have multiple wheels)
- string ItemWidths (width of each wheel, see ItemWidths chapter below)
- IList<GravityFlags> Gravities
- GravityFlags Gravity (shortcut for Gravities[0], used only when ItemWidths is set)
- IList<double> ItemHeights
Appearance of items inside a wheel
- IList<WheelItemAlign> Alignments (same as gravities. Uses WheelItemAlign instead of GravityFlags)
- WheelItemAlign ItemAlign (shortcut for ItemAligns[0])
- IList<WheelItemAlign> ItemAligns
Selection
- ICommand SelectedItemIndexChangedCommand
- EventHandler<WheelChangedEventArgs> SelectedItemIndexChanged
- int SelectedItemIndex (shortcut for SelectedItemsIndex[0])
- IList<int> SelectedItemsIndex
Templating
- ItemsSimpleTemplates (currently reserved, used by the xamarin forms renderer)
SelectedItemsIndex
is a list of integer. Each integer represents the selected index inside a wheel.
ItemWidths
: see chapter below
Alignments
or Gravities
is used to align a wheel inside the available WheelPicker's width, if it is larger than the wheel's width.
ItemAligns
is used to align the items inside a wheel.
</details>
Reference (net8-ios & Xamarin.iOS)
<details><summary>Click to expand</summary>
On iOS, this library uses the native UIPickerView with a custom UIPickerViewModel to greatly simplify the use of this control.
Sample usage:
var picker = new UIPickerView {ShowSelectionIndicator = true, BackgroundColor = UIColor.White};
var pickerViewModel = new WheelPickerModel(picker);
picker.Model = pickerViewModel;
pickerViewModel.ItemsSource = new [] { "Monday", "Tuesday", "Wednesday" };
pickerViewModel.SelectedItemsIndex = new [] { 0 };
pickerViewModel.ItemAligns = new List<WheelItemAlign> { WheelItemAlign.Left };
Vapolia.WheelPickerIos.WheelPickerModel
Definition
- object ItemsSource (either IReadOnlyCollection<T> or IReadOnlyCollection<IReadOnlyCollection<T>>)
- IReadOnlyCollection<T> ItemsSourceSimple (shortcut for ItemsSourceMulti with one wheel)
- IReadOnlyCollection<IReadOnlyCollection<T>> ItemsSourceMulti
Appearance
- nfloat HorizontalSpaceBetweenWheels
Item appearance
- string ItemWidths
- UIFont ItemFont
- UIColor ItemTextColor
- IList<WheelItemAlign> Alignments
- IList<WheelItemAlign> ItemAligns
Selection
- ICommand SelectedItemIndexChangedCommand
- int SelectedItemIndex (shortcut for SelectedItemsIndex[0])
- IEnumerable<int> SelectedItemsIndex
Templating
- ItemsSimpleTemplates (currently reserved, used by the xamarin forms renderer)
SelectedItemsIndex
is a list of integer. Each integer represents the selected index inside a wheel.
ItemWidths
: see chapter below
Alignments
is used to align a wheel inside the available WheelPicker's width, if it is larger than the wheel's width.
ItemAligns
is used to align the items inside a wheel.
</details>
ItemWidths (net8-android and net8-ios only, excluding Maui & Xamarn Forms)
<details><summary>Click to expand</summary>
ItemWidths
is used to choose the width of each wheel. It is a space separated string consisting of a combination of float numbers, stars (optionally prepended with a float number), or the "Auto" string.
The total WheelPicker width is distributed between the wheels by respecting either :
- float number: the exact width
- Auto: the width of the largest string in ItemsSource for a given wheel (if ItemsSource contains strings)
- star: the remaining space not assigned by the above rules, distributed among the other wheels using the optional float number as a weight
Examples of ItemWidths:
"*"
: one wheel having the full width of WheelPicker"* *"
: two wheels, each of the same width, exactly half of the width of the Wheel Picker"* * *"
: three wheels, each of the same width, exactly one third of the width of the Wheel Picker"100 2* *"
: three wheels, first has a100
device pixel width, second is twice the size of the third, and3*-100=width
of the WheelPicker, which resolves to*=WheelPickerWidth-100
"* Auto *"
: three wheels, the middle wheel's width is computed from the largest string in its items source (if items source contains strings).
</details>
Supported Platforms
- Maui, net8-iOS, net8-Android, Xamarin Forms
- Android api level 15+ (Android 4.0.3+)
- iOS 8+
Mvvm friendly
The Wheel Picker provides an event and a Command when the selection changes, making it easy to use with or without mvvm frameworks.
It also implements INotifyPropertyChanged
.
Live Preview
This control supports hot reload and live preview.
Commercial Support
Enterprise support is available: contact sales
Source code is available: contact sales
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-android34.0 is compatible. net8.0-browser was computed. net8.0-ios was computed. net8.0-ios17.0 is compatible. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. |
.NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.1 is compatible. |
MonoAndroid | monoandroid was computed. monoandroid13.0 is compatible. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. xamarinios10 is compatible. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0-rc.2.23479.6)
- System.IdentityModel.Tokens.Jwt (>= 7.0.3)
- Xamarin.Forms (>= 5.0.0.2612)
-
MonoAndroid 13.0
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0-rc.2.23479.6)
- System.IdentityModel.Tokens.Jwt (>= 7.0.3)
- Xamarin.Forms (>= 5.0.0.2612)
-
net8.0
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0-rc.2.23479.6)
- Microsoft.Maui.Controls (>= 8.0.0-rc.2.9511)
- System.IdentityModel.Tokens.Jwt (>= 7.0.3)
-
net8.0-android34.0
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0-rc.2.23479.6)
- Microsoft.Maui.Controls (>= 8.0.0-rc.2.9511)
- System.IdentityModel.Tokens.Jwt (>= 7.0.3)
-
net8.0-ios17.0
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0-rc.2.23479.6)
- Microsoft.Maui.Controls (>= 8.0.0-rc.2.9511)
- System.IdentityModel.Tokens.Jwt (>= 7.0.3)
-
Xamarin.iOS 1.0
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0-rc.2.23479.6)
- System.IdentityModel.Tokens.Jwt (>= 7.0.3)
- Xamarin.Forms (>= 5.0.0.2612)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
5.0.2 | 499 | 8/27/2024 |
5.0.1 | 157 | 8/15/2024 |
5.0.1-pre9 | 628 | 1/26/2024 |
5.0.1-pre8 | 306 | 1/8/2024 |
5.0.1-pre7 | 183 | 11/2/2023 |
4.8.0 | 678 | 7/14/2022 |
4.7.2 | 866 | 5/22/2021 |
4.7.2-pre1 | 430 | 3/17/2021 |
4.7.1 | 3,772 | 9/28/2020 |
4.7.0 | 626 | 9/24/2020 |
4.6.4 | 1,049 | 8/18/2020 |
4.6.3 | 731 | 7/11/2020 |
4.6.2 | 621 | 7/10/2020 |
4.6.1 | 642 | 7/9/2020 |
4.6.0 | 819 | 5/24/2020 |
4.6.0-pre1 | 457 | 5/24/2020 |
This package supports both Maui apps and native apps (including Xamarin Forms apps).
Sample use and documentation:
https://github.com/softlion/Wheelpicker-Samples
Commercial support is available at https://vapolia.eu/
This library has no dependency on SkiaSharp, and uses only hardware accelerated low level platform calls.
It is fast, small, and reliable.
,----,
,/ .`|
,` .' : ,---, ,-.
; ; /,--.' | ,--/ /| ,---,
.'___,/ ,' | | : ,---, ,--. :/ | /_ ./| ,---. ,--,
| : | : : : ,-+-. / |: : ' / ,---, | ' : ' ,'\ ,'_ /|
; |.'; ; : | |,--. ,--.--. ,--.'|' || ' / /___/ \. : | / / | .--. | | :
`----' | | | : ' | / \ | | ,"' |' | : . \ \ ,' '. ; ,. :,'_ /| : . |
' : ; | | /' :.--. .-. | | | / | || | \ \ ; ` ,'' | |: :| ' | | . .
| | ' ' : | | | \__\/: . . | | | | |' : |. \ \ \ ' ' | .; :| | ' | | |
' : | | | ' | : ," .--.; | | | | |/ | | ' \ \ ' \ | | : |: | : ; ; |
; |.' | : :_:,'/ / ,. | | | |--' ' : |--' \ ; ; \ \ / ' : `--' \
'---' | | ,' ; : .' \| |/ ; |,' : \ \ `----' : , .-./
`--'' | , .-./'---' '--' \ ' ; `--`----'
`--`---' `--`
5.0.0
Initial release for Maui.