UISearchBar in UIView - objective-c

I'm having difficulty following directions. I have a UISearchBar in a UIView. The user will enter the search string into the UISearchBar and click the search icon to search. The results will display in a new window (UITableView).
My search has shown me this:
A UISearchDisplayController cannot be added to a UIView because it
doesn't inherit from a UIView. You can add a UISearchBar in Interface
builder with an IBOutlet and then create a UISearchDisplayController
with that UISearchBar programmatically.
Just do it in code e.g. (assuming the view controller is vc): [vc
addSubview:mySearchDisplayController.searchBar]; // Note that
searchBar is the view, and mySearchDisplayController only CONTROLS the
searchBar etc.
and also this:
Just make your view controller implement the UISearchBarDelegate. In
your xib file, all you need to do is to add a UISearchBar to your view
and configure it as necessary, create an outlet for it (optional
really but helps to be explicit), and assign the delegate outlet to
your view controller. Then, to respond to the search bar events,
implement the UISearchBarDelegate protocol methods as necessary. For
example:
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
[self handleSearch:searchBar]; }
(void)searchBarTextDidEndEditing:(UISearchBar *)searchBar {
[self handleSearch:searchBar]; }
(void)handleSearch:(UISearchBar *)searchBar {
NSLog(#"User searched for %#", searchBar.text);
[searchBar resignFirstResponder]; // if you want the keyboard to go away }
(void)searchBarCancelButtonClicked:(UISearchBar *) searchBar {
NSLog(#"User canceled search");
[searchBar resignFirstResponder]; // if you want the keyboard to go away }
I'm just not getting it! Should I be adding mySearchController to my UIView? or my UISearchBar? Adding it to my UIView, nothing happens; adding it to my UISearchBar really wigs out the application. I don't even get an error - it just hangs.
Then, there is the second part: The delegate. Should I put the delegate in my UIView? Or in the UISearchDisplayController? Not sure which direction to go in and nothing so far is working. Please help.
All I really want at this point is just to get the handleSearch method to get executed. Thank you very much in advance for any help.
Very confused.

The idea is that you create a Search Bar in Interface Builder as an outlet and then use the following code to create UISearchDisplayController:
self.searchDisplayController2 = [[UISearchDisplayController alloc] initWithSearchBar:self.searchBar contentsController:self];
self.searchDisplayController2.delegate = self;
self.searchDisplayController2.searchResultsDelegate = self;
self.searchDisplayController2.searchResultsDataSource = self;
This code would be implemented in your View Controller, say in viewDidLoad. You will also have to implement at least two delegate functions in the same VC:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

Related

UITableView Swipe to delete not working properly on iOS8

I have a view controller, having a uitableview inside a uiview. The delegate and datasource embeded properly and everything is working fine.
I am using commitEditingStyle and canEditRowAtIndexPathMethods delegate methods for swipe to delete functionality.
The usage of methods are as follows.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
NSDictionary *dataElement = [cartArray objectAtIndex:indexPath.row];
NSString *productId = [dataElement objectForKey:#"id"];
NSString *productSizeId = [dataElement objectForKey:#"beden_id"];
[self deleteTableRowWithId:productId sizeId:productSizeId];
}
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath{
return YES;
}
The swipe gesture and delegate methods are working very fine without any problem on iOS7 tested both on emulator and device, however on iOS8 the swipe gesture doesn't work properly.
I tested this on iOS8 using iPhone 6 and to activate swipe I need to swipe like 20 times or more and from the edge table cell, sometimes cant even manage to get the swipe delete button at all.
I checked and tried most of the solutions on stack-overflow. Any help or suggestion will be deeply appreciated.
Hierarchy in the storyboard is like in the picture below.
Same issue, swipes would only work about 20% of the time on both simulator and device. In my case it was caused by ECSlidingViewController (a popular sliding menu implementation), which sets up a horizontal pan gesture to open the menu. This gesture needs to be disabled in the viewDidAppear: of the controller where you want swipe-to-delete to work properly:
#import "ECSlidingViewController.h"
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// Disable sliding menu pan gesture so it doesn't conflict with table view swipe-to-delete
self.slidingViewController.panGesture.enabled = NO;
}
Make sure to re-enable the pan gesture if you want other controllers to be able to use it:
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
// Re-enable sliding menu pan gesture so other controllers can use it
self.slidingViewController.panGesture.enabled = YES;
}
See this pull request for more info on the issue: https://github.com/ECSlidingViewController/ECSlidingViewController/pull/70
Long story short, whether you're using ECSlidingViewController or not, make sure there are no other pan gestures set up that collide with the swipe-to-delete pan gesture.
Sometimes, there are other gesture recognizers than just the panGesture. If you want to retain the pan gesture or other recognizers, and still allow swipe to delete, I have accomplished such with the following category in the visible view controller:
#interface UIView (CellSwipeAdditions)
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
#end
#implementation UIView (CellSwipeAdditions)
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
#end

Cannot dismiss the Search view

I have a parent class with tableview and searchbar over it which is a subclass of tableview controller. Delegates for the searchBar and searchdisplaycontroller are set in a seperate class inherited from UISearchdisplaycontroller. The datasource and delegates for tableview and searchbar are handled in this class seperately. The classes are under ARC.
Hence, When a user taps on search, the control transfers from FilesListController (parent)class to this class. Now, When a user taps on cancel button, the searchbar delegate set in this class i.e.
- (void)searchBarCancelButtonClicked:(UISearchBar *) searchBar
is CALLED but DOESN'T serve the purpose of dismissing the full screen searchtableview and return to the parentviewcontroller. However, if I don't write this delegate in the search class, it works properly. I have set the searchbar delegates in xib and on calling:
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
like this:
self.searchResultsTableView.delegate = self;
self.searchResultsTableView.dataSource = self;
[parentFileViewController.searchDisplayController setDelegate:self];
Where am I going wrong? Thanks in advance.
If you want to dismiss a UISearchBar with a SearchBarController, just use this Code:
[self.searchDisplayController setActive:NO animated:YES];
you should implement resign the responder in the delegate function i.e
- (void)searchBarCancelButtonClicked:(UISearchBar *) searchBar {
[searchBar resignFirstResponder];
}
Memory warnings can appear at any time during the application run time, you must assume a memory warning will happen and the view and disposable objects will have to be recreated.
We are handling such situation by setting to nil our arrays:
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
if([self isViewLoaded] && self.view.window == nil)
{
self.view = nil;
keys = nil;
names = nil;
errorDuringNetworkCall = nil;
}
}
And by dismissing the search bar tableview before performing the segue operation:
[self performSegueWithIdentifier:#"navigateToNextScreen" sender:self];
self.searchBar.text = #"";
[self.searchDisplayController setActive:NO animated:YES];
After a Memory warning is received the viewDidLoad method is called again and the arrays are populated, the search bar will continue to be useful.work without issues

UISearchDisplayController without a UITableView

Is it possible to implement a UISearchDisplayController without a UITableView? Or at least hide the TableView?
Just create an instance of UISearchBar in your view and implement the UISearchBarDelegate protocol. Make sure your view is set as the delegate for the search bar as well. When the user clicks the done button it will send a message to the delegate method searchBarSearchButtonClicked:
- (void) viewDidLoad {
[super viewDidLoad];
self.searchBar.delegate = self;
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
// Handle search request
}
You just need to either place the UISearchBar in your nib file or place it programmatically.

How to update DetailView using MasterDetail Application Template

I'm new to using the split view for creating iPad applications. When I first create the project just using the standard MasterDetail Application template (Xcode 4.2), it creates a MasterViewController and a DetailViewController. The template has the following method that is called when a row is selected from the popover table (master detail view controller):
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
if (!self.detailViewController)
{
self.detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
}
[self.navigationController pushViewController:self.detailViewController animated:YES];
Now I understand when you are using a regular navigation controller if you are programing for an iPhone you just do this type of thing to push on another view controller on to the stack. However, with this template, it just pushes the detail view onto the popover rather than updating what is already present. I'm confused as what I need to update to select something from the pop over (master detail view), and then have the detailView update.
Update:
To try and test out the "detailItem" that is already setup for you in the DetailViewController, I commented out the pushViewController and added the following:
//[self.navigationController pushViewController:self.detailViewController animated:YES];
self.detailViewController.detailItem = #"Test";
// setter in detailViewController
- (void)setDetailItem:(id)newDetailItem
{
if (_detailItem != newDetailItem) {
_detailItem = newDetailItem;
// Update the view.
[self configureView];
}
if (self.masterPopoverController != nil) {
[self.masterPopoverController dismissPopoverAnimated:YES];
}
}
- (void)configureView
{
// Update the user interface for the detail item.
// detailDescriptionLabel.text is a IBOutlet to the label on the detailView
if (self.detailItem) {
self.detailDescriptionLabel.text = [self.detailItem description];
}
}
According to this code, the text of the label on the detailViewController should be updated. However, when I do click on the item in the master view controller table, nothing happens.
There are a couple different ways you could do it. First off, like you said, remove the pushViewController call (I don't know why Apple's template does this... maybe just to show you you can?).
Next, let your MasterViewController know about the DetailViewController that is already displayed. I usually set master.detailViewController = detailViewController in the appDelegate.
Remember, the DetailViewController is already being displayed, so you won't always need to realloc it (unless you are replacing it with some other view)
First Option
Use delegate calls to set the information. Declare a protocol to pass information to the detailView and have it display it appropriately. Here is a tutorial describing this in more detail.
Second Option
Pass DetailViewController some data & override the setter to refresh the detailView. Here is a tutorial describing this in more detail.
// in DetailViewController
- (void)setDetailItem:(id)newDetailItem {
if (detailItem != newDetailItem) {
[detailItem release];
detailItem = [newDetailItem retain];
// Update the view.
navigationBar.topItem.title = detailItem;
NSString * imageName = [NSString stringWithFormat:#"%#.png",detailItem];
[self.fruitImageView setImage:[UIImage imageNamed:imageName]];
}
}
Edit: Just looked at the template again, and setDetailItem type code is already in there, but the code is creating a completely new detailView so the detailView that is viewable on the splitViewController is not changed at all.

How to load a table from a .nib when an item in a previous table is selected?

At the moment, I have an iOS app that starts out with a NavigationView (root view) and a table contained in the root view below the navigation bar. I am attempting to load another view (hoping to make it another table) from a .nib file when the first row in the original table is selected. How can I do this?
Any help or advice would be appreciated. Thank you very much.
You need to make use of the UITableViewDelegate method, tableView:didSelectRowAtIndexPath:
Ensure that your tableview's delegate is set to your view controller inside Interface Builder, or if you are not using interface builder..
[tableView setDelegate:self];
Your view controller will then adopt the UITableViewDelegate protocol and respond to tableView:didSelectRowAtIndexPath: when a row is selected.
Loading your new view when the first row is selected will be implemented like so..
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if(indexPath.section == 0){ // the first row
MyView *myView = [[MyView alloc] init];
[self.navigationController pushViewController:myView animated:YES];
[myView release];
}
}