UISearchBar Cancel button is visible but doesn't work - ios

I have the same problem as Using becomeFirstResponder causes cancel button to not work, except that the solution doesn't work in my case.
I created a storyboard project with a Navigation controller and a Table view controller in it. I added a UISearchDisplayController to the table view and all works well until I try to access the searchDisplayController as seen below in the code snippet. I am using a section index and added UITableViewIndexSearch (or #"{search}") to the top of the section titles so that the magnifying glass shows at the beginning of the A - Z index. When I click on the section index the following function is called:
- (NSInteger) tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
if ([title isEqualToString:UITableViewIndexSearch])
{
[self.searchDisplayController setActive:TRUE animated:TRUE]; // Either of these two lines
[self.searchDisplayController.searchBar becomeFirstResponder]; // will cause the search bar cancel button to not work
return 0;
}
return index - 1;
}
If I comment out both of the lines that access searchDisplayController then the search bar cancel button works as expected. If either of the two lines is not commented out in the code then the cancel button on the search bar acts as if it were not even there. Removing the becomeFirstResponder line means that I must click/touch in the search bar field to transfer focus to it, so in this case when I click on the cancel button the search bar gets focus. It's as if the cancel button is seen transparently through the search bar but can't be clicked/touched. Take those two lines of code out and the cancel button works again.
What the heck is going on?

Related

Navigation Bar Search Results

I would like to add an search directly to my navigation bar (like Apple Maps).
So thats no the problem, I'll just create it as Searchbar:
searchBar.placeholder = "Gebäude und Räume suchen"
var rightNavBarButton = UIBarButtonItem(customView: searchBar)
self.navigationItem.rightBarButtonItem = rightNavBarButton
But how should i solve to see the results? First ill tried to use an Adaptive Popover, and if the user enters at least 2 letters ill load the popover and show the results (so I am able to show an Popover on the iPad, and get a Fullscreen View on the iPhone) - but here i need to check on every keypress if the popover is still visible, AND if there is an adaptive popover I need to create the searchbar on the child-controller too.
So I am not sure how to solve such things like Apple Maps (iPhone and iPad Version) - can anyone give me some tipps how can I do that? Is that a Popover? A Custom View?
Edit:
The easiest way (and this is how its atm looks like) - I have a Button with an Search Icon, and if the user clicks on this SearchButton, ill load an "Search" Controller (with an Searchbar) - if the user clicks on one Result ill go "back" and show the result on the Map.
But I would prefer to make it like the Apple Maps App (with the difference between iPad and iPhone Version)
I can see why this is confusing. The functionality you are looking for used to be provided by UISearchDisplayController and UISearchDisplayDelegate. But these methods are deprecated in iOS 8.
The way to go these days is to use a UISearchController. The docs explain it pretty well:
You create a new search controller using the initWithSearchResultsController: method, passing in the view controller that manages the contents to be displayed. The searchResultsUpdater property contains the object that is responsible for updating the results. Often the object contained in the searchResultsUpdater property is the same as the view controller set during initialization. However, if you have created your own model object to filter and respond to queries, you can set it as the searchResultsUpdater.
The callback mechanism for presenting and dismissing the search results is provided by the UISearchControllerDelegate.
What apple do in iPad is using a UIPopover, i have previously done exactly the same thing for custom Maps app using the following delegates:
-(void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
//init a searchPopover with the view you want to show the results in and then call it
[self.searchPopover presentPopoverFromRect:[self.search bounds] inView:self.search permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
- (void)searchBarTextDidEndEditing:(UISearchBar *)aSearchBar
{
[self.searchPopover dismissPopoverAnimated:YES];;
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
//update the tableview that is in the searchPopover
//searchView is the view inside the popOver, filterResults is a custom method with an NSPredicate inside.
[self.searchView filterResultsUsingString:searchText];
}
In the view controller that will display the result, you implement delegation, so that when the user presses the desired button or row in that view, the parentview is notidifed and the popover is dismissed, you zoom on the annotation you want.
-(void)didSelectResult:(id)annotation
{
//so when you select the result, and call this delegate method:
self.annotationToSelect = annotation;
[self.searchBar resignFirstResponder];
self.search.text = #"";
[self.searchPopover dismissPopoverAnimated:YES];
}

How to associate iOS keyboard "go" button with UIButton?

I have a search bar in my SearchViewController, and currently, when they type into it, there's no Go button, it shows only return. I want a Go button to show in the keyboard, and I want it to be connected to the - (IBAction)nextButton:(id)sender that I have connected to the existing next UIButton under the search bar.
How do I go about enabling this and connecting it in this way? To clarify, the search bar and next button were created in storyboard, not programmatically.
[textField setReturnKeyType:UIReturnKeyGo];
or
- (void)setReturnKey {
//use condition here(not empty field)
self.searchField.returnKeyType = UIReturnKeyGo;
}
the other thing as Ghobs said you can find here...
- (BOOL) textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];//Dismiss the keyboard.
//Add action you want to call here.
return YES;
}
source for above code:Action of the "Go" button of the ios keyboard
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITextInputTraits_Protocol/index.html#//apple_ref/c/tdef/UIReturnKeyType

