iOS 11 extra space between keyboard and accessoryView - ios

I have some weird UI bug with inputAccessoryView and keyboard.
Code to add inputAccessoryView in viewDidLoad
let keyboardToolbar = UIToolbar()
keyboardToolbar.items = [
UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil),
UIBarButtonItem(title: "Hide", style: .done, target: self, action: #selector(resignFirstResponder))
]
keyboardToolbar.barStyle = barStyle
keyboardToolbar.sizeToFit()
myTextfield.inputAccessoryView = keyboardToolbar
First time entering screen and tap to textfield works good.
After closing this screen (popViewController) and entering it again and get focus to textField I've got this:
UIToolBar is above keyboard. Empty space have height = keyboard height
ui bug image

this because there is safe area in IOS 11 and this space appear on iphone X
Check this post may be duplicated
iPhone X how to handle View Controller inputAccessoryView?

I do not know the reason but workaround is to call either
view.endEditing
or
textField.resignFirstResponder()
in
viewWillDisappear

Related

Why is there empty space between my UIDatePicker and its toolbar when using the new datepickerstyle?

My iOS app uses a lot of UIDatePickers as input views for UITextFields. Before iOS 14, they worked perfectly and didn't have any issues. With the new "compact" style, though, for some reason there is a bar of transparent space in between the datepicker and its toolbar. This only happens on the iPhone X and later, so I'm assuming it's something to do with the curved screen, but I don't see what part of the code is causing the issue. Below are a code snippet of the datepicker as well as a screenshot of the issue— any help would be appreciated.
let toolbar = UIToolbar()
toolbar.sizeToFit()
let finishedButton = UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(donedatePicker))
finishedButton.tag = datePickerField!.tag
let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil)
let cancelButton = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(cancelDatePicker))
cancelButton.tag = datePickerField!.tag
toolbar.setItems([cancelButton,spaceButton,finishedButton], animated: false)
datePickerField!.inputAccessoryView = toolbar //datePickerField is the UITextField
The gray background and the "save changes" button are the actual app itself.
Apparently the new .compact style is meant to be used in place of the textfield, not as an inputview. So if you want to have it as an inputview like I do, you should just change the style back to .wheels.

Positioning UIToolbar swift

I am adding a UIToolbar to a UIPickerview programatically and I want the toolbar to be positioned directly above the picker view, which is centered in the view controller. I have used the following to center the toolbar, but the toolbar ends up on top of (in front of) my picker view:
self.toolBar.center = self.view.center
I also tried the following, but the toolbar ends up at the top of the view controller:
self.view.addSubview(self.toolBar)
How do I go about solving this positioning issue?
below is the code used to build the toolbar:
self.toolBar.barStyle = UIBarStyle.default
self.toolBar.isTranslucent = true
self.toolBar.tintColor = UIColor.white
self.toolBar.sizeToFit()
// self.toolBar.center = self.view.center
// self.view.addSubview(self.toolBar)
let doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.done, target: self, action: Selector("donePicker"))
self.toolBar.setItems([doneButton], animated: false)
self.toolBar.isUserInteractionEnabled = true
Set toolbar as an inputAccessoryView of UITextField after setting UIPickerView as inputView for textField like below,
textField.inputView = pickerView
textField.inputAccessoryView = self.toolBar
Remove adding toolBar as a subview
self.view.addSubview(self.toolBar)

Swift inputAccessoryView not attached to keyboard after rotation

I am experiencing an issue with the inputAccessoryView after ANY other view has been rotated. For example:
1) go to view A and rotate to landscape
2) then rotate back to portrait.
3) go to view B
in view B I have the below code to assign an inputAccessoryView to a UITextField However, after I rotate any view in the app, the accessory view always attaches to the top of the screen and not the top of the keyboard. If I don't rotate any view the accessory view attaches to the top of the keyboard as expected.
Here is the code used to create and assign the inputAccessoryView, it is called from the viewDidLoad
func addDoneButtonOnKeyboard(){
let doneToolbar = UIToolbar(frame: CGRect(x:0, y:0, width:320, height:50))
doneToolbar.barStyle = UIBarStyle.blackTranslucent
doneToolbar.isTranslucent = true
let flexSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace,
target: nil,
action: nil)
let doneButton = UIBarButtonItem(title: "Done",
style: UIBarButtonItemStyle.done,
target: self,
action: #selector(MyVC.doneButtonAction))
doneToolbar.setItems([flexSpace,doneButton], animated: false)
doneToolbar.sizeToFit()
doneToolbar.autoresizingMask=UIViewAutoresizing.flexibleWidth
self.myTextFild.inputAccessoryView = doneToolbar
}
I have searched SO but did not see any other questions/answers similar....
I my case the inputView was a datePicker and I had the same problem. The solution for me was:
textFieldDate.inputView?.autoresizingMask = [.flexibleHeight, .flexibleWidth]
Not sure if this helps for you as well, cause you are using a keyboard as inputView but maybe it helps others with datePicker problems.

