Wednesday, February 05, 2014

Virtual Keyboard in iOS - part 1


When you are a developer for more than one platform, you might find that what is considered basic or pre-built in one, it’s incomplete or completely missing in another one. This entry is about fixing some issues with the virtual keyboard on iOS; especially when it hides your text fields or keeps the input focus. Xamarin Studio/Mono and XCode were used for this example.


Hiding the keyboard

Tapping inside the TextField will show the keyboard, but it won't be possible to get rid of it by tapping outside or pressing “RETURN” on it. This is something pre-built in Silverlight for Windows Phone. Tapping outside of the textbox or hitting the “back” key will hide the keyboard. But well, there is no back key on the iPhone.

So let’s start by creating and extension method that we will use in the rest of the solution. The method will return the view that is the first responder or the “active” one.
public static class Extensions
 {
  public static UIView FirstResponder (this UIView view)
  {
   if (view.IsFirstResponder)
    return view;
   foreach (var child in view.Subviews)
   {
    var fs = child.FirstResponder ();
    if (fs != null)
     return fs;
   }
   return null;
  }

 }
Once it’s done, edit the code of the ViewController where the TextField is located and override the TouchesEnded method with the following implementation.
public override void TouchesEnded(NSSet touches, UIEvent evt)
  {
   var fs = this.View.FirstResponder ();
   if (fs != null)
    fs.ResignFirstResponder ();
  }
Basically the solution is to resign the focus once a touch action finished. But to complete the fix it’s necessary to do the same when the user hits the “return” key, for that a “delegate” [1]  for the TextField must be implemented. In this delegate the method ShouldReturn is overridden to surrender the focus.

public class HideOnEnterDelegate : UITextFieldDelegate
 {
  public override bool ShouldReturn (UITextField tf)
  {
   tf.ResignFirstResponder ();
   return true;
  }
 }
And back into the code of the ViewController preferably in the ViewDidLoad method (you can do it elsewhere)  assign the delegate to your text field.
public override void ViewDidLoad ()
  {
   base.ViewDidLoad ();
   
   //set the delegate for the TextField
   textField.Delegate = new HideOnEnterDelegate ();
  }
At this point the text field behavior is more natural, giving it focus will show the keyboard, taking focus away by tapping outside will now hide the keyboard and so will do the "RETURN" key.

That's it for now, round two will cover the more complicated issue when the keyboard overlays on top of the input text fields. And will include the full source code for this example app.

[1] The term delegate here is not related to C# delegates, but to the objective-C delegation pattern, for more see here.

No comments: