Change texts in Xamarin.Forms views independently from OS settings

JonAlzaJonAlza ESMember ✭✭

Hello,

I have an app only in English language, but my phone's OS is in Spanish. I have added a Picker to my page and if I tap it to change it's value, I see that cancel button text is in Spanish. I want to show this button in English. I'm using Xamarin.Forms because it's easier for me to develop with it, but I just need to know how I can make this change in Android. I tried this in OnCreate() method in the MainActivity, but it doen't work.

Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("en");
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;

The text of the button is still in Spanish. Do you know how can I change this text?

Thank you,
Jon.

Best Answer

  • JonAlzaJonAlza ES ✭✭
    edited November 2017 Accepted Answer

    I have managed to set the text on the negative button. I created CustomPicker and a CustomPickerRenderer:

    CustomPicker.cs (nothing special):

    public class CustomPicker : Picker {}
    

    CustomPickerRenderer.cs (inherited from Xamarin.Forms.Platform.Android.AppCompat.PickerRenderer and copying some methods from it with a few changes):

    using Android.App;
    using Android.Content;
    using Android.Content.Res;
    using Android.Text;
    using Android.Widget;
    using RendererTest.Droid.Renderers;
    using System;
    using System.Collections.Specialized;
    using System.Linq;
    using Xamarin.Forms;
    using Xamarin.Forms.Platform.Android;
    
    [assembly: ExportRenderer(typeof(RendererTest.Controls.CustomPicker), typeof(CustomPickerRenderer))]
    namespace RendererTest.Droid.Renderers
    {
        public class CustomPickerRenderer : Xamarin.Forms.Platform.Android.AppCompat.PickerRenderer
        {
            AlertDialog _dialog;
            TextColorSwitcher _textColorSwitcher;
    
            public CustomPickerRenderer(Context context) : base(context) { }
    
            // This method is necessary to set the OnClickListener, copied removing base.OnElementChanged(e); line
            protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
            {
                if (e.OldElement != null)
                    ((INotifyCollectionChanged)e.OldElement.Items).CollectionChanged -= RowsCollectionChanged;
    
                if (e.NewElement != null)
                {
                    ((INotifyCollectionChanged)e.NewElement.Items).CollectionChanged += RowsCollectionChanged;
                    if (Control == null)
                    {
                        EditText textField = CreateNativeControl();
                        textField.Focusable = false;
                        textField.Clickable = true;
                        textField.Tag = this;
                        textField.InputType = InputTypes.Null;
                        textField.SetOnClickListener(PickerListener.Instance);
                        _textColorSwitcher = new TextColorSwitcher(textField.TextColors);
                        SetNativeControl(textField);
                    }
                    UpdatePicker();
                    UpdateTextColor();
                }
            }
    
            // This method is necessary to change negative button text.
            void OnClick()
            {
                Picker model = Element;
                if (_dialog == null)
                {
                    using (var builder = new AlertDialog.Builder(Context))
                    {
                        builder.SetTitle(model.Title ?? "");
                        string[] items = model.Items.ToArray();
                        builder.SetItems(items, (s, e) => ((IElementController)model).SetValueFromRenderer(Picker.SelectedIndexProperty, e.Which));
    
                        builder.SetNegativeButton("Cancel", (o, args) => { }); // Changing negative button text
    
                        ((IElementController)Element).SetValueFromRenderer(VisualElement.IsFocusedPropertyKey, true);
    
                        _dialog = builder.Create();
                    }
                    _dialog.SetCanceledOnTouchOutside(true);
                    _dialog.DismissEvent += (sender, args) =>
                    {
                        (Element as IElementController)?.SetValueFromRenderer(VisualElement.IsFocusedPropertyKey, false);
                        _dialog.Dispose();
                        _dialog = null;
                    };
    
                    _dialog.Show();
                }
            }
    
            void RowsCollectionChanged(object sender, EventArgs e)
            {
                UpdatePicker();
            }
    
            void UpdatePicker()
            {
                Control.Hint = Element.Title;
    
                if (Element.SelectedIndex == -1 || Element.Items == null)
                    Control.Text = null;
                else
                    Control.Text = Element.Items[Element.SelectedIndex];
            }
    
            void UpdateTextColor()
            {
                _textColorSwitcher?.UpdateTextColor(Control, Element.TextColor);
            }
    
            // The listener is changed to work with CustomPickerRenderer
            class PickerListener : Java.Lang.Object, IOnClickListener
            {
                #region Statics
    
                public static readonly PickerListener Instance = new PickerListener();
    
                #endregion
    
                public void OnClick(global::Android.Views.View v)
                {
                    var renderer = v.Tag as CustomPickerRenderer; // Work with my renderer
                    renderer?.OnClick();
                }
            }
        }
    }
    

    Also it is necessary to add the TextColorSwitcher class to the source code.