How can I assign a pointer to the keyboard before I have assigned first responder

I am trying to create a user interface enabling users to switch between the keyboard and other menus when using a chat application.
On a click of the textField bar I want to raise either the keyboard or a collection view.
The problem occurs when I click the 'menu' button. I want the textField bar to raise revealing my menu view. Then, on a click on the keyboard button, instantly switch to the keyboard, rather than having it slide up from the bottom. This means I need to have the keyboard already loaded and hidden but in the background of the app.
Currently though the earliest I am managing to assign a variable to the keyboard is in the keyboardDidShow function.
-(void) keyboardDidShow: (NSNotification *) notification {
// Get the window the keyboard is a subview of
_window = [UIApplication sharedApplication].windows.lastObject;
_keyboard = _window.subviews[0];
}
This means that after it has been loaded once I can hide and reveal it, but I don't want it visible when it is loading this first time.
To achieve this using alternate means I have tried adding my extra views as subviews of the UIWindow the keyboard is created in:
[_window addSubview:_menuView];
[_window addSubview:_gamesView];
[_window addSubview:_stickerView];
[self hideSpecificView];
Unfortunately I keep coming across the same problem, until I have loaded the keyboard once it needs to fully load before I can get a pointer to it to hide it.
Here is a picture of my toolBar incase I am not being clear:
On clicking the menu icon or the stickers icon I want the bar to raise with a collection view. If I then click the textfield, with these views visible, I want to hide the visible view to immediately show the keyboard behind.
I have also tried experimenting with keyboardWillShow but as the window hasn't been loaded in front our screen I can't get a pointer to the keyboard to hide it before it loads.
An example of what I am after can be found many chat apps (facebook messenger, LINE, Kakao Talk)
Any help would be greatly appreciated
Although the way I came up with isn't perfect it works almost perfectly so hopefully this might help people in the future. If anyone else has solved it differently please post as it would be interesting to know how you did it.
I started by adding a class variable to a UIWindow in my header file and then setting off a timer to ping just after the keyboard will show method finishes. After this method has finished the keyboard has been created, just, and so I allocate it and hide it.
-(void) keyboardWillShow: (NSNotification *) notification {
// More keyboard code
_window = [UIApplication sharedApplication].windows.lastObject;
[NSTimer scheduledTimerWithTimeInterval:0.01
target:self
selector:#selector(allocateKeyboard)
userInfo:nil
repeats:NO];
}
- (void)allocateKeyboard {
if (!_keyboard) {
_keyboard = _window.subviews[0];
}
_keyboard.hidden = YES;
[self setViewForButtonType];
}
I have already previously added my other views, hidden them and constrained them to the bottom of the main view, this means that when the keyboard rises they do too.
- (void)viewDidLoad {
[self.view addSubview:_menuView];
[self.view addSubview:_gamesView];
[self.view addSubview:_stickerView];
}
...
- (void)hideViews {
_keyboard.hidden = YES;
_menuView.hidden = YES;
_gamesView.hidden = YES;
_stickerView.hidden = YES;
}
When buttons get pressed I simple then unhide the view that I want to see and hide the rest of the views.
When I say that this method doesn't work perfectly it is because if you load view main view and then click a button before the keyboard has loaded for the first time then you get a quick glimpse of the keyboard before the view appears over the top. This though only happens the first time and only if they don't click in the text field first.
Anyway, I found this was the best way of making views look like they are in front of the keyboard. Obviously my code was a lot longer and more complex (too long for here) but this is the gist of the method I used to solve it. Comment if you have any queries and I hope this helps.

