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();
}
Related
Update: This bug has been fixed in iOS 14.5
I have the following class embedded in a UINavigationController:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let barButton = UIBarButtonItem(title: "Save", style: .plain, target: nil, action: nil)
barButton.accessibilityLabel = "Save meeting"
navigationItem.rightBarButtonItem = barButton
}
}
When running iOS 14.4, the accessibility label is ignored and only the visible title is announced by VoiceOver. However, on iOS 13.7, the accessibility label is correctly used. Has the UIBarButtonItem usage changed or is this an iOS bug?
Screenshot for context:
When I must implement a UIBarButtonItem, I always follow these instructions to be sure that a11y will be stable and completely functional. π
I don't know if this situation is a bug or a kind of regression due to the new iOS version but implementing a11y in the navigation bar buttons as customization is a perfect way to encounter no unfortunate surprises even if it looks like a boilerplate solution. π€
I've created a blank project with a simple view controller embedded in a navigation controller where a right bar button is displayed as follows:
class NavBarViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
var a11yRightBarButton: UIBarButtonItem?
let a11y = UILabel()
a11y.text = "OK"
a11y.sizeToFit()
a11y.isUserInteractionEnabled = true //Mandatory to use the 'tap gesture'.
a11yRightBarButton = UIBarButtonItem(customView: a11y)
let tap = UITapGestureRecognizer(target: self,
action: #selector(validateActions(info:)))
a11yRightBarButton?.customView?.addGestureRecognizer(tap)
a11yRightBarButton?.isAccessibilityElement = true
a11yRightBarButton?.accessibilityTraits = .button
a11yRightBarButton?.accessibilityLabel = "validate your actions"
navigationItem.rightBarButtonItem = a11yRightBarButton
}
#objc func validateActions(info: Bool) -> Bool {
print("hello")
return true
}
}
Your right bar button displays "OK" and VoiceOver reads out "validate your actions" under iOS 14.4 and Xcode 12.4. π
Following this rationale, you can use a UIBarButtonItem as supporting the accessibilityLabel property in iOS 14. π
Set accessibility of UIBarButtonItem to true.
let barButton = UIBarButtonItem(title: "Save", style: .plain, target: nil, action: nil)
barButton.accessibilityLabel = "Save meeting"
barButton.isAccessibilityElement = true
navigationItem.rightBarButtonItem = barButton
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.
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
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.
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)