Forum Xamarin.Android
We are excited to announce that the Xamarin Forums are moving to the new Microsoft Q&A experience. Q&A is the home for technical questions and answers at across all products at Microsoft now including Xamarin!

We encourage you to head over to Microsoft Q&A for .NET for posting new questions and get involved today.

How to create a Custom Picker that displays the same alert dialog as the standard Picker

dapiggdapigg Member

I needed to create a custom picker for Android with rounded corners so I created a CustomPicker class and a CustomPickerRenderer class. The Picker now displays the way I want it but when I click it the alert / selection dialog looks nothing like the dialog that the standard Picker uses. I would have thought that I was extending the Picker class and that it should appear the same. How do I get the dialog to look like the standard?

CustomPickerRenderer.cs

using Android.Content;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using AdvancedMD.Mobile.Connect.CustomControls;
using Android.Support.V4.Content.Res;
using AdvancedMD.Mobile.Connect.Droid.CustomControls;

[assembly: ExportRenderer(typeof(CustomPicker), typeof(CustomPickerRenderer))]
namespace AdvancedMD.Mobile.Connect.Droid.CustomControls {

public class CustomPickerRenderer : PickerRenderer {

public CustomPickerRenderer(Context context) : base(context) {
}

protected override void OnElementChanged(ElementChangedEventArgs<Picker> e) {
  base.OnElementChanged(e);
  if (Control != null) {
    Control.SetBackground(ResourcesCompat.GetDrawable(Resources, Resource.Layout.RoundedCornerEntry, null));
  }
}

}
}

CaptureChallengeSettingsView.xaml (excerpt)

      <controls:CustomPicker Title="Select Security Question" TitleColor="#93A3B3" TextColor="White"
              HorizontalOptions="FillAndExpand" BackgroundColor="#476075"
              ItemsSource="{Binding Selections}" SelectedItem="{Binding Question1SelectedItem}" />
      <Picker Title="Basic Picker" TitleColor="#93A3B3" TextColor="White"
              HorizontalOptions="FillAndExpand" BackgroundColor="#476075"
              ItemsSource="{Binding Selections}" SelectedItem="{Binding Question1SelectedItem}" />

Custom rendered Picker:

Standard Picker:

Best Answer

  • dapiggdapigg Member
    Accepted Answer

    It looks like the base Picker for Android uses Xamarin.Forms.Platform.Android.AppCompat so I resolved this by using the IPickerRenderer.onClick() code and implementing it in my custom renderer to get the same look and feel.

    void IPickerRenderer.OnClick() {
      CustomPicker model = (CustomPicker)Element;
      if (_dialog == null) {
        using (var builder = new AlertDialog.Builder(Context)) {
          if (!Element.IsSet(CustomPicker.TitleColorProperty)) {
            builder.SetTitle(model.Title ?? "");
          }
          else {
            var title = new SpannableString(model.Title ?? "");
            title.SetSpan(new ForegroundColorSpan(model.TitleColor.ToAndroid()), 0, title.Length(), SpanTypes.ExclusiveExclusive);
    
            builder.SetTitle(title);
          }
    
          string[] items = model.Items.ToArray();
          builder.SetItems(items, (s, e) => ((IElementController)model).SetValueFromRenderer(CustomPicker.SelectedIndexProperty, e.Which));
    
          builder.SetNegativeButton(global::Android.Resource.String.Cancel, (o, args) => { });
    
          ((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();
      }
    }
    
    protected override void OnFocusChangeRequested(object sender, VisualElement.FocusRequestArgs e) {
      base.OnFocusChangeRequested(sender, e);
    
      if (e.Focus) {
        if (Clickable)
          CallOnClick();
        else
          ((IPickerRenderer)this)?.OnClick();
      }
      else if (_dialog != null) {
        _dialog.Hide();
        ((IElementController)Element).SetValueFromRenderer(VisualElement.IsFocusedPropertyKey, false);
        Control.ClearFocus();
        _dialog = null;
      }
    }
    

Answers

  • jezhjezh Member, Xamarin Team Xamurai

    Based on my test, when we used the PickerRenderer without adding other code, it still has such result.So it should be the Picker renderer have changed the Picker style.

     public class CustomPickerRenderer : PickerRenderer
        {
            public CustomPickerRenderer(Context context) : base(context)
            {
            }
        }
    
  • dapiggdapigg Member
    Accepted Answer

    It looks like the base Picker for Android uses Xamarin.Forms.Platform.Android.AppCompat so I resolved this by using the IPickerRenderer.onClick() code and implementing it in my custom renderer to get the same look and feel.

    void IPickerRenderer.OnClick() {
      CustomPicker model = (CustomPicker)Element;
      if (_dialog == null) {
        using (var builder = new AlertDialog.Builder(Context)) {
          if (!Element.IsSet(CustomPicker.TitleColorProperty)) {
            builder.SetTitle(model.Title ?? "");
          }
          else {
            var title = new SpannableString(model.Title ?? "");
            title.SetSpan(new ForegroundColorSpan(model.TitleColor.ToAndroid()), 0, title.Length(), SpanTypes.ExclusiveExclusive);
    
            builder.SetTitle(title);
          }
    
          string[] items = model.Items.ToArray();
          builder.SetItems(items, (s, e) => ((IElementController)model).SetValueFromRenderer(CustomPicker.SelectedIndexProperty, e.Which));
    
          builder.SetNegativeButton(global::Android.Resource.String.Cancel, (o, args) => { });
    
          ((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();
      }
    }
    
    protected override void OnFocusChangeRequested(object sender, VisualElement.FocusRequestArgs e) {
      base.OnFocusChangeRequested(sender, e);
    
      if (e.Focus) {
        if (Clickable)
          CallOnClick();
        else
          ((IPickerRenderer)this)?.OnClick();
      }
      else if (_dialog != null) {
        _dialog.Hide();
        ((IElementController)Element).SetValueFromRenderer(VisualElement.IsFocusedPropertyKey, false);
        Control.ClearFocus();
        _dialog = null;
      }
    }
    
  • jezhjezh Member, Xamarin Team Xamurai

    Congrats, and thanks for sharing the answer. Could you please mark it as an answer so that it could help others who have the similar question? Thanks.

  • LyndonHugheyLyndonHughey USUniversity ✭✭✭

    Thank you for this. You saved me lots of time and frustration!

Sign In or Register to comment.