How do I hide a button so that it turns see-through rather than white?

I am trying to program a view which has a list of exercises in a table view. The user can either swipe them to delete or go into edit mode and click multiple rows to delete faster (much like in mail).
At the bottom of the screen there is a finish button where the user will click when s/he has finished choosing the exercises they want in their workout. Currently I am trying to bring up the toolbar when the user enters edit mode to allow them to delete their multiple choices. When this happens the view is compressed and so the finish button raises up above the toolbar. This isn't what I want as it looks stupid to be able to finish while editing something else.
I have tried hiding the button but this leaves a white square just above the toolbar
I am not sure if I need to make the button transparent or if I am hiding it incorrectly.
How can I have the bottom button disappear completely when edit mode is entered to the extent it doesn't affect my table view and then reappear and almost 'swap' with the tool bar when editing mode is exited?
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
// Activates multiple selection
exercisesSelectedTableView.allowsMultipleSelectionDuringEditing = editing;
// Lets us know we have clicked editing - changes it to done
[super setEditing:editing animated:animated];
if (editing) {
// This bit is done when someone clicks edit
// Sets the view into editing mode
[exercisesSelectedTableView setEditing:editing animated:YES];
// Unhides the tool bar
[self.navigationController setToolbarHidden:NO animated:YES];
// Hides the finish button
[finishedButton setHidden:YES];
}
else {
// This bit is called once someone clicks done
[self.navigationController setToolbarHidden:YES animated:YES];
// Reveals finish button
[finishedButton setHidden:NO];
[super setEditing:NO animated:YES];
[exercisesSelectedTableView setEditing:NO animated:YES];
}
}
Found the answer to this out eventually.
Using the setToolBarHidden works fine but in the XIB file I needed to check that the table view went all the way down to the bottom of the view. As it was the table view only went to the top of the finished button. Therefore when it was hidden it left the white gap I assumed was the shadow of the button.
Morale of the story: Check the XIB files carefully

How do I programmatically get the state of UIBarButtonItems?

With a UIControl such as a UIButton you can use something like
myControl.state
to figure out whether the control is currently being pressed down.
However, I need to do the same with some UIBarButtonItems (which are not derived from UIControl), so that I can stop my table from editing while one of them is pressed down.
Here's my code:
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
//other checks
for(int b=0; b<self.toolbar.items.count; b++)
{
UIControl *currentControl= [self.toolbar.items objectAtIndex:b];
if(currentControl.state==UIControlStateHighlighted)
{
return NO;
}
}
return YES;
}
Obviously, it doesn't work, since it assumes that UIBarButtonItems can be treated as UIControls, but how would I do what I'm trying to do here?
If you want more control over your UIBarButtonItems the best thing to do is to recreate them as UIButtons (using custom art, etc), and then use the -initWithCustomView of UIBarButtonItem to create button items from actual UIViews.
This will give you full access to the usual button interactions methods: the only downside is you won't get the nice bar button style by default, and you'll have to provide the art for this yourself.
I had a similar problem before. I couldn't fix it, so I moved on. Here is what I did:
Use ToolBar instead of navigation bar, then use UIButton instead of UIBarButtonItem inside the toolbar.

Resources