Question

I'm building an application with an autocomplete UITableView from this tutorial. I have the autocomplete functionality working properly, but I would like the UITableView-autocomplete drop down to disappear when the word is clicked on or when it is touched up outside. I'm not sure how to set up a delegate when the object is set up programmatically. I've only done this using the interface builder.

.h

@interface slrpViewController : UIViewController<UITextFieldDelegate, UIPickerViewDelegate, UIPickerViewDataSource>
{
NSMutableArray *dataArray;
NSMutableData *receivedData;

NSMutableArray *pastUrls;
NSMutableArray *autocompleteUrls;
UITableView *autocompleteTableView;
}
@property(nonatomic, retain) IBOutlet UITextField *eWordEntered;
@property (nonatomic, retain) NSMutableArray *pastUrls;
@property (nonatomic, retain) NSMutableArray *autocompleteUrls;
@property (retain, nonatomic) NSMutableData *responseData;
@property (nonatomic, retain) UITableView *autocompleteTableView;
-(void)setReceivedData:(NSMutableData*)pReceivedData;
-(NSMutableData *) getReceivedData;
-(void) getAutoCompleteArray;
-(void)searchAutocompleteEntriesWithSubstring:(NSString *)substring;

.m

- (void)viewDidLoad
{
[super viewDidLoad];
[self getAutoCompleteArray];
pastUrls = [[NSMutableArray alloc] init];

NSLog(@"In the viewDidLoad and pasturl is: %@", self.pastUrls);
self.autocompleteUrls = [[NSMutableArray alloc] init];

autocompleteTableView = [[UITableView alloc] initWithFrame:CGRectMake(210, 225, 310, 120) style:UITableViewStylePlain];
self.autocompleteTableView.delegate = self;
self.autocompleteTableView.dataSource = self;
autocompleteTableView.scrollEnabled = YES;
autocompleteTableView.hidden = YES;
[self.view addSubview:autocompleteTableView];

-(void)setReceivedData:(NSMutableData*)pReceivedData
{
receivedData = pReceivedData;
}

-(NSMutableData *) getReceivedData{
return receivedData;
}

-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[receivedData setLength:0];   
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{[receivedData appendData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSError *e = nil;
NSError *error = nil;
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData: receivedData options:  NSJSONReadingMutableContainers error: &e];

NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:receivedData
                                                         options:kNilOptions
                                                           error:&error];
seneca_word.ids = [jsonDict objectForKey:@"ids"];
NSArray *array_ids = [jsonDict objectForKey:@"ids"];
NSString *ids = array_ids[0];
seneca_word.ids = ids;
for (id key in jsonDict)
{
    NSLog(@"key: %@, value: %@", key, [jsonDict objectForKey:key]);
    NSLog(@"The value of bases by itself is: %@", [jsonDict objectForKey:@"bases"]);
}

if (!jsonArray)
{
    NSLog(@"Error parsing JSON: %@", e);
}
else
{
    if([jsonDict objectForKey:@"english"] != nil){
        pastUrls = [jsonDict objectForKey:@"bases"];
    }

    else{
        //Some of JSON object that I don't want to use here

}//else   
}//(void)connectionDidFinishLoading

- (void)searchAutocompleteEntriesWithSubstring:(NSString *)substring {
[autocompleteUrls removeAllObjects];
for(NSString *curString in pastUrls) {
    NSRange substringRange = [curString rangeOfString:substring];
    if (substringRange.location == 0) {
        [autocompleteUrls addObject:curString];
    }
}
[autocompleteTableView reloadData];
}


- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
autocompleteTableView.hidden = NO;

NSString *substring = [NSString stringWithString:textField.text];
substring = [substring stringByReplacingCharactersInRange:range withString:string];
[self searchAutocompleteEntriesWithSubstring:substring];
return YES;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger) section {
return autocompleteUrls.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

UITableViewCell *cell = nil;
static NSString *AutoCompleteRowIdentifier = @"AutoCompleteRowIdentifier";
cell = [tableView dequeueReusableCellWithIdentifier:AutoCompleteRowIdentifier];
if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:AutoCompleteRowIdentifier];
}

cell.textLabel.text = [autocompleteUrls objectAtIndex:indexPath.row];
return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
self.eWordEntered.text = selectedCell.textLabel.text;

if(tableView == autocompleteTableView){
    //The autocomplete table view is the one that fired the didSelect delegate method
    //So hide the autocomplete table.
    //do whatever else you need to do to empty the autocompleteTableView's data source
    //or/and simply hide the table after that
    [autocompleteTableView setHidden:YES];    

}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//When the user clicks outside of the uitableview it will disappear
[autocompleteTableView setHidden:YES];
}

As you can see I populate the autocomplete UITableView with JSON data that I'm getting from a RESTful API.

I'm getting the warning, Assigning to 'id<UITableViewDelegate>' from incompatible type 'ViewController *const __strong' for the lines:

self.autocompleteTableView.delegate = self;
self.autocompleteTableView.dataSource = self;

I imagine once I get the delegate stuff sorted out I'll be able to do what I want. I did some research and tried to create a delegate class but wasn't able to get that solution working. I'm not even sure if that's the right way to go about this as I usually do this stuff by interface builder and not programmatically. Any direction or help is greatly appreciated. Thanks!

Was it helpful?

Solution

You should be using the tableView's didSelectCellAtIndexPathRow delegate method to identify user taps on a cell from a tableView. It's ok if you created your tableView progammatically.

  1. Simply make sure the UIViewController conforms to the UITableViewDelegate and UITableViewDataSource` protocols.

  2. make sure you set the tableView's delegate and dataSource property to self.

  3. Implement the didSelectCellAtIndexPathRow delegate method in your viewController's .m file like so:

    -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    
    }
    
  4. Then inside that delegate method you need to help detect from which tableView your didSelect method got fired from as you only want to hide the autocomplete table when the user selects a cell from that table. So you do a simple tableView check like so:

    if(tableView == autocompleteTableView){
        //The autocomplete table view is the one that fired the didSelect delegate method
        //So hide the autocomplete table.
        //do whatever else you need to do to empty the autocompleteTableView's data source
        //or/and simply hide the table after that 
        [autocompleteTableView setHidden:YES];
    }
    
  5. You probably also want to make sure that you set the autocompleteTableView hidden property to NO when the user types in something in the textfield so that the auto complete can show appear again.

And thats all buddy.

OTHER TIPS

try setting self.autocompleteTableView.hidden = YES;

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top