swift keyboard height after it has been hidden - ios

I am working on a chat app (think whatsapp). In one viewcontroller a user will pick a photo to send and then input their message in a textfield. The first time the textfield input moves with the keyboard height. That works fine. Now if a use chose the wrong image and clicked back and selected another image from the gallery or a photo the textfield does not move with the keyboard.
My code is:
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
func keyboardWillShow(_ note: Notification) {
if let keyboardSize = note.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? CGRect {
let keyboardHeight = keyboardSize.height
let duration = (note.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Float)
let curve = (note.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! CInt)
//----------------Image Attachment----------------
let imageX = self.imgBackgroundSend.frame.origin.x
let imageY = CGFloat(keyboardHeight)
let imageWidth = self.imgBackgroundSend.frame.size.width
let imageHeight = self.imgBackgroundSend.frame.size.height
self.imgBackgroundSend.frame = CGRect(x: imageX, y: imageY, width: imageWidth, height: imageHeight)
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(CDouble(duration))
UIView.setAnimationCurve(UIViewAnimationCurve(rawValue: Int(CInt(curve)))!)
UIView.commitAnimations()
let offsetScrollPoint = CGPoint(x: CGFloat(0), y: CGFloat(keyboardHeight))
self.scrlViewImageText.contentOffset = offsetScrollPoint
}
}
func keyboardWillHide(_ note: Notification) {
if let keyboardSize = (note.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
let keyboardHeight = keyboardSize.height
let duration = (note.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double)
let curve = (note.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! CInt)
//----------------Image Attachment----------------
let imageX = self.imgBackgroundSend.frame.origin.x
let imageY = self.scrlViewImageText.center.y - (self.imgBackgroundSend.frame.size.height/2)
print(keyboardHeight)
let imageWidth = self.imgBackgroundSend.frame.size.width
let imageHeight = self.imgBackgroundSend.frame.size.height
self.imgBackgroundSend.frame = CGRect(x: imageX, y: imageY, width: imageWidth, height: imageHeight)
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(CDouble(duration))
UIView.setAnimationCurve(UIViewAnimationCurve(rawValue: Int(CInt(curve)))!)
UIView.commitAnimations()
let offsetScrollPoint = CGPoint(x: CGFloat(0), y: CGFloat(0))
self.scrlViewImageText.contentOffset = offsetScrollPoint
}
`
I am only a junior dev and am struggling to figure this one out as easy as it probably is

Aditya Srivastava was correct - changing the UIKeyboardFrameBeginUserInfoKey with UIKeyboardFrameEndUserInfoKey worked a treat.
Thank you so much.
As an aside - I also wanted to make the UITextView expand upwards not downwards so it does go below the keyboard. I did using this code snippet.
var frame: CGRect = txtMessage.frame
frame.origin.y = frame.maxY - txtMessage.contentSize.height
frame.size.height = txtMessage.contentSize.height
txtMessage.frame = frame

Related

How to autoscroll the scrollView horizontally?

I am using this code to scroll the scrollview horizontally when sliding the scrollview.
func getScrollView() {
upperScroll.delegate = self
upperScroll.isPagingEnabled = true
// pageControll.numberOfPages = logoImage.count
upperScroll.isScrollEnabled = true
let scrollWidth: Int = Int(self.view.frame.width)
upperScroll.contentSize = CGSize(width: CGFloat(scrollWidth), height:(self.upperScroll.frame.height))
print(upperScroll.frame.size.width)
upperScroll.backgroundColor = UIColor.clear
for index in 0..<logoImage.count {
let xPosition = self.view.frame.width * CGFloat(index)
upperScroll.layoutIfNeeded()
let img = UIImageView(frame: CGRect(x: CGFloat(xPosition), y: 0, width: upperScroll.frame.size.width, height: self.upperScroll.frame.height))
img.layoutIfNeeded()
let str = logoImage[index]
let url = URL(string: str)
img.sd_setImage(with: url, placeholderImage: UIImage(named:"vbo_logo2.png"))
upperScroll.addSubview(img)
}
view.addSubview(upperScroll)
upperScroll.contentSize = CGSize(width: CGFloat((scrollWidth) * logoImage.count), height: self.upperScroll.frame.height)
}
But i want to auto scroll?
How can i do this. Can anyone help me please.
I got the solution
#objc func animateScrollView() {
let scrollWidth = upperScroll.bounds.width
let currentXOffset = upperScroll.contentOffset.x
let lastXPos = currentXOffset + scrollWidth
if lastXPos != upperScroll.contentSize.width {
print("Scroll")
upperScroll.setContentOffset(CGPoint(x: lastXPos, y: 0), animated: true)
}
else {
print("Scroll to start")
upperScroll.setContentOffset(CGPoint(x: 0, y: 0), animated: true)
}
}
func scheduledTimerWithTimeInterval(){
// Scheduling timer to Call the function "updateCounting" with the interval of 1 seconds
timer = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(self.animateScrollView), userInfo: nil, repeats: true)
}
and call this function in ViewDidAppear
https://developer.apple.com/documentation/uikit/uiscrollview/1619400-setcontentoffset?language=objc
func scrollToPoint(point: CGPoint) {
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(10.0)) {
upperScroll.setContentOffset(point/* where you want to scroll to*/, animated:true)
}
}
you can specify the x axis when you are creating the point to pass to the func:
CGPoint(x: 100, y: 0)
There are method available to scroll for visible rect in scrollView. You need to pass CGRect in method, this means area where you want to scroll.
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated;
How about that:
let timer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: (#selector(ViewController.timerAction)), userInfo: nil, repeats: true)
#objc func timerAction() {
var xOffSet = 0
xOffSet += 10
UIView.animateWithDuration(1, delay: 0, options: UIViewAnimationOptions.CurveLinear, animations: {
self.scrollView.contentOffset.x = xOffSet
}, completion: nil)
}
How to implement auto scroll in UIScrollview using Swift 3?

How to make keyboard show up but not cover the element at the bottom of the screen Swift 4?

I have a layout like below for my screen, it is a TextView on top,and 2 button at the bottom :
What I want is the keyboard appear at the bottom of the 2 button.The desired output will be like this whenever the keyboard is showed up:
Therefore I implement this code in my ViewController :
override func viewDidLoad() {
super.viewDidLoad()
self.statusTextView.perform(
#selector(becomeFirstResponder),
with: nil,
afterDelay: 0.1)
NotificationCenter.default.addObserver(self, selector: #selector(MyViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(MyViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
#objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y == 0{
self.view.frame.origin.y -= keyboardSize.height
}
}
}
#objc func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y != 0{
self.view.frame.origin.y += keyboardSize.height
}
}
}
By the code above the keyboard is show under 2 button at the bottom,the textView is move up as well.Here is the output:
As you can see,the textView is moved up as well.Therefore it not appear in the screen.
So my question is,how to make the keyboard show without cover any element in the bottom and not affecting the element as well?
After implement the solution from #D.Desai,I get this error in my Xcode
#objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue,
let window = self.view.window?.frame
// We're not just minusing the kb height from the view height because
// the view could already have been resized for the keyboard before
self.view.frame = CGRect(x: self.view.frame.origin.x,
y: self.view.frame.origin.y,
width: self.view.frame.width,
height: window.origin.y + window.height - keyboardSize.height)
} else {
debugPrint("We're showing the keyboard and either the keyboard size or window is nil: panic widely.")
}
}
#objc func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
let viewHeight = self.view.frame.height
self.view.frame = CGRect(x: self.view.frame.origin.x,
y: self.view.frame.origin.y,
width: self.view.frame.width,
height: viewHeight + keyboardSize.height)
} else {
debugPrint("We're about to hide the keyboard and the keyboard size is nil. Now is the rapture.")
}
}

Creating floating text box in ios application

I want to add an option when clicking on a cell it will show floating text box above the keyboard and its blurs the background.
Anyone familiar with this and how to implement it?
You can view image at the following link:
Start with adding some properties to your class:
var textField = UITextField()
var composeBarView = UIView()
var blurView = UIView()
let barHeight:CGFloat = 44
Next create the blur view, textField and container view. Do this in the viewWillAppear:
blurView = UIView(frame: self.view.frame)
blurView.alpha = 0.5
blurView.backgroundColor = UIColor.blackColor();
self.view.addSubview(blurView);
blurView.hidden = true;// Note its hidden!
textField = UITextField(frame: CGRectMake(0, 0, UIScreen.mainScreen().bounds.width, barHeight))
composeBarView = UIView(frame: CGRectMake(0, UIScreen.mainScreen().bounds.height-64, UIScreen.mainScreen().bounds.width, barHeight));
composeBarView.addSubview(textField);
self.view.addSubView(composeBarView);
Then you should register for the UIKeyboardWillShowNotification and UIKeyboardWillHideNotification notifications:
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillToggle:", name: UIKeyboardWillShowNotification, object: nil);
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillToggle:", name: UIKeyboardWillHideNotification, object: nil);
Implement the keyboardWillToggle method:
func keyboardWillToggle(notfication: NSNotification){
if let userInfo = notfication.userInfo {
let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as NSValue).CGRectValue()
let startFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as NSValue).CGRectValue();
let duration:NSTimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
let animationCurveRaw = animationCurveRawNSN?.unsignedLongValue ?? UIViewAnimationOptions.CurveEaseInOut.rawValue
let animationCurve:UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)
var signCorrection:CGFloat = 1;
if (startFrame.origin.y < 0 || startFrame.origin.x < 0 || endFrame.origin.y < 0 || endFrame.origin.x < 0){
signCorrection = -1;
}
let widthChange = (endFrame.origin.x - startFrame.origin.x) * signCorrection;
let heightChange = (endFrame.origin.y - startFrame.origin.y) * signCorrection;
let sizeChange = UIInterfaceOrientationIsLandscape(self.interfaceOrientation) ? widthChange : heightChange;
var frame = composeBarView.frame
frame.origin.y += (sizeChange - barHeight ?? 0.0 )
composeBarView.frame = frame;
UIView.animateWithDuration(duration,
delay: NSTimeInterval(0),
options: animationCurve,
animations: { self.view.layoutIfNeeded() },
completion: nil)
}
}
Note that we must account for the bar height, when you show the keyboard. You will need to adjust the view back to its original position.
Then when the didSelectRowAtIndexPath is called you call:
textFiled.becomeFirstResponder()
blureView.hidden = false;
Not tested yet but i think that you can do it with a modal segue?
For an exemple, when your textfield become editing you can segue to a new CellViewcontroller which can appear above your actual Tableview and insert this parameters :
func prensentationController(controller: UIPresentationController, viewControllerdaptivePresentationStyle style: UIModalPresentationtyle) -> UIViewController
let navcon = UINavigationController(UIPresentationViewController: controller.presentedViewController)
let visualEffectView = UIVisualEffectView(effect:UIBlurEffect(style: .ExtraLight))
visualEffectView.frame = navcon.view.bounds
navcon.view.insertSubview(visualEffectView, atIndex: 0)
return navcon
}

TextView inside ScrollView stick to keyboard

I have a UIScrollView and content inside it. Inside content there is a UITextView. When user presses the UITextView I want the UITextView stick to the keyboard.
In the image:
Whole thing is UIScrollView
Bottom black area is the visible screen
Red area is content
Blue area is UITextView
Green distance is the dynamic margin between content and the screen bound.
I want to calculate the green distance which the user can see along with the blue are(UITextView) which the user can see. If the user half swiped UITextView, the UITextView should still stick to the keyboard.
let userInfo = notification.userInfo!
let keyboardEndFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as NSValue).CGRectValue()
let keyboardBeginFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as NSValue).CGRectValue()
let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as UInt
let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as Double
let options = UIViewAnimationOptions(curve << 16)
UIView.animateWithDuration(duration, delay: 0, options: options,
animations: {
var visibleGreen = ???
var visibleBlue = ???
var amountToSubtract = visibleGreen + visibleBlue
var newFrame = (self.currentCardInstance?.newCommentCell.frame)!
var kbFrameEnd = self.view.convertRect(keyboardEndFrame, toView: nil)
var kbFrameBegin = self.view.convertRect(keyboardBeginFrame, toView: nil)
newFrame.origin.y -= kbFrameBegin.origin.y - kbFrameEnd.origin.y + amountToSubtract
self.currentCardInstance?.newCommentCell.frame = newFrame;
},
completion: nil
)
Here is how I solved it:
var keyboardModifier: CGFloat = 0
func keyboardWillAppear(notification: NSNotification) {
println("keyboardWillAppear")
keyboardResize(notification: notification)
scrollToBottom()
}
func keyboardWillDisappear(notification: NSNotification) {
println("keyboardWillDisappear")
keyboardResize(notification: notification)
}
func keyboardResize(#notification: NSNotification) {
let userInfo = notification.userInfo!
let keyboardEndFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as NSValue).CGRectValue()
let keyboardBeginFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as NSValue).CGRectValue()
let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as UInt
let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as Double
let options = UIViewAnimationOptions(curve << 16)
var newFrame = (self. currentCardInstance?.frame)!
var kbFrameEnd = self.view.convertRect(keyboardEndFrame, toView: nil)
var kbFrameBegin = self.view.convertRect(keyboardBeginFrame, toView: nil)
keyboardModifier = kbFrameBegin.origin.y - kbFrameEnd.origin.y
scrollView.frame.size.height -= keyboardModifier
}
func scrollToBottom() {
var bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.size.height)
scrollView.setContentOffset(bottomOffset, animated: false)
}

How to make UITextField move up when keyboard is present?

How do I prevent a UITextField from being hidden by the keyboard?
I assume this is happening on a UIViewController. If so, you can setup the following two functions to be called when the keyboard will show/hide, and respond appropriately in their blocks.
Setting up the UIViewController:
class ViewController: UIViewController, UITextFieldDelegate... {
var frameView: UIView!
First, in viewDidLoad():
override func viewDidLoad() {
self.frameView = UIView(frame: CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height))
// Keyboard stuff.
let center: NotificationCenter = NotificationCenter.default
center.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
center.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
Then implement the following two functions to respond to your NotificationCenter functions defined in viewDidLoad() above. I give you an example of moving the entire view, but you can also animate just the UITextFields.
#objc func keyboardWillShow(notification: NSNotification) {
let info:NSDictionary = notification.userInfo! as NSDictionary
let keyboardSize = (info[UIResponder.keyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
let keyboardHeight: CGFloat = keyboardSize.height
let _: CGFloat = info[UIResponder.keyboardAnimationDurationUserInfoKey] as! NSNumber as! CGFloat
UIView.animate(withDuration: 0.25, delay: 0.25, options: .curveEaseInOut, animations: {
self.frameView.frame = CGRect(x: 0, y: (self.frameView.frame.origin.y - keyboardHeight), width: self.view.bounds.width, height: self.view.bounds.height)
}, completion: nil)
}
#objc func keyboardWillHide(notification: NSNotification) {
let info: NSDictionary = notification.userInfo! as NSDictionary
let keyboardSize = (info[UIResponder.keyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
let keyboardHeight: CGFloat = keyboardSize.height
let _: CGFloat = info[UIResponder.keyboardAnimationDurationUserInfoKey] as! NSNumber as! CGFloat
UIView.animate(withDuration: 0.25, delay: 0.25, options: .curveEaseInOut, animations: {
self.frameView.frame = CGRect(x: 0, y: (self.frameView.frame.origin.y + keyboardHeight), width: self.view.bounds.width, height: self.view.bounds.height)
}, completion: nil)
}
Don't forget to remove the notifications when leaving your view
override func viewWillDisappear(_ animated: Bool) {
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
}
Here is the simple solution in Swift. I translated some Objective-C code that worked for me in the past.
func textFieldDidBeginEditing(textField: UITextField) { // became first responder
//move textfields up
let myScreenRect: CGRect = UIScreen.mainScreen().bounds
let keyboardHeight : CGFloat = 216
UIView.beginAnimations( "animateView", context: nil)
var movementDuration:NSTimeInterval = 0.35
var needToMove: CGFloat = 0
var frame : CGRect = self.view.frame
if (textField.frame.origin.y + textField.frame.size.height + /*self.navigationController.navigationBar.frame.size.height + */UIApplication.sharedApplication().statusBarFrame.size.height > (myScreenRect.size.height - keyboardHeight)) {
needToMove = (textField.frame.origin.y + textField.frame.size.height + /*self.navigationController.navigationBar.frame.size.height +*/ UIApplication.sharedApplication().statusBarFrame.size.height) - (myScreenRect.size.height - keyboardHeight);
}
frame.origin.y = -needToMove
self.view.frame = frame
UIView.commitAnimations()
}
func textFieldDidEndEditing(textField: UITextField) {
//move textfields back down
UIView.beginAnimations( "animateView", context: nil)
var movementDuration:NSTimeInterval = 0.35
var frame : CGRect = self.view.frame
frame.origin.y = 0
self.view.frame = frame
UIView.commitAnimations()
}
Swift 4 code, It is very simple instead of using many things like NSNotificationCenter, then calculating the height of everything and making conditions makes this more complicated,
The Simple way to do this is coded below, it will work to move up the view.
func textFieldDidBeginEditing(_ textField: UITextField) {
moveTextField(textfield: textField, moveDistance: -250, up: true)
}
func textFieldDidEndEditing(_ textField: UITextField) {
moveTextField(textfield: textField, moveDistance: -250, up: false)
}
func moveTextField(textfield: UITextField, moveDistance: Int, up: Bool) {
let moveDuration = 0.3
let movement: CGFloat = CGFloat(up ? moveDistance: -moveDistance)
UIView.beginAnimations("animateTextField", context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(moveDuration)
self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)
UIView.commitAnimations()
}
you can change that -250 value according to the placement of your textfields.
In case you are using a UIScrollView or any of its subclasses, e.g., UITableView, you can also manipulate the contentInset property. That way you do not have to mess with frame, bounds, NSLayoutConstraint or NSLayoutAnchor.
func keyboardWillShow(notification: Notification) {
let info = notification.userInfo!
let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
let keyboardHeight: CGFloat = keyboardSize.height
let duration = info[UIKeyboardAnimationDurationUserInfoKey] as! TimeInterval
UIView.animate(withDuration: duration, delay: 0, options: UIViewAnimationOptions.curveEaseInOut, animations: {
self.tableView?.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardHeight, right: 0)
}, completion: nil)
}
func keyboardWillHide(notification: Notification) {
let info = notification.userInfo!
let duration = info[UIKeyboardAnimationDurationUserInfoKey] as! TimeInterval
UIView.animate(withDuration: duration, delay: 0, options: UIViewAnimationOptions.curveEaseInOut, animations: {
self.tableView?.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}, completion: nil)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
Swift 3.0
var activeField: UITextField?
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(ProfileViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(ProfileViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
func textFieldDidBeginEditing(_ textField: UITextField){
activeField = textField
}
func textFieldDidEndEditing(_ textField: UITextField){
activeField = nil
}
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if (self.activeField?.frame.origin.y)! >= keyboardSize.height {
self.view.frame.origin.y = keyboardSize.height - (self.activeField?.frame.origin.y)!
} else {
self.view.frame.origin.y = 0
}
}
}
func keyboardWillHide(notification: NSNotification) {
self.view.frame.origin.y = 0
}
In Swift 3 use this code
override func viewDidLoad() {
super.viewDidLoad()
let center: NotificationCenter = NotificationCenter.default
center.addObserver(self, selector: #selector(RFLogInViewController.keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
center.addObserver(self, selector: #selector(RFLogInViewController.keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
func keyboardWillShow(notification: NSNotification) {
let info:NSDictionary = notification.userInfo! as NSDictionary
let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
let keyboardHeight: CGFloat = keyboardSize.height
let _: CGFloat = info[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber as! CGFloat
UIView.animate(withDuration: 0.25, delay: 0.25, options: .curveEaseInOut, animations: {
self.view.frame = CGRect(x: 0, y: (self.view.frame.origin.y - keyboardHeight), width: self.view.bounds.width, height: self.view.bounds.height)
}, completion: nil)
}
func keyboardWillHide(notification: NSNotification) {
let info: NSDictionary = notification.userInfo! as NSDictionary
let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
let keyboardHeight: CGFloat = keyboardSize.height
let _: CGFloat = info[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber as! CGFloat
UIView.animate(withDuration: 0.25, delay: 0.25, options: .curveEaseInOut, animations: {
self.view.frame = CGRect(x: 0, y: (self.view.frame.origin.y + keyboardHeight), width: self.view.bounds.width, height: self.view.bounds.height)
}, completion: nil)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(true)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
Just add 'IQKeyboardManager' library into your project, and Done. You have not to do anything else. For reference please check this url.
https://github.com/hackiftekhar/IQKeyboardManager
Swift 4
I have seen numerous of answer and plenty of them did not work for me where I have a UIViewController With numerous of text fields.
According to the Apple documentation I have translate the example to Swift 4
Your content needs to be embedded within an scrollview.
Add the notification listeners for when the keyboard will appear or dissappear.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidShow), name: .UIKeyboardDidShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: .UIKeyboardWillHide, object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self)
}
Implement UITextField Delegates
func textFieldDidBeginEditing(_ textField: UITextField) {
currentTextField = textField
}
func textFieldDidEndEditing(_ textField: UITextField, reason: UITextFieldDidEndEditingReason) {
currentTextField = nil
}
Selectors
#objc func keyboardDidShow(notification: NSNotification) {
print("\(logClassName): keyboardWDidShow")
let keyboardFrame = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
let keyboardSize:CGSize = keyboardFrame!.size
let contentInsets:UIEdgeInsets = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0)
trackScrollView.contentInset = contentInsets
trackScrollView.scrollIndicatorInsets = contentInsets
var aRect:CGRect = self.view.frame
aRect.size.height -= keyboardSize.height
if !(aRect.contains(currentTextField!.frame.origin)){
trackScrollView.scrollRectToVisible(currentTextField!.frame, animated: true)
}
}
#objc func keyboardWillHide(notification: NSNotification){
print("\(logClassName): keyboardWillHide")
let contentInsents:UIEdgeInsets = UIEdgeInsets.zero
trackScrollView.contentInset = contentInsents
trackScrollView.scrollIndicatorInsets = contentInsents
}
first of all you should have scrollview
step 1:find the height of key board
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo ? [UIKeyboardFrameBeginUserInfoKey] as ? NSValue) ? .cgRectValue {
let keyboardHeight = keyboardSize.height
a = keyboardHeight
}
}
step 2: bind the delegete methods of textfield
func textFieldDidBeginEditing(_ textField: UITextField) {
utility.setUserDefaultBool(value: false, key: "FrameMoveFlag") //flag
let b = view1.frame.height - textField.frame.origin.y
if (b < 350) {
view1.frame.origin.y = view1.frame.origin.y + (view1.frame.height - textField.frame.origin.y) - (a + 50)
utility.setUserDefaultBool(value: true, key: "FrameMoveFlag") //flag
}
}
func textFieldDidEndEditing(_ textField: UITextField) {
if (utility.getUserDefaultBOOLForKey(key: "FrameMoveFlag") == true) {
view1.frame.origin.y = 0
}
}
Swift 3 code for Geiger answer
func textFieldDidBeginEditing(_ textField: UITextField) { // became first responder
//move textfields up
let myScreenRect: CGRect = UIScreen.main.bounds
let keyboardHeight : CGFloat = 216
UIView.beginAnimations( "animateView", context: nil)
var movementDuration:TimeInterval = 0.35
var needToMove: CGFloat = 0
var frame : CGRect = self.view.frame
if (textField.frame.origin.y + textField.frame.size.height + UIApplication.shared.statusBarFrame.size.height > (myScreenRect.size.height - keyboardHeight - 30)) {
needToMove = (textField.frame.origin.y + textField.frame.size.height + UIApplication.shared.statusBarFrame.size.height) - (myScreenRect.size.height - keyboardHeight - 30);
}
frame.origin.y = -needToMove
self.view.frame = frame
UIView.commitAnimations()
}
func textFieldDidEndEditing(_ textField: UITextField) {
//move textfields back down
UIView.beginAnimations( "animateView", context: nil)
var movementDuration:TimeInterval = 0.35
var frame : CGRect = self.view.frame
frame.origin.y = 0
self.view.frame = frame
UIView.commitAnimations()
}
If you don't want to manually work with appearing and disappearing of the keyboard, just use the UITableViewController and it will handle all text fields in the table view.
Check out my gist, I use a scrollView for my case, but it works for any kind of view, you only have to remove the scrollView part and replace it with your view.
The gist is very well commented so you will also understand how this case is handled.
https://gist.github.com/Sjahriyar/916e93153a29dc602b45f29d39182352
I created KeyboardController to handle the keyboard issue. All that needs to be done is call setUpKeyBoardListeners() and set the lastElement as whatever the last element in your view is.
Gist: https://gist.github.com/espitia/ef830cf677fa1bc33ffdf16ac12d0204

Resources