- There is a search bar that allows you to enter text. Every time a character is entered, a fetchcontroller is updated with a new search criteria.
- When an item is selected, it will fully populate the search bar.
- When the add button is selected, it will create a GUI image of the search bar and animate it going towards the add button.
- It is fairly generic. It takes as parameters the table, and search key allowing it to hit any single table query for selecting/searching items. When an item is selected a delegate is called with the selection data.
- When the keyboard is displayed the list shrinks so that it doesn't go behind the keyboard.
It has a few flaws as well
- These nice features are embedded in a special purpose class.
- The add button is a standard button next to the search bar. This doesn't look as nice as the standard (and easier) adding a button the navigation controller.
- The .xib file is a problem when using this library. I had it go out of date, and had to manually copy changes to the main project. There probably is a better way to send xib files to a main project, but I haven't figured it out yet.
Some Choice tidbits:
Shrinking the view
In viewDidLoad place the following code:
Delegating item creation and actions:
By defining a simple protocol and ensuring a delegate exists we can delegate out the selection of an
existing item and also the actual action that takes place upon selection.
Adding an item
Shrinking the view
In viewDidLoad place the following code:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardAppearing:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDisappearing:) name:UIKeyboardWillHideNotification object:nil];
and then add the following two methods. Note that suggestions is the outlet for the list being displayed.
- (void)keyboardDisappearing:(NSNotification *)notification {
suggestions.frame=originalSize;
}
- (void)keyboardAppearing:(NSNotification *)notification {
NSDictionary *keys=[notification userInfo];
NSValue *value=[keys objectForKey:UIKeyboardBoundsUserInfoKey];
CGRect bounds;
[value getValue:&bounds];
CGRect myFrame=[suggestions frame];
originalSize=myFrame;
suggestions.frame=CGRectMake(myFrame.origin.x,myFrame.origin.y,myFrame.size.width,
myFrame.size.height-bounds.size.height);
}
Delegating item creation and actions:
By defining a simple protocol and ensuring a delegate exists we can delegate out the selection of an
existing item and also the actual action that takes place upon selection.
@protocol SuggesionActionHandler<NSObject>
- (id) createNewItem:(NSString *) searchValue;
- (void) doActionForItem:(id) item;
@end
Adding an item
Adding an item: Note that this combines the animation and action into the same area. It really should be separated out. I'm not sure I like how I search for the currently existing item. At the very least it should be broken out into another method.
- (IBAction) addCurrentItem:(id) sender
{
NSManagedObject *matchingItem=nil;
NSString *currentText=searchBar.text;
UIGraphicsBeginImageContext(searchBar.bounds.size);
[searchBar.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageView *imageView=[[UIImageView alloc] initWithImage :viewImage];
imageView.frame=searchBar.frame;
[self.view addSubview:imageView];
[UIView beginAnimations:nil context:imageView];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.25];
[imageView setFrame:addButton.frame];
// Search for the existing item if one.
if (fetchController!=nil)
{
if (fetchController.sections!=nil)
{
for (id<NSFetchedResultsSectionInfo> sectionInfo in fetchController.sections)
{
for (NSManagedObject *object in [sectionInfo objects])
{
NSString *keyForSearch=[object valueForKey:self.searchVariable];
if ([keyForSearch isEqualToString: currentText])
{
matchingItem=object;
break;
}
}
if (matchingItem!=nil)
break;
}
}
}
if (delegate!=nil)
{
if (matchingItem==nil)
{
matchingItem=[delegate createNewItem:currentText];
}
[delegate doActionForItem:matchingItem];
}
else
{
NSLog(@"Delegate is nil, no action can be performed ");
}
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
[UIView commitAnimations];
}
Updating a Fetch controller with a search predicate:
This was slightly tricky, since the examples assumed a hardcoded search variable. I had to format the string twice so that I could build the format string with the field name prior to doing substitution.
Updating a Fetch controller with a search predicate:
This was slightly tricky, since the examples assumed a hardcoded search variable. I had to format the string twice so that I could build the format string with the field name prior to doing substitution.
NSFetchRequest *request=[[NSFetchRequest alloc] init];
NSEntityDescription *entity=[NSEntityDescription entityForName:managedTable
inManagedObjectContext:coreControl.managedObjectContext];
[request setEntity:entity];
[request setFetchBatchSize:20];
NSSortDescriptor *sortDesc=[[NSSortDescriptor alloc] initWithKey:searchVariable ascending:YES];
NSArray *sortDescs=[[NSArray alloc] initWithObjects:sortDesc,nil];
NSString *searchString=[searchText stringByAppendingString:@"*"];
NSString *predicateFormat=[[NSString alloc] initWithFormat:@"%@ like[cd] %%@",searchVariable];
NSLog(@"Searching table %@ %@ for %@",managedTable,searchVariable,searchString);
NSPredicate *predicate = [NSPredicate
predicateWithFormat:predicateFormat,
searchString];
NSLog(@"Pred Desc %@", [predicate description]);
[request setPredicate:predicate];
[request setSortDescriptors:sortDescs];
if (fetchController!=nil)
{
[fetchController release];
}
self.fetchController=[[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:coreControl.managedObjectContext sectionNameKeyPath:nil cacheName:managedTable];
self.fetchController.delegate=self;
NSError *error;
[self.fetchController performFetch:&error] ;
// NSLog(@"Unresolved error %@", error);
// NSLog(@"Fetch count %d",fetchController.sections);
[self.suggestions reloadData];
[predicateFormat release];
[request release];
[sortDesc release];
[sortDescs release];
No comments:
Post a Comment