UISearchController Needs an extra tap to become first responder - ios

I switched my apps one screen from UISearchBar to UISearchController. It's a tableview controller. As per design I should not keep the search bar on UI initially unless it is activated, (Normally it's a common practice to keep search bar as the 'tableHeaderView'). The problem was, I have a search button, when tapped 'search bar' should be activated and become first responder.
When tapped on cancel button, it should be removed from UI. However when I'm tapping on the 'Search Bar Button' on navigation bar, the UISearchController gets activated, providing a dim background but the keyboard doesn't appear. I need to tap one more time on search bar to bring the keyboard upon UI.
Here's my search bar button action:
#IBAction func onTapSearch(_ sender: AnyObject) {
self.view.addSubview(searchController.searchBar)
searchController.isActive = true
searchController.becomeFirstResponder()
isSearchActive = true
self.navigationController?.setToolbarHidden(true, animated: false)
}
I'm configuring the UISearchController in my viewDidLoad method. Let me know if that part code is any of you want to see, however it's usual code. And I verified I'm not calling anywhere resignFirstResponder() method anywhere.

try this,
Just replace this line,
searchController.becomeFirstResponder()
With this below,
searchController.searchBar.becomeFirstResponder()
Edit,
func didPresentSearchController(_ searchController1: UISearchController) {
searchController1.searchBar.becomeFirstResponder()
}
Implement this delegate method and try.

Related

How to make editingDidEnd not trigger when user tap back navigation in swift?

Currently i have an issue in editingDidEnd method of swift textfield.
I have a module inside editingDidEnd func to check some validation in B ViewController. If the validation is wrong then it shows popup / alert.
In this case, while user is typing and still focus on the textField, users tap back on navigation bar. it makes editingDidEnd function is also called. So the page is showing A ViewController and also showing pop up.
Is there any workaround to handle this issue? I don't want the alert is showing when i tap back in navigation bar. My expectation is if user press back on navigation. it's not call editingDidEnd function
Thanks Before
e.g.
B View Controller
extension bviewcontroller: textfielddelegate {
func editingDidEnd(_ value: String, textField: SearchTextField) {
//showingalert
}
}
You can add a guard statement to your editingDidEnd method like below.
func editingDidEnd(_ value: String, textField: SearchTextField) {
guard navigationController?.topViewController is bviewcontroller else {
print("DON'T SHOW ALERT")
return
}
print("SHOW ALERT")
}
I have tested the above code with a simple view controller containing a UITextField. However, your delegate method appears to be something different than the standard UITextFieldDelegate's textFieldDidEndEditing(_:) method.
Otherwise I would have suggested that you could also try experimenting with the textFieldDidEndEditing(_:reason:) method.

UIButton selector not working after button tapped within WKWebView

I have a custom titleView with 2 custom UIButtons with arrow images that allow navigation to the next view controller in the paging structure. They work perfectly fine until a button is tapped within the WKWebView. Then they don't work anymore and the selector is not called. Note that other buttons in the nav bar still work (UIBarButtonItems). The buttons work properly again after the user swipes over to the next view controller.
After looking into it some, it looks like a WKCompositingView becomes first responder and if I override becomeFirstResponder() in a WKWebView subclass, the issue goes away. I'm still a little baffled though, and would like to understand the root of the problem.
class NonFirstRespondableWebView: WKWebView {
override func becomeFirstResponder() -> Bool {
return false
}
}
Does anyone have any insight into why this is happening?
Most UI elements in swift have a UIResponder. Unhandled events are passed up the responder chain to enclosing views. My guess is that the WKWebView is absorbing all touch events once the window has become active. You can learn more about the responder chain here
Regarding a first responder. From the docs:
The first responder is usually the first object in a responder chain to receive an event or action message. In most cases, the first responder is a view object that the user selects or activates with the mouse or keyboard.
Assuming you want to keep interactivity with the WKWebView fully functional (e.g. you need to bring up a keyboard or something), you can use
webView.resignFirstResponder()
To resign the responder at any time.
Otherwise, an extension that would give you the same functionality might look something like this:
extension WKWebView {
open override func becomeFirstResponder() -> Bool {
if self.superview?.superview is UIWebView {
return false
} else {
return super.becomeFirstResponder()
}
}
}

How to change UIBarButtonItem text during runtime "cleanly" (Edit --> Done --> Edit)?

