Xamarin.forms: Change the text of Cancel/Done button of Picker

Created on 12 Apr 2018  Â·  4Comments  Â·  Source: xamarin/Xamarin.Forms

Is there any way we can change the cancel button text of Picker? I know that you are supposed to use resx files for localization, but one of the languages I have to support is Kurdish(ckb) which is not very well supported by most operating systems. So I had to write custom localization logic, but I have trouble localizing some of the system specified strings.

screenshot_20180412-223838

l10n picker proposal-accepted enhancement âž•

Most helpful comment

You can change picker's cancel/done button text with custom renderer.

Bindable properties:

public static readonly BindableProperty DoneButtonTextProperty
public static readonly BindableProperty CancelButtonTextProperty

iOS

On iOS use DoneButtonProperty in Custom Renderer.

protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
        {
            base.OnElementChanged(e);
            if (e.NewElement == null) return;
            var customPicker = e.NewElement as CustomPicker;
            if (Control == null)
            {
                SetNativeControl(new UITextField
                {
                    RightViewMode = UITextFieldViewMode.Always,
                    ClearButtonMode = UITextFieldViewMode.WhileEditing,
                });
                SetUIButton(customPicker.DoneButtonText);
            }
            else
            {
                SetUIButton(customPicker.DoneButtonText);

            }
        }

        public void SetUIButton(string doneButtonText)
        {
            UIToolbar toolbar = new UIToolbar();
            toolbar.BarStyle = UIBarStyle.Default;
            toolbar.Translucent = true;
            toolbar.SizeToFit();
            UIBarButtonItem doneButton = new UIBarButtonItem(String.IsNullOrEmpty(doneButtonText) ? "Accept" : doneButtonText, UIBarButtonItemStyle.Done, (s, ev) =>
            {
                Control.ResignFirstResponder();

            });
            UIBarButtonItem flexible = new UIBarButtonItem(UIBarButtonSystemItem.FlexibleSpace);
            toolbar.SetItems(new UIBarButtonItem[] { doneButton,flexible }, true);
            Control.InputAccessoryView = toolbar;
        }

Android

On Android you can use both of the properties.

```
AlertDialog _dialog;
IElementController ElementController => Element as IElementController;
CustomPicker customPicker;
public CustomPickerRenderer(Context context) : base(context)
{
}

    protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
    {
        if (e.NewElement == null) return;
        customPicker = e.NewElement as CustomPicker;
        if (e.NewElement != null)
        {
            if (Control == null)
            {
                var textField = CreateNativeControl();
                textField.SetOnClickListener(CustomPickerListener.Instance);
                textField.InputType = InputTypes.Null;
                SetNativeControl(textField);
            }
        }
        base.OnElementChanged(e);
    }

    public void OnClick()
    {
        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 = Android.Views.DescendantFocusability.BlockDescendants;
            picker.Value = model.SelectedIndex;
        }

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

        ElementController.SetValueFromRenderer(VisualElement.IsFocusedPropertyKey, true);

        var builder = new AlertDialog.Builder(Context);
        builder.SetView(layout);
        builder.SetTitle(model.Title ?? "");
        builder.SetNegativeButton(customPicker.CancelButtonText ?? "Cancel", (s, a) =>
        {
            ElementController.SetValueFromRenderer(VisualElement.IsFocusedPropertyKey, false);
            _dialog = null;
        });
        builder.SetPositiveButton(customPicker.DoneButtonText ?? "Accept", (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.IsFocusedPropertyKey, false);
            }
            _dialog = null;
        });

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

    class CustomPickerListener : Java.Lang.Object, IOnClickListener
    {
        public static readonly CustomPickerListener Instance = new CustomPickerListener();

        public void OnClick(global::Android.Views.View v)
        {
            var renderer = v.Tag as CustomPickerRenderer;
            if (renderer == null)
                return;

            renderer.OnClick();
        }
    }

All 4 comments

You can change picker's cancel/done button text with custom renderer.

Bindable properties:

public static readonly BindableProperty DoneButtonTextProperty
public static readonly BindableProperty CancelButtonTextProperty

iOS

On iOS use DoneButtonProperty in Custom Renderer.

protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
        {
            base.OnElementChanged(e);
            if (e.NewElement == null) return;
            var customPicker = e.NewElement as CustomPicker;
            if (Control == null)
            {
                SetNativeControl(new UITextField
                {
                    RightViewMode = UITextFieldViewMode.Always,
                    ClearButtonMode = UITextFieldViewMode.WhileEditing,
                });
                SetUIButton(customPicker.DoneButtonText);
            }
            else
            {
                SetUIButton(customPicker.DoneButtonText);

            }
        }

        public void SetUIButton(string doneButtonText)
        {
            UIToolbar toolbar = new UIToolbar();
            toolbar.BarStyle = UIBarStyle.Default;
            toolbar.Translucent = true;
            toolbar.SizeToFit();
            UIBarButtonItem doneButton = new UIBarButtonItem(String.IsNullOrEmpty(doneButtonText) ? "Accept" : doneButtonText, UIBarButtonItemStyle.Done, (s, ev) =>
            {
                Control.ResignFirstResponder();

            });
            UIBarButtonItem flexible = new UIBarButtonItem(UIBarButtonSystemItem.FlexibleSpace);
            toolbar.SetItems(new UIBarButtonItem[] { doneButton,flexible }, true);
            Control.InputAccessoryView = toolbar;
        }

Android

On Android you can use both of the properties.

```
AlertDialog _dialog;
IElementController ElementController => Element as IElementController;
CustomPicker customPicker;
public CustomPickerRenderer(Context context) : base(context)
{
}

    protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
    {
        if (e.NewElement == null) return;
        customPicker = e.NewElement as CustomPicker;
        if (e.NewElement != null)
        {
            if (Control == null)
            {
                var textField = CreateNativeControl();
                textField.SetOnClickListener(CustomPickerListener.Instance);
                textField.InputType = InputTypes.Null;
                SetNativeControl(textField);
            }
        }
        base.OnElementChanged(e);
    }

    public void OnClick()
    {
        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 = Android.Views.DescendantFocusability.BlockDescendants;
            picker.Value = model.SelectedIndex;
        }

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

        ElementController.SetValueFromRenderer(VisualElement.IsFocusedPropertyKey, true);

        var builder = new AlertDialog.Builder(Context);
        builder.SetView(layout);
        builder.SetTitle(model.Title ?? "");
        builder.SetNegativeButton(customPicker.CancelButtonText ?? "Cancel", (s, a) =>
        {
            ElementController.SetValueFromRenderer(VisualElement.IsFocusedPropertyKey, false);
            _dialog = null;
        });
        builder.SetPositiveButton(customPicker.DoneButtonText ?? "Accept", (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.IsFocusedPropertyKey, false);
            }
            _dialog = null;
        });

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

    class CustomPickerListener : Java.Lang.Object, IOnClickListener
    {
        public static readonly CustomPickerListener Instance = new CustomPickerListener();

        public void OnClick(global::Android.Views.View v)
        {
            var renderer = v.Tag as CustomPickerRenderer;
            if (renderer == null)
                return;

            renderer.OnClick();
        }
    }

As part of this enhancement, could we also include the ability to set the text color?

Control
How to change UpdateMode from Immediately To WhenFinished

when add this line to xaml iOSSpecific:Picker.UpdateMode="WhenFinished" selected item not updated
@samhouts

Was this page helpful?
0 / 5 - 0 ratings