xamarin / XamarinCommunityToolkit

The Xamarin Community Toolkit is a collection of Animations, Behaviors, Converters, and Effects for mobile development with Xamarin.Forms. It simplifies and demonstrates common developer tasks building iOS, Android, and UWP apps with Xamarin.Forms.
MIT License
1.59k stars 475 forks source link

[Enhancement] Multi-column picker #358

Closed djordje200179 closed 2 years ago

djordje200179 commented 3 years ago

Summary

Sometimes developers want to use a single picker to pick multiple values.

Examples

  1. Credit card expiration date uses Months and Years columns and you can't use DatePicker because it has an extra column (column for Days is not needed)
  2. US Height measurement system uses feets and inches, and they usually use values between 0 and 12, so this simple picker could be useful.

Implementation I have already created the control for my own needs. I have implemented the control for Android and UWP, so someone else needs to implement the control for iOS. Pretty much everything works correctly (only minor fixes are needed), so it will be easy for me to create and submit the pull request.

Native controls The control is inherited from the built-in Picker control, so the control will look exactly same as built-in Picker looks, Material visual is already supported for Android.

Popup is shown using:

Screenshots

Screenshot_1601663202 Screenshot_1601663217 Screenshot_1601663220 image

API Changes

New view will be created:

public class MulticolumnPicker : Picker {
        public static new readonly BindableProperty SelectedIndexProperty = BindableProperty.Create(nameof(SelectedIndex), typeof(IList<int>), typeof(MulticolumnPicker), new List<int>(), BindingMode.TwoWay, propertyChanged: OnSelectedIndexChanged);

        public static new readonly BindableProperty SelectedItemProperty = BindableProperty.Create(nameof(SelectedItem), typeof(IList), typeof(MulticolumnPicker), new List<object>(), BindingMode.TwoWay, propertyChanged: OnSelectedItemChanged);

public static new readonly BindableProperty MaskProperty = BindableProperty.Create(nameof(Mask), typeof(string), typeof(MulticolumnPicker), default, BindingMode.TwoWay, propertyChanged: OnMaskChanged);

        public new ObservableCollection<IList> Items { get; } = new ObservableCollection<IList>();

        public new event EventHandler<SelectedIndexesEventArgs> SelectedIndexChanged;

        ....
 }

How to use in XAML

<controls:MulticolumnPicker Title="Expiration date" SelectedItem="{Binding Item.ExpiryDate, Mode=TwoWay, Converter={StaticResource ListToExpiryDateConverter}}" Mask="{0} / {1}">
    <controls:MulticolumnPicker.Items>
        <scg:List x:TypeArguments="x:String">
            <x:String>01</x:String>
            <x:String>02</x:String>
            <x:String>03</x:String>
            <x:String>04</x:String>
            <x:String>05</x:String>
            <x:String>06</x:String>
            <x:String>07</x:String>
            <x:String>08</x:String>
            <x:String>09</x:String>
            <x:String>10</x:String>
            <x:String>11</x:String>
            <x:String>12</x:String>
        </scg:List>

        <scg:List x:TypeArguments="x:String">
            <x:String>18</x:String>
            <x:String>19</x:String>
            <x:String>20</x:String>
            <x:String>21</x:String>
            <x:String>22</x:String>
            <x:String>23</x:String>
            <x:String>24</x:String>
            <x:String>25</x:String>
            <x:String>26</x:String>
            <x:String>27</x:String>
            <x:String>28</x:String>
            <x:String>29</x:String>
        </scg:List>
    </controls:MulticolumnPicker.Items>
</controls:MulticolumnPicker>
SkyeHoefling commented 3 years ago

This seems useful, but I am not sure if it makes sense to have 2 competing controls in the toolkit.

Popup is shown using: Android: AlertDialog with NumberPickers UWP: Flyout with ListBoxes iOS: UIPickerView

The Popup Control #292 uses the exact same native controls for both Android and UWP. Once we have the Popup Control, it should be simple to include the specific logic you are requesting as shared Xamarin.Forms code. Currently I am waiting for v5.0.0 support in the toolkit to properly support the Popup Control.

Could you elaborate how this will differ from the Popup Control? As this is written it seems very targeted at displaying a list of information in a popup which can be accomplished using the Popup Control.

djordje200179 commented 3 years ago

You could ask exactly same question about built-in Picker control...

This is used as extended Picker and it uses native picking controls (NumberPicker on Android and UIPickerView on IOS)... unlike situation in which you used new Popup control and created your own view that would be preety complex and it wouldn't be so easy to transfer data between Entry and Popup

SkyeHoefling commented 3 years ago

@djordje200179 Thank you for updating the description with more screenshots and explanation of your proposal. Originally I thought it was a Multi-Line control that added multiple entry controls to a popup. As opposed to a date/year picker or feet/inches picker that has 2 vertical pickers the user can scroll through at the same time. I am not sure if this control is a common control that makes sense for the toolkit, but it definitely has value to developers that need it. I will defer to the decision makers and other community members about the value of contributing this.

I am still finding the documentation to this Enhancement confusing as far as what properties, events, and classes need to be added. You mentioned that your current implementation is sub-classed the existing Picker control, but it will be useful to have more information on what all that means. Could you update your description to include a table of properties and events with descriptions. I have added an example of what I think should be added from what I can determine from reading the description as it is today. I didn't fill out any descriptions intentionally and would love to see what each property is supposed to do.

Properties Property Type Description
Mask string
Items ObservableCollection<IList>
SelectedIndex unknown
SelectedItem object
Title string
Events Event Description
SelectedIndexChanged
SelectedItemChanged (this wasn't listed, but if we have a SelectedItem property we should probably have an event for it)

Important Question to Maintainers

As far as I can tell we do not have any controls in the toolkit that subclass existing Xamarin.Forms controls. The closest thing we have is a specification that will be using effects to gain access to the native control. I think for a control such as this it makes sense to either subclass or build our own custom renderer.

Cfun1 commented 3 years ago

@jfversluis This issue needs the Label "needs-approval" if it has not yet been approved. (when opened was using the old GitHub feature-request template)

brminnick commented 2 years ago

Thanks! However, we are no longer adding new features to Xamarin Community Toolkit, focusing on the .NET MAUI Community Toolkit.

Please open a New Feature Discussion to implement this feature in the .NET MAUI Community Toolkit.

I've posted more information about the Future Of Xamarin Community Toolkit here: https://devblogs.microsoft.com/xamarin/the-future-of-xamarin-community-toolkit/?WT.mc_id=mobile-0000-bramin

rushabhshah97 commented 5 months ago

Summary

Sometimes developers want to use a single picker to pick multiple values.

Examples 1. Credit card expiration date uses Months and Years columns and you can't use DatePicker because it has an extra column (column for Days is not needed) 2. US Height measurement system uses feets and inches, and they usually use values between 0 and 12, so this simple picker could be useful.

Implementation I have already created the control for my own needs. I have implemented the control for Android and UWP, so someone else needs to implement the control for iOS. Pretty much everything works correctly (only minor fixes are needed), so it will be easy for me to create and submit the pull request.

Native controls The control is inherited from the built-in Picker control, so the control will look exactly same as built-in Picker looks, Material visual is already supported for Android.

Popup is shown using:

  • Android: AlertDialogwith NumberPickers
  • UWP: Flyoutwith ListBoxes
  • iOS: UIPickerView

Screenshots

Screenshot_1601663202 Screenshot_1601663217 Screenshot_1601663220 image

API Changes

New view will be created:

public class MulticolumnPicker : Picker {
      public static new readonly BindableProperty SelectedIndexProperty = BindableProperty.Create(nameof(SelectedIndex), typeof(IList<int>), typeof(MulticolumnPicker), new List<int>(), BindingMode.TwoWay, propertyChanged: OnSelectedIndexChanged);

      public static new readonly BindableProperty SelectedItemProperty = BindableProperty.Create(nameof(SelectedItem), typeof(IList), typeof(MulticolumnPicker), new List<object>(), BindingMode.TwoWay, propertyChanged: OnSelectedItemChanged);

public static new readonly BindableProperty MaskProperty = BindableProperty.Create(nameof(Mask), typeof(string), typeof(MulticolumnPicker), default, BindingMode.TwoWay, propertyChanged: OnMaskChanged);

      public new ObservableCollection<IList> Items { get; } = new ObservableCollection<IList>();

      public new event EventHandler<SelectedIndexesEventArgs> SelectedIndexChanged;

      ....
 }

How to use in XAML

<controls:MulticolumnPicker Title="Expiration date" SelectedItem="{Binding Item.ExpiryDate, Mode=TwoWay, Converter={StaticResource ListToExpiryDateConverter}}" Mask="{0} / {1}">
  <controls:MulticolumnPicker.Items>
      <scg:List x:TypeArguments="x:String">
          <x:String>01</x:String>
          <x:String>02</x:String>
          <x:String>03</x:String>
          <x:String>04</x:String>
          <x:String>05</x:String>
          <x:String>06</x:String>
          <x:String>07</x:String>
          <x:String>08</x:String>
          <x:String>09</x:String>
          <x:String>10</x:String>
          <x:String>11</x:String>
          <x:String>12</x:String>
      </scg:List>

      <scg:List x:TypeArguments="x:String">
          <x:String>18</x:String>
          <x:String>19</x:String>
          <x:String>20</x:String>
          <x:String>21</x:String>
          <x:String>22</x:String>
          <x:String>23</x:String>
          <x:String>24</x:String>
          <x:String>25</x:String>
          <x:String>26</x:String>
          <x:String>27</x:String>
          <x:String>28</x:String>
          <x:String>29</x:String>
      </scg:List>
  </controls:MulticolumnPicker.Items>
</controls:MulticolumnPicker>

@djordje200179 Can you please share the control logic on GitHub or any other platform? I need it for my project.