UIButtonBarItem does not seem to fire selector

I am writing a simple iOS app in XCode 7.3, which I believe puts me using Swift 2.2. I am trying to use a UIDatePicker with UIToolbar with a UITextfield, and for some reason I tapping on the Cancel button seems not to call the method datePickerCancelled on the controller. Everything displays fine(picker, buttons , etc.), but the event won't fire. I have tried several variations of adding the selector to the UIBarButtonItem, and nothing seems to work. As you can see from the code this a pretty trivial case so it escapes why it should be this difficult. Thank you.
override func viewDidLoad() {
super.viewDidLoad()
var datePicker = UIDatePicker()
var datePickerToolbar = UIToolbar()
let doneButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Done, target: nil, action: nil)
let cancelButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Cancel, target: self, action: #selector(datePickerCancelled))
let flexSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil)
datePickerToolbar.setItems([cancelButton,flexSpace, doneButton], animated: true)
datePicker.userInteractionEnabled = true
cancelButton.enabled = true
self.dateField.inputView = datePicker
self.dateField.inputAccessoryView = datePickerToolbar
}
func datePickerCancelled(){
self.datePicker.resignFirstResponder();
}` I
The problem is this line:
var datePickerToolbar = UIToolbar()
This results in a toolbar of zero size. The Cancel button is visible, but it is outside of its superview, namely the toolbar — because the toolbar has zero size.
A view outside of its superview cannot be tapped.
You can easily confirm this by setting the toolbar's clipsToBounds to true and running the app. The Cancel button will now be invisible, because things outside the toolbar are no longer shown.
If the event did fire, your datePickerCancelled function still wouldn't do anything:
func datePickerCancelled(){
self.datePicker.resignFirstResponder();
}
Your date picker was never first responder, so that line wouldn't cause anything to happen.
Perhaps you meant this:
func datePickerCancelled(){
self.dateField.resignFirstResponder();
}

Reorganizing Toolbar and NavigationBar after TraitCollectionDidChange

I want to support a layout similar to Safari, where in horizontally regular environments, buttons are displayed on the navigation bar, but in horizontally compact environments, some buttons are on the navigation bar and some buttons are on the toolbar.
This is what I have in my traitCollectionDidChange
override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
let editingContextButton = editing ? resetButton : doneButton
if traitCollection.horizontalSizeClass == .Regular {
navigationController?.toolbarHidden = true
navigationItem.leftBarButtonItems = [editButtonItem(), helpButton]
navigationItem.rightBarButtonItems = [editingContextButton, addButton]
} else if traitCollection.horizontalSizeClass == .Compact{
navigationController?. toolbarHidden = false
navigationItem.leftBarButtonItems = [editButtonItem()]
navigationItem.rightBarButtonItems = [editingContextButton]
navigationController?.toolbarItems = [helpButton, UIBarButtonItem(barButtonSystemItem: .FlexibleSpace, target: nil, action: nil), addButton]
}
}
But it seems there is a problem when transitioning from a regular horizontal size class to a compact one. The items in the navigation bar are always correct, but the toolbar items are cut off or empty.
When bringing up the ViewController, it is always set up and displayed correctly, and it's always right in the horizontally regular size class – there's only a problem when the size class changes from regular to compact.
Here's an example, showing the add button in the bottom right disappearing from the toolbar after the change in size class.
The same thing happens when rotating the device on 5.5" iPhones, and in portrait on iPad, the toolbar is just empty after activating multitasking. What's the problem here? Thanks!
I realized that I was not setting the toolbar items correctly. Instead of
navigationController?.toolbarItems = [helpButton, UIBarButtonItem(barButtonSystemItem: .FlexibleSpace, target: nil, action: nil), addButton]
I should have done:
setToolbarItems([helpButton, UIBarButtonItem(barButtonSystemItem: .FlexibleSpace, target: nil, action: nil), addButton], animated: false)

Resources