I am trying to implement a very basic chat feature into my app and I am using constraints to keep everything in the correct place. It is great except for when I need to actually type, and the problem that arises is that the keyboard covers the text field and I not only cannot see the textfield but I cannot dismiss it. Thank you for all help!
In summary,
Using a textfield with contraints at bottom of screen
keyboard shows up and covers it, and I cannot dismiss the keyboard
Just set observers for UIKeyboardWillShowNotification and UIKeyboardWillHideNotification.
Whenever, UIKeyboardWillShowNotification is triggered, move the UITextfield upwards equivalent to the keyboard height. Then, when the UIKeyboardWillHideNotification is triggered, move the keyboard back into place.
Dismiss keyboard by tapping anywhere
override func viewDidLoad()
{
super.viewDidLoad()
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "dismissKeyboard")
view.addGestureRecognizer(tap)}
func dismissKeyboard()
{
view.endEditing(true)
}
Related
When a user taps on a button, I'd like the keyboard to pop up (which is easy), but I want a view that goes up along with it (sticking to the top of the keyboard). This view will be have a "send a message.." textfield. When the user pushes done, I want the keyboard to go away along with the view.
How do I make this view "stick" to the keyboard?
UITextFields have a property called inputAccessoryView
- Apple Documentation
- Relevant Stack Overflow Answer
This will pin whatever view you assign as that textfield's inputAccessoryView to the top of the keyboard.
Something important from the answer in that link to remember:
Note that the view you use should neither be in the view hierarchy elsewhere, nor should you add it to some superview, this is done for you.
go to your storyboard and add a view(lets call it topKeyboardView) at the bottom of your viewController. and give it the following constraints:
bottom space to bottom layout = 0
and then add the textfield*(i prefer using textView to make it change its height when the message gets too long...)*
and your button(send) on top of topKeyboardView.
lets code now..
go to your viewController.swift and add an IBOutlet to your textField and button and add this function:
//this is will tell if the keyboard hidden or not
func addKeyboardNotifications() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name:UIKeyboardWillHideNotification, object: nil)
}
// MARK:- Notification
func keyboardWillShow(notification: NSNotification) {
print("keyboard is up")
}
func keyboardWillHide(notification: NSNotification) {
print("keyboard is down")
}
in your viewDidLoad call the function:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
addKeyboardNotifications()
}
run it...
When a user taps on a button, I'd like the keyboard to pop up (which is easy), but I want a view that goes up along with it (sticking to the top of the keyboard). This view will be have a "send a message.." textfield. When the user pushes done, I want the keyboard to go away along with the view.
How do I make this view "stick" to the keyboard?
UITextFields have a property called inputAccessoryView
- Apple Documentation
- Relevant Stack Overflow Answer
This will pin whatever view you assign as that textfield's inputAccessoryView to the top of the keyboard.
Something important from the answer in that link to remember:
Note that the view you use should neither be in the view hierarchy elsewhere, nor should you add it to some superview, this is done for you.
go to your storyboard and add a view(lets call it topKeyboardView) at the bottom of your viewController. and give it the following constraints:
bottom space to bottom layout = 0
and then add the textfield*(i prefer using textView to make it change its height when the message gets too long...)*
and your button(send) on top of topKeyboardView.
lets code now..
go to your viewController.swift and add an IBOutlet to your textField and button and add this function:
//this is will tell if the keyboard hidden or not
func addKeyboardNotifications() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name:UIKeyboardWillHideNotification, object: nil)
}
// MARK:- Notification
func keyboardWillShow(notification: NSNotification) {
print("keyboard is up")
}
func keyboardWillHide(notification: NSNotification) {
print("keyboard is down")
}
in your viewDidLoad call the function:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
addKeyboardNotifications()
}
run it...
I have a UITextfield with an inputView of PickerView. I want to achieve that when users double tap on the UITextfield, the pickerView shows up modally, like default, and the focus of accessibility changes from the textfield to the pickerView. This is how I do it for now:
func textFieldDidBeginEditing(textField: UITextField) {
let dispatchTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(0.65 * Double(NSEC_PER_SEC)))
dispatch_after(dispatchTime, dispatch_get_main_queue(), {
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, self.quantityPicker)})
}
This delegate simply gets called when user double taps the textField and send a UIAccessibilityLayoutChangedNotification after a delay of 0.65 seconds to focus on pickerView.
Then questions are:
I used a delay here to wait for the pickerView pop-up animation to be done, but it will be much better if I can know that pickerView animation is done somewhere and put
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, self.quantityPicker)
there. So is there any delegate or other simple way to know that pickerView is ready to use?
When I double tap the textField, it will read the content of the textField first until it gets intercepted. Is there anyway to disable this to make it like: when I single tap the button, read accessibilityLabel, trait, hints etc, and when I double tap it, it reads nothing and just does its job.
You can use notification centre event UIKeyboardDidShowNotification. In the view controller hosting the UITextField add code to viewWillAppear method:
NSNotificationCenter.defaultCenter().addObserver(self,
selector: #selector(self.keyboardDidShow(_:)),
name: UIKeyboardDidShowNotification,
object: nil)
In the viewWillDisappear method add:
NSNotificationCenter.defaultCenter().removeObserver(self)
Then add a method keyboardDidShow:
func keyboardDidShow(notification:NSNotification) {
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, self.quantityPicker)
}
Of course if you have other input fields in your view controller you'll need to add some conditional code to keyboardDidShow.
Tested and working. Thanks for the question, I've been chasing the same issue.
If you present the view as part of a separate modal view controller, you can use the viewDidAppear method as the callback you are looking for.
-(void)viewDidAppear:(BOOL)animated {
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, outletOfViewYouWantFocused);
}
#Dale's answer in Swift 4:
viewWillAppear
NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidShow(notification:)), name: UIResponder.keyboardDidShowNotification, object: nil)
viewWillDisappear
NotificationCenter.default.removeObserver(self)
keyboardDidShow
#objc func keyboardDidShow(notification: Notification) {
UIAccessibility.post(notification: .layoutChanged, argument: self.quantityPicker)
}
I have developed an app that makes use of the iOS8 feature to show or hide the navigation bar on a tap of the view.
However, the main view contains a UIButton which also act upon taps. The problem is that both 'objects' are receiving the tap and if I tap the button, the navigation bar toggles its visibility.
I can get to the barHideOnTapGestureRecognizer via the navigation controller but not really sure what can be done with it to stop it responding if a button is tapped.
Is there a way (apart from switching off or changing to 'Swipe to Hide') to subdue the navigation bar's appearance/disappearance when a button is pressed?
Don't use the standard barHideOnTapGestureRecognizer. Fortunately, it's not hard to roll your own:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let gestureRecognizer = UITapGestureRecognizer(target: self, action: "toggleBarsOnTap:")
self.view.addGestureRecognizer(gestureRecognizer)
}
func toggleBarsOnTap(sender: AnyObject?) {
let hidden = !self.navigationBarHidden
self.setNavigationBarHidden(hidden, animated: true)
self.setToolbarHidden(hidden, animated: true)
}
Taps on the view will show/hide the bars, and taps on controls (subviews of the view) will not.
[self.navigationController setNavigationBarHidden:YES];
The scrollview takes up the whole viewcontroller. A textview is placed in the scrollview. I wish to dismiss the keyboard when the use taps outside of the keyboard.
boostContent is the IBOutlet of the textview.
I've tried the code below and it doesn't work.
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
self.scrollView.endEditing(true)
boostContent.resignFirstResponder()
}
What's the correct solution?
I've also tried self.view.endEditing(true)
Add a Tap Gesture Recognizer to the same view holding your text view. Wire it up to this:
#IBAction func tapped(sender: AnyObject) {
boostContent.resignFirstResponder()
}
I think the issue with what you were trying to do is that your touchesBegan wasn't being called because it is defined on your ViewController and the content view of the scroll view is intercepting the touches.
One way is to add a tap gesture to your view controller and resign the first responder there. The other way, and I think is a better one, is to use a container view. You put it inside you scrollview and then put all your objects, including the textfield, in the container view.