There are plenty of tutorials and answers on StackOverflow regarding how to centre the contents of a UIView when the keyboard is partially obscuring it, however I couldn’t find any that take into consideration views with are not fullscreen - such as iPad form sheets.

Setting up AutoLayout

Set up a vertically centred constraint (for the view you want to keep centred), and call it something like verticallyCenteredConstraint. Then create an IBOutlet to it in your view controller, so that it’s constant property can be easily changed.

Keyboard Notifications

Combine the y origin and height of the UIView, along with the height of the keyboard, then subtract this from the height of the screen (which I calculate by adding the keyboards y origin with it’s height). If the keyboard is overlapping your view, then the result should be a negative number which indicates how many points the overlap is. If the value is negative then divide it by 2 and set it as the verticallyCenteredConstraint constant.

Animating Autolayout

You can easily animate changes to auto layout by creating an UIView animation block and calling layoutifneeded() on the view you want to animate.

So far I’ve tested this code successfully on an iPad Air 2, iPad Pro 12.9”, iPhone 5s, and iPhone 6.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
func keyboardWillShow(notification : NSNotification) {
		
		if allowCancel == true {
			addCancelButtonToKeyboard()
		}
		
		if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue() {
			let offset = ((keyboardSize.origin.y + keyboardSize.height) - (keyboardSize.height + self.view.frame.height)) / 2
			centerOffset.constant = offset < 0 ? offset : 0
			// Old method which did not work well on non-fullscreen views (e.g. iPad formsheet)
			// centerOffset.constant = (0 - (abs(self.view.convertRect(self.view.frame, toView: nil).origin.y - keyboardSize.size.height) / 2))
			
			// Animate autolayout only if the view is actually on the screen, if we always animate then we see some strange effects (the view animating from the right as it's being presented)
			if self.isBeingPresented() == false {
				UIView.animateWithDuration(0.2, animations: {
					self.view.layoutIfNeeded()
				})
			}

		}
		
	}
	
	func keyboardWillHide(notification : NSNotification) {
		centerOffset.constant = 0
		UIView.animateWithDuration(0.2, animations: {
			self.view.layoutIfNeeded()
		})
	}