Answers

  • seanydaseanyda GBMember ✭✭✭✭✭

    Check out here:
    https://developer.xamarin.com/guides/xamarin-forms/advanced/localization/#Windows_Application_Projects

    It has the information available on how to update iOS and Android Picker too above this section.

  • JonAlzaJonAlza ESMember ✭✭

    I know how to use resources. I used resources in other multi-language app. In this case I want to change an specific text, but there is no public property that gives me access to change it (i.e. picker.CancelButtonText).

    I tried changing Java.Util.Locale.Default = new Java.Util.Locale("en");, but it doesn't work. The button is displaying in Spanish.

  • JonAlzaJonAlza ESMember ✭✭

    I've checked the PickerRender.cs file and I found this code:

    var builder = new AlertDialog.Builder(Context);
    builder.SetView(layout);
    builder.SetTitle(model.Title ?? "");
    builder.SetNegativeButton(global::Android.Resource.String.Cancel, (s, a) =>
    {
        ElementController.SetValueFromRenderer(VisualElement.IsFocusedPropertyKey, false);
        // It is 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;
    });
    

    global::Android.Resource.String.Cancel is a int constant, so I can't change it. Do you know you if there is access to the negative button text?

  • JonAlzaJonAlza ESMember ✭✭
    edited November 2017 Accepted Answer

    I have managed to set the text on the negative button. I created CustomPicker and a CustomPickerRenderer:

    CustomPicker.cs (nothing special):

    public class CustomPicker : Picker {}
    

    CustomPickerRenderer.cs (inherited from Xamarin.Forms.Platform.Android.AppCompat.PickerRenderer and copying some methods from it with a few changes):

    using Android.App;
    using Android.Content;
    using Android.Content.Res;
    using Android.Text;
    using Android.Widget;
    using RendererTest.Droid.Renderers;
    using System;
    using System.Collections.Specialized;
    using System.Linq;
    using Xamarin.Forms;
    using Xamarin.Forms.Platform.Android;
    
    [assembly: ExportRenderer(typeof(RendererTest.Controls.CustomPicker), typeof(CustomPickerRenderer))]
    namespace RendererTest.Droid.Renderers
    {
        public class CustomPickerRenderer : Xamarin.Forms.Platform.Android.AppCompat.PickerRenderer
        {
            AlertDialog _dialog;
            TextColorSwitcher _textColorSwitcher;
    
            public CustomPickerRenderer(Context context) : base(context) { }
    
            // This method is necessary to set the OnClickListener, copied removing base.OnElementChanged(e); line
            protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
            {
                if (e.OldElement != null)
                    ((INotifyCollectionChanged)e.OldElement.Items).CollectionChanged -= RowsCollectionChanged;
    
                if (e.NewElement != null)
                {
                    ((INotifyCollectionChanged)e.NewElement.Items).CollectionChanged += RowsCollectionChanged;
                    if (Control == null)
                    {
                        EditText textField = CreateNativeControl();
                        textField.Focusable = false;
                        textField.Clickable = true;
                        textField.Tag = this;
                        textField.InputType = InputTypes.Null;
                        textField.SetOnClickListener(PickerListener.Instance);
                        _textColorSwitcher = new TextColorSwitcher(textField.TextColors);
                        SetNativeControl(textField);
                    }
                    UpdatePicker();
                    UpdateTextColor();
                }
            }
    
            // This method is necessary to change negative button text.
            void OnClick()
            {
                Picker model = Element;
                if (_dialog == null)
                {
                    using (var builder = new AlertDialog.Builder(Context))
                    {
                        builder.SetTitle(model.Title ?? "");
                        string[] items = model.Items.ToArray();
                        builder.SetItems(items, (s, e) => ((IElementController)model).SetValueFromRenderer(Picker.SelectedIndexProperty, e.Which));
    
                        builder.SetNegativeButton("Cancel", (o, args) => { }); // Changing negative button text
    
                        ((IElementController)Element).SetValueFromRenderer(VisualElement.IsFocusedPropertyKey, true);
    
                        _dialog = builder.Create();
                    }
                    _dialog.SetCanceledOnTouchOutside(true);
                    _dialog.DismissEvent += (sender, args) =>
                    {
                        (Element as IElementController)?.SetValueFromRenderer(VisualElement.IsFocusedPropertyKey, false);
                        _dialog.Dispose();
                        _dialog = null;
                    };
    
                    _dialog.Show();
                }
            }
    
            void RowsCollectionChanged(object sender, EventArgs e)
            {
                UpdatePicker();
            }
    
            void UpdatePicker()
            {
                Control.Hint = Element.Title;
    
                if (Element.SelectedIndex == -1 || Element.Items == null)
                    Control.Text = null;
                else
                    Control.Text = Element.Items[Element.SelectedIndex];
            }
    
            void UpdateTextColor()
            {
                _textColorSwitcher?.UpdateTextColor(Control, Element.TextColor);
            }
    
            // The listener is changed to work with CustomPickerRenderer
            class PickerListener : Java.Lang.Object, IOnClickListener
            {
                #region Statics
    
                public static readonly PickerListener Instance = new PickerListener();
    
                #endregion
    
                public void OnClick(global::Android.Views.View v)
                {
                    var renderer = v.Tag as CustomPickerRenderer; // Work with my renderer
                    renderer?.OnClick();
                }
            }
        }
    }
    

    Also it is necessary to add the TextColorSwitcher class to the source code.

Sign In or Register to comment.