locked
Add 'Done' button to keyboard on iOS RRS feed

  • Question

  • User45170 posted

    How does one add a 'Done' button to a keyboard when editing an Entry on Xamarin.Forms? (iOS only)

    I'm not sure how to write a renderer for this and wire that to a Keyboard on Xamarin.Forms.

    Thursday, June 12, 2014 4:19 PM

All replies

  • User311 posted

    This should be it, assuming that all Entry elements now get this keyboard (as I think MonoTouch.Dialog does by default):

    [assembly: ExportRenderer(typeof(Entry), typeof(DoneEntryRenderer))]
    namespace MyProject.iOS.Renderers
    {
        public class DoneEntryRenderer : EntryRenderer
        {
            protected override void OnModelSet(VisualElement model)
            {
                base.OnModelSet(model);
                var textField = (UITextField)this.Control;
                textField.ReturnKeyType = UIReturnKeyType.Done;
            }
        }
    }
    
    Thursday, June 12, 2014 6:34 PM
  • User39602 posted

    I think that's not exactly what he was looking for. Instead, try setting the InputAccessoryView property of the UITextField to a UIView that contains the widgets you need.

    Friday, June 13, 2014 12:21 PM
  • User45170 posted

    Thanks much René, that's what I was looking for. With your hint and the following article I was able to implement what I needed ;-)

    http://nnish.com/2013/12/02/adding-custom-buttons-to-ios-keyboard-in-c-xamarin/

    Saturday, June 14, 2014 7:19 PM
  • User55936 posted

    Pedro, Can you share the code you used to add the InputAccessoryView to an Xamarin.Forms.Edit control? I have like 50 fields on my various pages and I want to automatically add the InputAccessoryView to each of them, including a picker view if possible.

    Thanks

    Friday, July 18, 2014 6:05 PM
  • User45170 posted

    I can't share the exact code I'm using as that code is actually my client's code, but here is the idea:

    Have a new Entry that extends Xamarin.Forms' Entry, like class MyEntry : Entry and create a custom renderer for it that extends EntryRenderer, like class MyEntryRenderer : EntryRenderer and on the OnElementChanged method you can set this.Control.InputAccessoryView to any UIView. You can follow this link to create an appropriate UIToolbar to set it here.

    Then in your app just reference MyEntry instead of Entry and if the renderer is implemented correctly you'll see that the InputAccessoryView appears.

    [assembly: ExportRenderer(typeof(MyEntry), typeof(MyEntryRenderer))]
    namespace MyProject.iOS.Renderers
    {
        public class MyEntryRenderer : EntryRenderer
        {
            protected override void OnElementChanged(ElementChangedEventArgs<Entry> args) {
            {
                base.OnElementChanged(args);
                this.Control.InputAccessoryView = (...) ; // do your magic here
            }
        }
    }
    
    Friday, July 18, 2014 6:33 PM
  • User55936 posted

    Thanks with this and about 4 other posts I was able to get a custom view with the close button (and a bunch of other fun buttons that I'm going to remove) working with Xamarin.Forms

    Friday, July 18, 2014 11:28 PM
  • User51075 posted

    With the information on this post, I was able to get this working in iOS, but I need to be able to replicate this functionality on Android. Can this be done in a similar fashion for Android by modifying the Renderer?

    Thanks, Doug

    Wednesday, September 17, 2014 10:35 PM
  • User28744 posted

    It was necessary to write my own renderer for Entry, so here is full code (all YOU need to do is just change your namespace :))...

    using Xamarin.Forms;
    using Xamarin.Forms.Platform.iOS;
    using MonoTouch.UIKit;
    using System.Drawing;
    
    
    [assembly: ExportRenderer(typeof(Entry), typeof(Example.Renderers.CustomEntryRenderer))]
    
    namespace Example.Renderers
    {
        public class CustomEntryRenderer : EntryRenderer
        {
            protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
            {
                base.OnElementChanged(e);
    
                // Check for only Numeric keyboard
                if (this.Element.Keyboard == Keyboard.Numeric) {
                    this.AddDoneButton ();
                }
            }
    
            /// <summary>
            /// Add toolbar with Done button
            /// </summary>
            protected void AddDoneButton()
            {
                UIToolbar toolbar = new UIToolbar (new RectangleF (0.0f, 0.0f, 50.0f, 44.0f));
    
                var doneButton = new UIBarButtonItem (UIBarButtonSystemItem.Done, delegate {
                    this.Control.ResignFirstResponder ();
                });
    
                toolbar.Items = new UIBarButtonItem[] {
                    new UIBarButtonItem (UIBarButtonSystemItem.FlexibleSpace),
                    doneButton
                };
                this.Control.InputAccessoryView = toolbar;
            }
        }
    }
    
    Friday, October 10, 2014 9:03 AM
  • User219765 posted

    public EntryDoneRenderer () { }

    protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
    {
        base.OnElementChanged (e);
    
        if (this.Element.Keyboard == Keyboard.Numeric) 
        {
            // only want the Done on the numeric keyboard type
            UIToolbar toolbar = new UIToolbar (new RectangleF (0.0f, 0.0f, (float)Control.Frame.Size.Width, 44.0f));
    
            var doneButton = new UIBarButtonItem (UIBarButtonSystemItem.Done, delegate {
                this.Control.ResignFirstResponder ();
                Type baseEntry = this.Element.GetType();
                if(baseEntrySendCompleted==null)
                    // use reflection to find our method
                    baseEntrySendCompleted = baseEntry.GetMethod("SendCompleted",BindingFlags.NonPublic|BindingFlags.Instance);
                    baseEntrySendCompleted.Invoke(this.Element,null);            });
    
            toolbar.Items = new UIBarButtonItem[] {  new UIBarButtonItem (UIBarButtonSystemItem.FlexibleSpace),doneButton   };
            this.Control.InputAccessoryView = toolbar;
        }
    }
    

    }

    Monday, May 9, 2016 12:45 PM
  • User181025 posted

    @VinayKumar.9706 I'm getting null for the SendCompleted event. It used to work but not anymore.

    Saturday, July 30, 2016 3:15 AM
  • User72380 posted

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

        var toolbar = new UIToolbar(new CGRect(0.0f, 0.0f, Control.Frame.Size.Width, 44.0f));
    
        toolbar.Items = new[]
        {
            new UIBarButtonItem(UIBarButtonSystemItem.FlexibleSpace),
            new UIBarButtonItem(UIBarButtonSystemItem.Done, delegate {
                Control.ResignFirstResponder();
                ((IEntryController)Element).SendCompleted();
            })
        };
    
        this.Control.InputAccessoryView = toolbar;
    }
    
    Friday, October 7, 2016 9:53 PM
  • User76049 posted

    @rocharocha

    Wasn't working in iOS 10 for me, thanks for posting that code.

    Monday, October 31, 2016 4:04 PM
  • User181025 posted

    @PedroLima @PaulDivan I have a PR sitting to make this easier: https://github.com/xamarin/Xamarin.Forms/pull/407

    Tuesday, November 1, 2016 5:49 PM
  • User89714 posted

    Has anybody done the equivalent on UWP, to provide a Done button on UWP phones?

    Monday, February 27, 2017 5:04 PM
  • User313602 posted

    I created a gist based on @"PavelPenkava.8634" answer: https://gist.github.com/yuv4ik/4592401836bd6bc54ac85fcc5cdbaa2f

    Friday, May 5, 2017 2:01 PM