I have UIView which is container for button "send" and textView.
When I starting editing I have keyboard on the screen and I change Y origin of the container to move it higher and not be covered by keyboard.
When I finish editing I got keyboard hidden and my container(UIView with button and textView) just disappears! But if I turn simulator right or left this became visible again.
Here is the animation code that move my container up and down:
func textViewDidChange(textView: UITextView) {
self.messagePromptLabel.hidden = messageTextView.hasText() ? true : false
}
func textViewDidEndEditing(textView: UITextView) {
if !self.messageTextView.hasText() {
self.messagePromptLabel.hidden = false
}
}
func didTapScrollView(){
self.view.endEditing(true)
}
func keyboardWasShown(notification: NSNotification) {
let dict: NSDictionary = notification.userInfo!
let keyboardSize: NSValue = dict.valueForKey(UIKeyboardFrameEndUserInfoKey) as! NSValue
let frameKeyboardSize: CGRect = keyboardSize.CGRectValue()
UIView.animateWithDuration(0.3, animations: { () -> Void in
self.chatScrollView.frame.origin.y -= frameKeyboardSize.height
self.messageView.frame.origin.y -= frameKeyboardSize.height
}) { (finished: Bool) -> Void in
}
}
func keyboardWillHide(notification: NSNotification) {
UIView.animateWithDuration(0.3, animations: { () -> Void in
self.chatScrollView.frame.origin.y = self.chatScrollViewOriginY!
self.messageView.frame.origin.y = self.messageTextViewOriginY!
}) { (finished: Bool) -> Void in
}
}
Some additional code
This code may help find out something.
#IBOutlet weak var messageTextView: UITextView!
#IBOutlet weak var chatScrollView: UIScrollView!
#IBOutlet weak var messagePromptLabel: UILabel!
#IBOutlet weak var messageView: UIView!
var chatScrollViewOriginY: CGFloat?
var messageTextViewOriginY: CGFloat?
var messageArray = [String]()
var senderArray = [String]()
var currentUserImage: UIImage?
var recipientImage: UIImage?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
messageTextView.addSubview(messagePromptLabel)
self.title = recipientNickname
chatScrollViewOriginY = self.chatScrollView.frame.origin.y
messageTextViewOriginY = self.messageTextView.frame.origin.y
print(" messageTextViewOriginY \(messageTextViewOriginY)")
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWasShown:", name: UIKeyboardDidShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: "didTapScrollView")
tapGestureRecognizer.numberOfTouchesRequired = 1
chatScrollView.addGestureRecognizer(tapGestureRecognizer)
chatScrollView.backgroundColor = UIColor.redColor()
}
func textViewDidChange(textView: UITextView) {
self.messagePromptLabel.hidden = messageTextView.hasText() ? true : false
}
func textViewDidEndEditing(textView: UITextView) {
if !self.messageTextView.hasText() {
self.messagePromptLabel.hidden = false
}
}
func didTapScrollView(){
self.view.endEditing(true)
}
Question:
What make my UIView container invisible all the time when I hidding keyboard and make it visible when I turn my phone left or right?
You need to add this code in your send button action:
self.view.endEditing(true)
Related
I have textfield and button inside containerview, now if i tap on textfield i need containerview has to up with keyboard
according to this answer
for bottom view
bottom = leading = trailing = 0, height = 80
and
i have created containerview bottom constraint to NSLayoutConstraint
and addd code like this: but i am unable to move container viewup, only keyboard coming.. view not comingup, where am i wrong
class MessageDetailsVCViewController: UIViewController {
#IBOutlet weak var messageTextfield: UITextField!
#IBOutlet weak var viewbottomConstraint: NSLayoutConstraint!
#IBOutlet weak var bottomContainerView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification), name: UIResponder.keyboardWillHideNotification, object: nil)
// Do any additional setup after loading the view.
}
override func viewWillDisappear(_ animated: Bool) {
NotificationCenter.default.removeObserver(self)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.bottomContainerView.superview?.setNeedsLayout()
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
override func resignFirstResponder() -> Bool {
return true
}
#objc func handleKeyboardNotification(_ notification: Notification) {
if let userInfo = notification.userInfo {
let keyboardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as AnyObject).cgRectValue
let isKeyboardShowing = notification.name == UIResponder.keyboardWillShowNotification
viewbottomConstraint?.constant = isKeyboardShowing ? -keyboardFrame!.height : 0
UIView.animate(withDuration: 0.5, animations: { () -> Void in
self.view.layoutIfNeeded()
})
}
}
}
You can try positive keyboardFrame!.height
viewbottomConstraint?.constant = isKeyboardShowing ? keyboardFrame!.height : 0
I am using scrolview for view with height 1000, initially i don't want my scrolView to scroll. if i tap on any textField then i want my scrolview to scroll and if i return keyboard then i don't want my scrollview to scroll.
Here i am able to textfield up when when keyboard appears but i am unable to return textfield to its orginal position when i return keyboard and when i return keyboard i dont want my view to scroll,
Please help me in the code.
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var scrolView: UIScrollView!
#IBOutlet weak var upTFLD: UITextField!
var activeTextField = UITextField()
#IBOutlet weak var downTFLD: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
upTFLD.delegate = self
downTFLD.delegate = self
NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardAppear(_:)), name: UIResponder.keyboardDidShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardDisappear(_:)), name: UIResponder.keyboardDidHideNotification, object: nil)
}
#objc func onKeyboardAppear(_ notification: NSNotification) {
let info = notification.userInfo!
let rect: CGRect = info[UIResponder.keyboardFrameBeginUserInfoKey] as! CGRect
let kbSize = rect.size
let insets = UIEdgeInsets(top: 0, left: 0, bottom: kbSize.height+20, right: 0)
self.scrolView.contentInset = insets
self.scrolView.scrollIndicatorInsets = insets
var visibleRect: CGRect = self.scrolView.convert(self.scrolView.bounds, to: self.view)
visibleRect.size.height -= rect.size.height;
let inputRect: CGRect = self.activeTextField.convert(self.activeTextField.bounds, to: self.scrolView)
if (visibleRect.contains(inputRect)) {
self.scrolView.scrollRectToVisible(inputRect, animated: true)
}
}
#objc func onKeyboardDisappear(_ notification: NSNotification) {
self.scrolView.contentInset = UIEdgeInsets.zero
self.scrolView.scrollIndicatorInsets = UIEdgeInsets.zero
}
public func textFieldDidBeginEditing(_ textField: UITextField) {
activeTextField = textField
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
activeTextField.resignFirstResponder()
return true
}
}
initially i dont want scrolling, and if i return keyboard i need textfield come to its original position and no scrolling again.
Only keyboard appears then only i need scrolling. please help me in the code.
You just need to set the contentOffset of your ScrollView right after the keyboard is hidden.
Create a variable to store offsetBeforeShowKeyboard
var offsetBeforeShowKeyboard: CGFloat?
When view is initially loaded:
self.scrollView.isScrollEnabled = false
When select any TextField:
public func textFieldDidBeginEditing(_ textField: UITextField) {
self.scrollView.isScrollEnabled = true
if (self.offsetBeforeShowKeyboard == nil) {
self.offsetBeforeShowKeyboard = self.scrollView.contentOffset
}
}
When keyboard is hidden
#objc func onKeyboardDisappear(_ notification: NSNotification) {
self.scrollView.isScrollEnabled = false
if let offset = self.offsetBeforeShowKeyboard {
self.scrolView.setContentOffset(offset, animated: true)
}
self.offsetBeforeShowKeyboard = nil
}
In viewWillAppear
yourScrollview.isScrollEnabled = false
After Keyboard appears make it true
yourScrollview.isScrollEnabled = true
Alternatively you can use IQKeyboard manager to take care of textfields.Checkout: IQKeyboardManager
This question already has answers here:
Swift - how do I allow the textfield to still recognize spaces after the correct answer inputed as still the correct answer
(2 answers)
Closed 6 years ago.
Then how to I allow only a next question button appear when only the right answer is written? I am using Swift! Below is my code. Any help would be greatly appreciated! Thanks!
This is my code and at
import UIKit
class InputViewController1: UIViewController, UITextFieldDelegate {
#IBOutlet var questionLabel: UILabel!
#IBOutlet var correctAnswerLabel: UILabel!
#IBOutlet var inputTextField: UITextField!
var enteredAnswer: String?
var correctAnswer = "Correct Answer = Small"
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(InputViewController1.keyboardWillShow(_:)), name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(InputViewController1.keyboardWillHide), name: UIKeyboardWillHideNotification, object: nil)
inputTextField.delegate = self
titlesForLabels()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func titlesForLabels() {
questionLabel.text = "What is the size of the lesion(s)?"
correctAnswerLabel.text = correctAnswer
correctAnswerLabel.hidden = true
inputTextField.text = nil
inputTextField.enabled = true
}
func keyboardWillShow(notification: NSNotification) {
let userInfo = notification.userInfo!
let keyboardFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()
UIView.animateWithDuration(0.1, animations: { () -> Void in
self.view.frame.origin.y = -keyboardFrame.size.height
})
}
func keyboardWillHide() {
UIView.animateWithDuration(0.1, animations: { () -> Void in
self.view.frame.origin.y = 0
})
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
enteredAnswer = textField.text
checkForCorrectAnswer()
return true
}
func checkForCorrectAnswer() {
if enteredAnswer!.lowercaseString == correctAnswer.lowercaseString {
print("Correct")
correctAnswerLabel.textColor = UIColor.greenColor()
} else {
print("Wrong Answer")
correctAnswerLabel.textColor = UIColor.redColor()
}
correctAnswerLabel.hidden = false
}
}
Please study this code very carefully before asking questions. Using the addTarget method for UIControlEvents.EditingChanged (.EditingChanged), you can alter the properties of your InputViewController with the live current value of your inputTextField. This is done in the textDidChange function. Notice also, that nexButton.alpha is set to 0.0 in viewDidLoad and altered accordingly in both textDidChange and checkForCorrectAnswer.
class InputViewController1: UIViewController, UITextFieldDelegate {
#IBOutlet weak var questionLabel: UILabel!
#IBOutlet weak var correctAnswerLabel: UILabel!
#IBOutlet weak var inputTextField: UITextField!
#IBOutlet weak var nextButton: UIButton!
#IBAction func nextButtonPressed(sender: UIButton) {
}
var enteredAnswer: String?
var correctAnswer = "Small"
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(InputViewController1.keyboardWillShow(_:)), name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(InputViewController1.keyboardWillHide), name: UIKeyboardWillHideNotification, object: nil)
inputTextField.addTarget(self, action: #selector(InputViewController1.textDidChange(_:)), forControlEvents: .EditingChanged)
inputTextField.delegate = self
nextButton.alpha = 0.0
titlesForLabels()
}
func titlesForLabels() {
questionLabel.text = "What is the size of the lesion(s)?"
correctAnswerLabel.text = correctAnswer
correctAnswerLabel.hidden = true
inputTextField.text = nil
inputTextField.enabled = true
}
func keyboardWillShow(notification: NSNotification) {
let userInfo = notification.userInfo!
let keyboardFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()
UIView.animateWithDuration(0.1, animations: {
self.view.frame.origin.y = -keyboardFrame.size.height
})
}
func keyboardWillHide() {
UIView.animateWithDuration(0.1, animations: {
self.view.frame.origin.y = 0
})
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
enteredAnswer = textField.text
checkForCorrectAnswer()
return true
}
func checkForCorrectAnswer() {
if enteredAnswer!.lowercaseString == correctAnswer.lowercaseString {
correctAnswerLabel.textColor = UIColor.greenColor()
UIView.animateWithDuration(0.5, animations: {
self.nextButton.alpha = 1.0
}, completion: nil)
correctAnswerLabel.text = "Correct!"
} else {
print("Wrong Answer")
correctAnswerLabel.textColor = UIColor.redColor()
correctAnswerLabel.text = "Incorrect!"
}
correctAnswerLabel.hidden = false
}
func textDidChange(sender: UITextField) {
enteredAnswer = inputTextField.text
correctAnswerLabel.textColor = UIColor.redColor()
correctAnswerLabel.text = "Incorrect!"
if enteredAnswer!.lowercaseString != correctAnswer.lowercaseString {
UIView.animateWithDuration(0.5, animations: {
self.nextButton.alpha = 0.0
}, completion: nil)
}
}
}
I have tried to follow other guides on here but to no avail.
My app structure currently is a navigation controller that leads to viewcontrollers with scrollview embedded in them. The textfields, textview, buttons etc are on top of the scrollview. When the keyboard appears, and I dismiss it by tapping outside, the scrollview moves up with the keyboard, but does not come down. It seems like this problem is brought on by having the Navigation controller or the nav bar. How can I fix it?
EDIT: I just realized that every time I simulate that particular viewcontroller, everything in it is moved down the same distance before I tap on any textField/textView. Then when the keyboard is shown, it simply moves it up so it looks like how it's setup in storyboard. How do I get rid of the initial downward displacement?
#IBOutlet var scrollView: UIScrollView!
var activeTextView:UIView? = UIView()
#IBOutlet var main: UITextView!
#IBOutlet var initials: UITextField!
#IBOutlet var maleWord: UITextField!
#IBOutlet var maleButton: UIButton!
#IBOutlet var femaleWord: UITextField!
#IBOutlet var femaleButton: UIButton!
#IBOutlet var age: UITextField!
func registerForKeyboardNotifications() {
let notificationCenter = NSNotificationCenter.defaultCenter()
notificationCenter.addObserver(self,
selector: "keyboardWillBeShown:",
name: UIKeyboardWillShowNotification,
object: nil)
notificationCenter.addObserver(self,
selector: "keyboardWillBeHidden:",
name: UIKeyboardWillHideNotification,
object: nil)
}
func tapped() {
initials.resignFirstResponder()
main.resignFirstResponder()
age.resignFirstResponder()
}
// Called when the UIKeyboardDidShowNotification is sent.
func keyboardWillBeShown(sender: NSNotification) {
let info: NSDictionary = sender.userInfo!
let value: NSValue = info.valueForKey(UIKeyboardFrameEndUserInfoKey) as! NSValue
let keyboardSize: CGSize = value.CGRectValue().size
let contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize.height, 0.0)
scrollView.contentInset = contentInsets
scrollView.scrollIndicatorInsets = contentInsets
// If active text field is hidden by keyboard, scroll it so it's visible
var aRect: CGRect = self.view.frame
aRect.size.height -= keyboardSize.height
let activeTextViewRect: CGRect? = self.main.frame
let activeTextViewOrigin: CGPoint? = activeTextViewRect?.origin
if (!CGRectContainsPoint(aRect, activeTextViewOrigin!)) {
scrollView.scrollRectToVisible(activeTextViewRect!, animated:true)
}
}
// Called when the UIKeyboardWillHideNotification is sent
func keyboardWillBeHidden(sender: NSNotification) {
self.scrollView .setContentOffset(CGPointMake(0, 0), animated: true)
self .viewDidLayoutSubviews()
self.activeTextView = nil
}
func textViewDidBeginEditing(textView: UITextView) {
self.activeTextView = textView
scrollView.scrollEnabled = true
}
func textViewDidEndEditing(textView: UITextView) {
self.activeTextView = nil
scrollView.scrollEnabled = false
self.scrollView .setContentOffset(CGPointMake(0, 0), animated: true)
}
func textFieldShouldReturn(textField: UITextField) -> Bool // called when 'return' key pressed. return NO to ignore.
{
textField.resignFirstResponder()
return true;
}
override func viewDidLoad() {
super.viewDidLoad()
var tap = UITapGestureRecognizer (target: self, action: ("tapped"))
self.view.addGestureRecognizer(tap)
self.main.delegate = self
self.initials.delegate = self
self.age.delegate = self
self.registerForKeyboardNotifications()
}
Update your function like following
func keyboardWillBeHidden(sender: NSNotification) {
let contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, 0.0, 0.0)
scrollView.contentInset = contentInsets
self.scrollView .setContentOffset(CGPointMake(0, 0), animated: true)
self .viewDidLayoutSubviews()
self.activeTextView = nil
}
My app structure currently is a navigation controller that leads to viewcontrollers with scrollview embedded in them. The textfields, textview, buttons etc are on top of the scrollview. By using my current code, the scrollview moves the view when UITextFields are clicked, but not UITextViews. I have tried to adopt Apple's recommended method and tweaked it for UITextViews.
Also, in the function keyboardWillBeShown, the part that checks if active textfield/textview in hidden by the keyboard and scrolls, seems to not make any difference at all.
Where have I gone wrong? Thanks
class unwellBasic: UIViewController, UITextViewDelegate,
UIScrollViewDelegate, UITextFieldDelegate {
#IBOutlet var scrollView: UIScrollView!
weak var activeTextView : UITextView?
weak var activeTextField : UITextField?
#IBOutlet var main: UITextView!
#IBOutlet var initials: UITextField!
#IBOutlet var maleButton: UIButton!
#IBOutlet var femaleButton: UIButton!
#IBOutlet var age: UITextField!
#IBOutlet var test: UITextField!
func registerForKeyboardNotifications() {
let notificationCenter = NSNotificationCenter.defaultCenter()
notificationCenter.addObserver(self,
selector: "keyboardWillBeShown:",
name: UIKeyboardWillShowNotification,
object: nil)
notificationCenter.addObserver(self,
selector: "keyboardWillBeHidden:",
name: UIKeyboardWillHideNotification,
object: nil)
}
#IBAction func back(sender: AnyObject) {
self.navigationController?.popViewControllerAnimated(true)
}
#IBAction func next(sender: AnyObject) {
self.performSegueWithIdentifier("bodySegue", sender: self)
}
func tapped() {
initials.resignFirstResponder()
main.resignFirstResponder()
age.resignFirstResponder()
test.resignFirstResponder()
self.activeTextView = nil
}
// Called when the UIKeyboardDidShowNotification is sent.
func keyboardWillBeShown(sender: NSNotification) {
let info: NSDictionary = sender.userInfo!
let value: NSValue = info.valueForKey(UIKeyboardFrameEndUserInfoKey) as! NSValue
let keyboardSize: CGSize = value.CGRectValue().size
let contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize.height, 0.0)
scrollView.contentInset = contentInsets
scrollView.scrollIndicatorInsets = contentInsets
// If active text field is hidden by keyboard, scroll it so it's visible
if self.activeTextView != nil {
var aRect: CGRect = self.view.frame
aRect.size.height -= keyboardSize.height
let activeTextViewRect: CGRect? = self.activeTextView!.frame
let activeTextViewOrigin: CGPoint? = activeTextViewRect?.origin
if (!CGRectContainsPoint(aRect, activeTextViewOrigin!)) {
scrollView.scrollRectToVisible(activeTextViewRect!, animated:true)
}
}
if self.activeTextField != nil {
var aRect: CGRect = self.view.frame
aRect.size.height -= keyboardSize.height
let activeTextViewRect: CGRect? = self.activeTextField!.frame
let activeTextViewOrigin: CGPoint? = activeTextViewRect?.origin
if (!CGRectContainsPoint(aRect, activeTextViewOrigin!)) {
scrollView.scrollRectToVisible(activeTextViewRect!, animated:true)
}
}
}
// Called when the UIKeyboardWillHideNotification is sent
func keyboardWillBeHidden(sender: NSNotification) {
let contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, 0.0, 0.0)
scrollView.contentInset = contentInsets
self.scrollView .setContentOffset(CGPointMake(0, 0), animated: true)
self .viewDidLayoutSubviews()
self.activeTextView = nil
}
func textViewDidBeginEditing(textView: UITextView) {
self.activeTextView = textView
scrollView.scrollEnabled = true
}
func textViewDidEndEditing(textView: UITextView) {
self.activeTextView = nil
scrollView.scrollEnabled = false
self.scrollView .setContentOffset(CGPointMake(0, 0), animated: true)
self .viewDidLayoutSubviews()
}
func textFieldDidBeginEditing(textField: UITextField) {
activeTextField = textField
scrollView.scrollEnabled = true
}
func textFieldDidEndEditing(textField: UITextField) {
activeTextField = nil
scrollView.scrollEnabled = false
}
func textFieldShouldReturn(textField: UITextField) -> Bool // called when 'return' key pressed. return NO to ignore.
{
textField.resignFirstResponder()
return true;
}
override func viewDidLoad() {
super.viewDidLoad()
var tap = UITapGestureRecognizer (target: self, action: ("tapped"))
self.view.addGestureRecognizer(tap)
self.main.delegate = self
self.initials.delegate = self
self.age.delegate = self
self.registerForKeyboardNotifications()
}
inherit your scroll view with TPKeyboardAvoiding, you don't need to code too much