Click here to Skip to main content
Click here to Skip to main content
Technical Blog

Tagged as

Virtual Keyboard in iOS - Part 2

, 15 Mar 2014 CPOL
Rate this:
Please Sign up or sign in to vote.
Virtual Keyboard in iOS - Part 2

Introduction

In one the first entries of this series, I covered the issues with the keyboard in iOS not hiding automatically when needed. In this second - and final - entry on the subject, I am going to go for the most annoying issue when creating UIs in iOS.


The Keyboard Overlaps a Focused TextField

If you have a TextField below the keyboard top edge position, they will be hidden once the keyboard shows up. The keyboard size is 320x216 points* in portrait mode, so anything below the 264 (iPhone 4/4s) or 352 (iPhone 5/5s) points won’t be visible. It is so simple that is almost unbelievable, but it happens as you can see in the images. Since this default behavior is inconvenient, we are going for the workaround.

The solution is not pretty, but it is trivial: we need to place the UI elements inside a UIScrollView and will use notifications to monitor when the keyboard will Show/Hide and will scroll the content of the container to ensure that views inside are always visible. We are using Xamarin and Xcode to develop this example. The first step is to subscribe to the notifications:

public override void ViewWillDisappear (bool animated)
{
 base.ViewWillDisappear (animated);
 UnregisterNotifications ();
}

public override void ViewWillAppear (bool animated)
{
 base.ViewWillAppear (animated);
 this.scrollView.ContentSize = new SizeF (320, 400);
 RegisterNotifications ();
}

NSObject _keyboardWillShow;
NSObject _keyboardWillHide;

protected  void RegisterNotifications ()
{
 _keyboardWillShow = NSNotificationCenter.DefaultCenter.AddObserver (UIKeyboard.WillShowNotification, WillShow);
 _keyboardWillHide = NSNotificationCenter.DefaultCenter.AddObserver (UIKeyboard.WillHideNotification, WillHide);
}

protected  void UnregisterNotifications ()
{
 NSNotificationCenter.DefaultCenter.RemoveObserver (_keyboardWillShow);
 NSNotificationCenter.DefaultCenter.RemoveObserver (_keyboardWillHide);
}

There is also an outlet called scrollView to access our container and on the ViewWillAppear method, we set the ContentSize of the container. You should adjust this value to your specific UI layout.

The NSNotificationCenter is a singleton that will allows us to register for notifications, which are essentially events. We will register for two specific notifications on the ViewWillAppear and unregister them on the ViewWillDisapear.

The trickiest part is the WillShow event, in this case the actions are:

  • Get the area above the keyboard.
  • Get the area of the active view.
  • If those areas intersect (meaning it is not 100% visible), then we scroll to ensure the active view is completely visible.
protected void WillShow (NSNotification notification)
{
 var activeView = this.View.FirstResponder ();
 if (activeView == null)
  return;    

 //get keyboard bounds
 var keyboardBounds = UIKeyboard.FrameBeginFromNotification (notification);

 var contentInsets = new UIEdgeInsets (0.0f, 0.0f, keyboardBounds.Size.Height, 0.0f);
 scrollView.ContentInset = contentInsets;
 scrollView.ScrollIndicatorInsets = contentInsets;
    
 //get the are above the keyboard
 var areaVisibleAboveKeyboard = new RectangleF (this.View.Frame.Location,
          new SizeF (this.View.Frame.Width, this.View.Frame.Size.Height - keyboardBounds.Size.Height));

 //get the area of the view we want to ensure its visible
 var areaActiveView = activeView.Superview.ConvertRectToView (activeView.Frame, this.View);   
    
 //if we can't see the full view, then scroll so its visible
 if (!areaVisibleAboveKeyboard.Contains (areaActiveView)) 
 {
  var scrollPoint = new PointF (0.0f, areaActiveView.Location.Y + areaActiveView.Height + 
  scrollView.ContentOffset.Y - areaVisibleAboveKeyboard.Height);
  scrollView.SetContentOffset (scrollPoint, true);
 }
}

The WillHide is far simpler; just reset the scroll the original state.

protected void WillHide (NSNotification notification)
{
 var activeView = this.View.FirstResponder ();
 if (activeView == null)
  return;         

 //scroll back 
 var animationDuration = UIKeyboard.AnimationDurationFromNotification (notification);
 var contentInsets = new UIEdgeInsets (0.0f, 0.0f, 0.0f, 0.0f);
 UIView.Animate (animationDuration, delegate {
  scrollView.ContentInset = contentInsets;
  scrollView.ScrollIndicatorInsets = contentInsets;
    }
 );
}

Notice that in both the notifications, we are checking for an active view, or “first responder” we are using the extensions method from the previous article.

You can get the full code of a working demonstration of both problems and their solutions.

  1. KeyboardMess.zip - full source code
  2. or see all the code above together on a GitHub Gist.

* Points are not pixels, check iPhone Development Guide for more details.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Leonardo Paneque
Team Leader
United States United States
Leonardo loves to code with C# and thinks .NET platforms rocks.
He has a Master degree in Computer Sciences and likes to share code and ideas.
Follow on   Twitter

Comments and Discussions

 
QuestionGreat article ! PinprofessionalVolynsky Alex15-Mar-14 3:54 
GeneralRe: Great article ! PinmemberLeonardo Paneque16-Mar-14 12:20 
GeneralRe: Great article ! PinprofessionalVolynsky Alex16-Mar-14 12:24 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.141223.1 | Last Updated 15 Mar 2014
Article Copyright 2014 by Leonardo Paneque
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid