Home > Enterprise >  Xamarin - Custom Picker without NumberPicker
Xamarin - Custom Picker without NumberPicker

Time:05-13

I have a custom picker on my Xamarin Project and it is taking me a long time to achieve what I want.

I want my CustomPicker to display like this

enter image description here

Instead of this, as I can't get to center the words and it is quicker to select with the other one.

enter image description here

I don't want a cancel button and I have already achieve that but I can't figure out a way of having both

  • No cancel button
  • Picker view like the first image

This is my CustomPicker class

public class CustomPicker : Picker
    {
        public static readonly BindableProperty DonebuttonTextProperty = BindableProperty.Create("DonebuttonText", typeof(string),
            typeof(string), null);
        public string CancelButtonText
        {
            get { return (string)GetValue(DonebuttonTextProperty); }
            set { SetValue(DonebuttonTextProperty, value); }
        }
    }

My CustomPickerRenderer on Android


    public class CustomPickerRenderer : Xamarin.Forms.Platform.Android.AppCompat.PickerRenderer
    {
        public CustomPickerRenderer(Context context) : base(context) { }

        private IElementController ElementController => Element as IElementController;
        private AlertDialog _dialog;

        protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
        {
            base.OnElementChanged(e);

            if (e.NewElement == null || e.OldElement != null)
                return;

            Control.Click  = Control_Click;

        }
        protected override void Dispose(bool disposing)
        {
            Control.Click -= Control_Click;
            base.Dispose(disposing);
        }

        private void Control_Click(object sender, EventArgs e)
        {
            Picker model = Element;

            var picker = new NumberPicker(Context);
            if (model.Items != null && model.Items.Any())
            {
                picker.MaxValue = model.Items.Count - 1;
                picker.MinValue = 0;
                picker.SetDisplayedValues(model.Items.ToArray());
                picker.WrapSelectorWheel = false;
                picker.DescendantFocusability = DescendantFocusability.BlockDescendants;
                picker.Value = model.SelectedIndex;
            }

            var layout = new LinearLayout(Context) { Orientation = Orientation.Vertical };
            layout.AddView(picker);

            ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, true);

            var builder = new AlertDialog.Builder(Context);
            builder.SetView(layout);
            builder.SetTitle(model.Title ?? "");
            builder.SetPositiveButton("Done", (s, a) =>
            {
                ElementController.SetValueFromRenderer(Picker.SelectedIndexProperty, picker.Value);
                // It is possible for the Content of the Page to be changed on SelectedIndexChanged.
                // In this case, the Element & Control will no longer exist.
                if (Element != null)
                {
                    if (model.Items.Count > 0 && Element.SelectedIndex >= 0)
                        Control.Text = model.Items[Element.SelectedIndex];
                    ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
                    // It is also possible for the Content of the Page to be changed when Focus is changed.
                    // In this case, we'll lose our Control.
                    Control?.ClearFocus();
                }
                _dialog = null;
            });

            _dialog = builder.Create();
            _dialog.DismissEvent  = (ssender, args) =>
            {
                ElementController?.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
            };
            _dialog.Show();
        }

    }

As you can see I used Xamarin.Forms.Platform.Android.AppCompat.Picker in order to use the view that I want to display but then if I use NumberPicker it will display it like the second photo.

Please help I haven't seen any example of how to do this and I have been searching a lot. Thanks.

CodePudding user response:

If you want the picker to show like the first screenshot. You could reset the picker layout to put the items in a listview. For the separator between items in ietview, you could set the divider ro null.

Xaml:

 <Picker x:Name="picker"
Title="Select"
TitleColor="Red">
        <Picker.ItemsSource>
            <x:Array Type="{x:Type x:String}">
                <x:String>item1</x:String>
                <x:String>item2</x:String>
                <x:String>item3</x:String>
                <x:String>item4</x:String>

            </x:Array>
        </Picker.ItemsSource>
    </Picker>

Custom Renderer:

[assembly: ExportRenderer(typeof(Picker), typeof(CustomPickerRenderer2))]
namespace App1.Droid
{
public class CustomPickerRenderer2 : PickerRenderer
{
    AlertDialog listDialog;
    string[] items;
    public CustomPickerRenderer2(Context context) : base(context)
    {

    }
    protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
    {
        base.OnElementChanged(e);



        if (Control != null)
        {
            Control.Click  = Control_Click; ;
        }

    }

    private void Control_Click(object sender, EventArgs e)
    {
        Picker model = Element;
        items = model.Items.ToArray();
        AlertDialog.Builder builder = new AlertDialog.Builder(this.Context);
        builder.SetTitle(model.Title ?? "");
        builder.SetNegativeButton("Cancel", (s, a) =>
        {
            Control?.ClearFocus();
            builder = null;
        });

        Android.Views.View view = LayoutInflater.From(this.Context).Inflate(Resource.Layout.listview, null);
        Android.Widget.ListView listView = view.FindViewById<Android.Widget.ListView>(Resource.Id.listView1);

        MyAdapter myAdapter = new MyAdapter(items, Element.SelectedIndex);
        listView.Adapter = myAdapter;
        listView.ItemClick  = ListView_ItemClick;
        builder.SetView(view);
        listDialog = builder.Create();

        listDialog.Show();

    }

    private void ListView_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
    {
        Control.Text = items[e.Position];
        Element.SelectedIndex = e.Position;
        Console.WriteLine(items[e.Position]);
        listDialog.Dismiss();
        listDialog = null;
    }
}

class MyAdapter : BaseAdapter
{
    private string[] items;
    private int selectedIndex;

    public MyAdapter(string[] items)
    {
        this.items = items;
    }

    public MyAdapter(string[] items, int selectedIndex) : this(items)
    {
        this.selectedIndex = selectedIndex;
    }

    public override int Count => items.Length;

    public override Java.Lang.Object GetItem(int position)
    {
        return items[position];
    }

    public override long GetItemId(int position)
    {
        return position;
    }

    public override Android.Views.View GetView(int position, Android.Views.View convertView, ViewGroup parent)
    {
        if (convertView == null)
        {
            convertView = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.listview_item, null);
        }
        TextView textView = convertView.FindViewById<TextView>(Resource.Id.textView1);
        textView.Text = items[position];
        return convertView;
    }
}
}

listview.xml: You could creat in your Resources/layout in android project.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
     <ListView
   android:id="@ id/listView1"           
  android:divider="@null"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"/> 


</LinearLayout>

listview_item.xml : You could creat in your Resources/layout in android project.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
   <TextView
      android:id="@ id/textView1"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"/>
</LinearLayout>

enter image description here

  • Related