UIPickerView in UITableView

26,442

Solution 1

This is also based on your other question, so I am including those functionalities here as well (i.e. the switch).

In your YourTableViewController.h

set:

@interface YourTableViewViewController : UITableViewController <UIPickerViewDataSource, UIPickerViewDelegate>

In your YourTableViewController.m

Paste this code:

@interface YourTableViewViewController ()
@property NSInteger toggle;
@property (strong, nonatomic) UIPickerView *pickerView;
@end

@implementation YourTableViewViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.toggle = 0;
    self.pickerView = [[UIPickerView alloc] initWithFrame:(CGRect){{0, 0}, 320, 480}];
    self.pickerView.delegate = self;
    self.pickerView.dataSource = self;
    self.pickerView.center = (CGPoint){160, 640};
    self.pickerView.hidden = YES;
    [self.view addSubview:self.pickerView];
}

#pragma mark - Table view data source

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // Return the number of rows in the section.
    return 2;    
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if(cell == nil)
    {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
    }
    if(indexPath.row == 0)
    {
        [cell.contentView addSubview:self.mySwitch];
    }
    if(indexPath.row == 1)
    {
        cell.textLabel.textColor = [UIColor darkGrayColor];
        if(self.toggle == 0)
        {
            cell.textLabel.text = @"Choose a number";
        }
        else
        {
            cell.textLabel.text = @"Cancel";
        }
    }
    // Configure the cell...

    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if(indexPath.row == 1)
    {
        if(self.toggle == 0)
        {
            self.toggle = 1;
            [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:YES];
            [self bringUpPickerViewWithRow:indexPath];
        }
        else
        {
            self.toggle = 0;
            [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:YES];
            [self hidePickerView];
        }
    }
}

- (void)bringUpPickerViewWithRow:(NSIndexPath*)indexPath
{
    UITableViewCell *currentCellSelected = [self.tableView cellForRowAtIndexPath:indexPath];
    [UIView animateWithDuration:1.0f
                          delay:0.0f
                        options:UIViewAnimationOptionCurveEaseInOut
                     animations:^
                     {
                         self.pickerView.hidden = NO;
                         self.pickerView.center = (CGPoint){currentCellSelected.frame.size.width/2, self.tableView.frame.origin.y + currentCellSelected.frame.size.height*4};
                     }
                     completion:nil];
}

- (void)hidePickerView
{
    [UIView animateWithDuration:1.0f
                          delay:0.0f
                        options:UIViewAnimationOptionCurveEaseInOut
                     animations:^
     {
         self.pickerView.center = (CGPoint){160, 800};
     }
                     completion:^(BOOL finished)
     {
         self.pickerView.hidden = YES;
     }];
}

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    self.toggle = 0;
    [self.tableView reloadData];
    [self hidePickerView];
    NSLog(@"row selected:%ld", (long)row);
}

- (NSString*) pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
    return [NSString stringWithFormat:@"%d", row+1];
}

- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
    return 1;
}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
    return 10;
}

@end

Tested.

Addendum:

Also, in your storyboard, change the separator for YourTableView to None (looks better in your case here).

Table View Separator:

in viewDidLoad, add:

self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;

And in bringUpPickerViewWithRow

after:

UITableViewCell *currentCellSelected = [self.tableView cellForRowAtIndexPath:indexPath];

add:

self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
[self.tableView setNeedsDisplay];

And lastly, in hidePickerView, add:

self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
[self.tableView setNeedsDisplay];

Solution 2

Have you seen the sample program released with iOS 7 called DateCell? It uses a UIDatePicker, but I found it pretty straightforward to adapt it to a regular UIPickerView.

It does exactly what you're describing: edit a UITableViewCell with a picker that opens directly under the row you're editing.

Share:
26,442
Mike_NotGuilty
Author by

Mike_NotGuilty

State-certified technical engineer and Software-Engineer. Web development (React, Angular, PHP) App development (Native, React-Native, Ionic) Microcontroller development

Updated on July 09, 2022

Comments

  • Mike_NotGuilty
    Mike_NotGuilty almost 2 years

    First of all: I know that some people already posted topics like that, but nobody gave a clear answer in all those topics.

    I have a settings-UITableView in my application. Now i want to add a TableViewCell where i can choose between some numbers with a UIPickerView.

    In the tableView didSelectRowAtIndexPath method i created the if statement for the right cell

    -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    
        if (indexPath.row == 1){
    
        }
    }
    

    How can i add a UIPickerView for this cell? It should slide up from the bottom and it would be nice if there is something like a "done" button.

  • Mike_NotGuilty
    Mike_NotGuilty over 10 years
    thanks for the answer! i get an error in the bringUpPickerViewWithRow method at self.pickerView = CGPoint ... incompatible type CGPoint (aka struct CGPoint). Do you know why?
  • Mike_NotGuilty
    Mike_NotGuilty over 10 years
    works! thanks! I have more cells under this cell. is it possible that the picker doesn't slide that high? Do i have just to edit this self.pickerview.center line? is this line responsible how high the picker slides? ... ok yes it is that line, haha. :-)
  • Unheilig
    Unheilig over 10 years
    @user2710855 Yes, play around with that line and you will get the height you want.
  • Mike_NotGuilty
    Mike_NotGuilty over 10 years
    one final question: is it possible that when i tap on the cell, THEN the tableview separator lines should disappear? that would be great
  • Unheilig
    Unheilig over 10 years
    @user2710855 yes, let me add that in my answer.
  • Mughees Musaddiq
    Mughees Musaddiq about 10 years
    What if we don't want to use mySwitch? as it is giving an error.
  • Mughees Musaddiq
    Mughees Musaddiq about 10 years
    @Unheilig Thanks, But I replaced cell.textLabel.text = @"Choose a number"; with cell.textLabel.text = [ASQT objectAtIndex:indexPath.row]; as I want to populate table with several questions. However it is only showing a single row.
  • Mughees Musaddiq
    Mughees Musaddiq about 10 years
    @Unheilig if(indexPath.row == 0) contains mySwitch statement that I already have commented. It isn't working.
  • Mughees Musaddiq
    Mughees Musaddiq about 10 years
    @Unheilig I have replaced if(indexPath.row == 0) with if(indexPath.row != 1) and added cell.textLabel.text = [ASQT objectAtIndex:indexPath.row];. When I uncomment the [cell.contentView addSubview:self.mySwitch]; it gives an error Property mySwith not found on object of type "YourTableViewViewController". However, if I comment mySwitch statement it doesn't work :(
  • Mughees Musaddiq
    Mughees Musaddiq about 10 years
    @Unheilig Thanks, your updated code did populate the table but the UIPickerView is appearing only for one row. I want UIPickerView to appear for all the rows in the table.
  • Mughees Musaddiq
    Mughees Musaddiq about 10 years
    @Unheilig Isn't it possible? Please suggest me a solution to this problem as I'm struggling for last couple of days to achieve this functionality.
  • Unheilig
    Unheilig about 10 years
    @MugheesMusaddiq I would suggest adding your UIPicker to the contentView to the cell and make sure you implement the delegate method of your UIPickerView so that you could do something with the UIPicker when it is selected. To make it look nice, one would have to set up the correct height for the cell.
  • Mughees Musaddiq
    Mughees Musaddiq about 10 years
    @Unheilig There should be a tutorial to implement inline pickerView like DateCell. I'll give it a try, Thanks :)