How to trigger the "cancel search" when using only a UISearchBar? - ios

I have a table view with a header that displays a UISegmentedControl and a UISearchBar. Keep in mind that I am not using a UISearchController. When I have searched the current list, and I toggle a different segment, I want to cancel the search and reload the list with the new data.
Currently I am manually clearing the search text, animating the cancel button and hiding the keyboard. But I am also doing that inside my searchBarCancelButtonClicked method.
Is there a way to programmatically cancel the search (clearing the text, hiding the keyboard, and hiding the cancel button) when only using a UISearchBar?

No, there's no way to automatically clear the text field, hide the keyboard, etc. Even though it seems like common functionality, it's up to each developer to decide how to implement it. Apple just provides the ability to catch the event when the user taps the Cancel button.
Typically, I'll create a local function in the view controller like:
-(void)clearSearchBar:(UISearchBar *)searchBar {
searchBar.Text = #"";
[searchBar resignFirstResponder];
...
}
Then, in searchBarCancelButtonClicked: (assuming you've created an IBOutlet for the search bar), you can do this:
-(void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
[self clearSearchBar:self.searchBar];
}
You can then also call clearSearchBar: anywhere else you need to clear it.
Obviously, there's room to use categories here to avoid duplicating code.
You could also just call searchBarCancelButtonClicked: like this:
[self.searchBar.delegate searchBarCancelButtonClicked:self.searchBar];

Related

Saving searches from searchBar

I have a UISearchController set up in my table VC and works as expected.
However, I want to be able to save the text from searches (i.e. after they press 'search' or 'enter' on keyboard) into an array.
I couldn't find anything relevant here https://developer.apple.com/documentation/uikit/uisearchbar?language=objc and suspect the solution will involve stuff with the keyboard...
You need to implement searchBarSearchButtonClicked: and/or searchBarTextDidEndEditing: on your searchBar's delegate. These method are called whenever the user presses the search button or finishes editing the text in the search bar, respectively
There is delegate:
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar;
Inside this delegate method add searchBar.text into your desired array.

Can I have a UISearchBar be its own .inputAccessoryView?

I need simple text input to aid in data filtering. Ideally I'd like to keep a strong reference to a UISearchBar, and when the user taps "Search", then this searchBar would becomeFirstResponder() and I would set
self.searchBar.inputAccessoryView = self.searchBar
But that doesn't seem to work. The .searchBar is generally not in the view controller's view hierarchy, and is something I would just hope to attach to the keyboard.
Otherwise I'll think of another approach. Ultimately I'm just trying to have text input that I can see while editing, and that should be attached to the toolbar. Ideally with an .inputAccessoryView so I don't have to bother with keyboard notifications / animations
Does anyone know if this is possible?
If I understand you correctly, you want to use the search bar both for triggering a keyboard and for showing the search term entered by the user, but do not want to always have the search bar on-screen but have it activated via a "Search" button.
That's not possible with a single UISearchBar, but you can just use two of them:
Add one as subview to your view controller and hide it (bar1), and use the second as inputAccessoryView (bar2); you should become delegate of both search bars.
When the user presses the "Search" button make bar1 become first responder, handle its events via the delegate protocol, and update the bar2 accordingly.
Prevent the user from directly entering text in bar2 by blocking it
with the shouldChangeTextIn delegate method. Other events that are
received in bar2 could be forwarded to bar1 where this makes sense for you.
To get you started, here's some code for the basic setup (which would go in e.g. viewDidLoad):
self.dummySearchBar = UISearchBar()
dummySearchBar.isHidden = true
dummySearchBar.delegate = self
self.visibleSearchBar = UISearchBar()
visibleSearchBar.delegate = self
dummySearchBar.inputAccessoryView = visibleSearchBar
Then, in your "Search" button handler, let the keyboard with the attached search bar appear like this:
dummySearchBar.becomeFirstResponder()
Note: I have a similar setup in a project but for simplicity I use UITextFields instead of UISearchBars; still, I think the basic approach should work with UISearchBars as well.
add toolBar to searchBar
searchBar.inputAccessoryView = toolBar
hide keyboard
searchBar.endEditing(true)

Is there a way to know that iOS keyboard is really hidden (dismissed by user)?

I need a way to detect the case when user dismisses iOS keyboard manually, using "keyboard" button on keyboard. I tried to use UIKeyboardDidHideNotification, but quickly discovered that this event is also fired when user splits the keyboard, leaving it on screen.
Is there a way to know for sure that keyboard was really hidden?
To get solution I had to slightly modify my original implementation: I've replaced assigning nil to inputView member of my main view with creating and destroying custom invisible UIView<UIKeyInput> view to show and hide keyboard correspondingly. This allowed me to override this view's resignFirstResponder method which is always called on keyboard resigning - either in normal or in split state, when user dismisses keyboard using special button or when I remove it programmatically.
I believe that UIKeyboardDidHideNotification is only sent when the keyboard is truly gone. From the Apple docs:
Posted immediately after the dismissal of the keyboard.
However, you could also look to see if any of your inputs are currently the first responder:
BOOL keyboardUp = NO;
for (UIView *view in self.textInputs)
{
if (view.isFirstResponder)
{
keyboardUp = YES;
break;
}
}

Getting notified when user presses "Search" on keyboard in UISearchDisplayController

I am using a UISearchDisplayController to let the user search through a list of buildings on a university campus. Sometimes, the user will know exactly what building they want, enter the building's number, and that building will then be the only building result showing in the UITableView. At the moment, if the user proceeds to hit "Search" on the keyboard, the keyboard animates off the screen and the user then has to make a second tap on the sole item in the UITableView to be sent to a point on a map showing the location of that building.
My question is, is there a way to be notified when the user hits the "Search" button on the keyboard inside a UISearchDisplayController, so that I can perform a check to see if there's only one result, and if so, take the user straight to that result, rather than requiring them to explicitly make the second tap? I've looked at the methods provided by the UISearchDisplayDelegate, but can't see anything relevant.
UISearchDisplayController has a UISearchBar, you can set a delegate for search bar and implement -searchBarSearchButtonClicked:.
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
}
This also works with the keyboard search button.

How do I make the keyboard go away when the user clicks somewhere else? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Dismiss keyboard by touching background of UITableView
How do I make the keyboard go away when the user clicks somewhere else?
Note: I know how to make the keyboard disappear with sending the resignFirstResponder command to the UITextField. At present the "Done" button is connected to all the correct code to do this and this works.
I have a UITableView with different UITableViewCells, and if the user moves onto another cell I want the keyboard to disappear.
So what events do I also need to include the resignFirstResponder in, for the keyboard to disappear.
Suppose UITableViewCell A has the UITextField, and UITableViewCell B has a button. If the user presses the button in cell B, then I will need to send the command resignFirstResponder back to the UITextField in cell A. First of all the button has no idea which cell it should sent the command to, and second even if the button did know which cell to send the command to how would it?
There's no trivial way to do this. You can put a transparent set of "shield views" all the way around the text field that take up the rest of the screen, and use any touches on them to dismiss the keyboard.
You can create a generic 'hideKeyboard' method in which you can include all text fields that can be first responders. For example,
-(void) hideKeyboard {
[textFieldName resignFirstResponder];
[textFieldSurname resignFirstResponder];
for (UITextField * txtField in arrTextFields) {
[txtField resignFirstResponder];
}
}
Then, at various sections in your class, depending on the functionality required, call;
[self hideKeyBoard];
This simple method means you won't need to keep track of the individual item that 'has the focus' / first responder status.
How to touch any part of the screen to make the keyboard go away
To touch somewhere outside the UITableView and have the keyboard disappear, place an invisible button on top of the 'touch area' that you want to respond to. Then, simply call [self hideKeyboard] from the touch event for that invisible button. Using IB, drag a new rounded button onto your view, then size it to take up the full size of the screen. Next,drag the button up or down the controls list in the IB document window so that button is behind all text fields and buttons, but in front of anything else (like images etc.). Finally, change the type of the button to 'Custom' to make it invisible, but still respond to events. Now all you have to do is to connect the new button's 'touch up inside' event to trigger the 'hideKeyboard' method.
Additionally, see this post for a brilliant solution to dismiss the keyboard when the above solution doesn't work : stackoverflow question 1823317

Resources