I'm trying to change UIBarButtonItem text "cleanly" during runtime so that Edit/Done modes can be toggled. Every time I change the title attribute during runtime, however, the animation seems clumsy. I'm looking to emulate the appearance and function of the Edit/Done button in the Contacts app (where Edit simply fades and Done appears in its place).
#IBAction func editDoneButtonPressed(sender: UIBarButtonItem) {
if(sender.title == "Edit"){
sender.title = "Done"
}else{
sender.title = "Edit"
}
}
Initial settings: Identifier is set to "custom" and Title is set to "Edit"
Simpler programatical solutions are preferred, however, the appearance of the animation is indeed paramount. I'd consider toggling the UIBarButtonItem identifier, rather than its text attribute, however, I'm not sure of an elegant way to toggle the identifier during runtime.
BTW: I'm using Swift to construct the app.
Links to...
Screencast of Contacts app Edit/Done toggle animation:
https://youtu.be/5mT_vzpNhIw
Screencast of my Edit/Done toggle animation:
https://youtu.be/mEweotJNVNE
Thank you.
There's a much better way, a standard way, to get an Edit/Done button.
UIViewController provides a standard Edit/Done button that is already hooked into the editing property of the view controller.
A common usage is as follows:
Inside the viewDidLoad method of your view controller, use the standard button:
self.navigationItem.rightBarButtonItem = editButtonItem
Put the editButtonItem wherever you actually need it.
Then, instead of setting up your own action, simply override the setEditing(_:animated:) method:
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
if (editing) {
// user just tapped the Edit button (it now says Done)
} else {
// user just tapped the Done button (it now says Edit)
}
}

What is triggered when "Done" is pressed after changing from "Edit" in UINavigationItem bar for UITableViewController?

Short: In Swift/iOS, when does the "Done" (which was previously "Edit") nav bar button trigger when getting out of the UITableViewController "Edit" mode? When the user presses "Done" I'd like to enable a "+" button in my UINavigationItem bar so the user can once-again add rows by migrating to another view controller.
Longer: When a UITableViewController is showing below a UINavigationItem nav bar, there is an "Edit" button which turns into "Done" after it's clicked to enable deletes & move/drags. Works great when this button is enabled via uncommenting code in viewDidLoad() generated as part of the UITableViewController class:
self.navigationItem.leftBarButtonItem = self.editButtonItem
I've got my move/drags & deletes working fine, but I want to appropriately disable my "+" button (addBarButton, used for navigating to another view controller to add a new row) while the user is in the Edit mode. I'd then like to re-enable addBarButton after the user has clicked "Done" (which turns back into "Edit").
It looks like disabling addBarButton during the func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) is correct. If I read Apple's docs right, this is triggered when user presses Edit in the nav bar. What I don't know is what is triggered when the user presses "Done" (the button formerly labeled "Edit"). If I enable my addBarButton "+" button after the func tableView with moveRowAt, this enables addBarButton before the user has pressed "Done".
The Apple doc I'm referencing is at:
https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/TableView_iPhone/ManageReorderRow/ManageReorderRow.html#//apple_ref/doc/uid/TP40007451-CH11-SW1
Apologies if I'm missing something obvious. Thx
The answer is right in the description for the UIViewController editButtonItem documentation:
If one of the custom views of the navigationItem property is set to the returned object, the associated navigation bar displays an Edit button if isEditing is false and a Done button if isEditing is true. The default button action invokes the setEditing(_:animated:) method.
The last sentence is the key. You should override the setEditing(_:animated:) method in your table view controller subclass. Be sure you call the super implementation and then perform whatever custom action you want based on whether the controller is entering or exiting editing mode.
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
if (editing) {
// User tapped the Edit button, do what you need
} else {
// User tapped the Done button, do what you need
}
}

Prevent UISearchBarController to show UINavigationBar

I'm using a UINavigationBar ALWAYS hidden (I'm using NavigationBar facilities to push ou pop views but I'm not showing it to final user), the problem is that in one of those views I have a tableView with UISearchBar. When I select the searchBar, make a search and click on it's "Cancel" button the NavigationBar appears, but I want to keep the Navigation hidden as it is.
I've tried to hidden the navigationBar one more time by willDismissSearchController or didDismissSearchController by
func willDismissSearchController(searchController: UISearchController) {
self.navigationController?.navigationBar.hidden = true
}
but it did not worked as I want.
Thank you in advance.
I've found a solution, so as it is a unusual question I'll reply for other people know the solution.
the following code did worked for me:
override func viewDidLayoutSubviews() {
self.navigationController?.navigationBar.hidden = true
}

Resources