Dan Nichols
Dan Nichols

Reputation: 55

UISegmentedControl inside a UITableViewCell - segmented control disappears when table reloads

I've searched the forum, but have not found anything that works for my situation. I am still new at this, so it is probably something simple, but I can't seem to figure it out.

I have a UITableViewController that has several sections. I have created a custom class called a SSSDataEntryCell that allows the user to enter text. However, in one of the cells, I want to replace it with a UISegmentedControl. The code works the first time the table is displayed (the control appears, I can select a segment and the value changes), but on any type of reload event (rotation, scrolling where the cell is not visible, etc.), the segmented control no longer appears.

Do I need to recreate the segmented control every time? That seems inefficient, especially since it is an ivar. I have tried releasing the subview of the cell before adding and a number of other suggestions on stackoverflow, but nothing seems to fix it. Thanks in advance!

Here is the relevant part of my .h

@interface SSSEditDetailViewController : UITableViewController <UITextFieldDelegate>
{
    // lets us set the sex (male, female)
    UISegmentedControl *sexSwitch;
}

Here is the relevant part of the .m

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Load the NIB file for our custom cell
    UINib *nib = [UINib nibWithNibName:@"SSSDataEntryTableCell" bundle:nil] ;

    // Register the NIB which contains the cell
    [[self tableView] registerNib:nib forCellReuseIdentifier:@"SSSDataEntryTableCell"] ;

    //
    // set up the sex switch if needed
    //
    if ( sexSwitch == nil )
    {
        NSArray *values = [[NSArray alloc] initWithObjects:kSSSMale, kSSSFemale, nil] ;
        sexSwitch = [[UISegmentedControl alloc] initWithItems:values] ;
        [sexSwitch addTarget:self action:@selector(changeSex:)  
                  forControlEvents:UIControlEventValueChanged] ;
        [sexSwitch setSegmentedControlStyle:UISegmentedControlStyleBar] ;
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    SSSDataEntryTableCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SSSDataEntryTableCell"] ;

    if ( [indexPath section] == 0 )
    {
        [[cell dataField] setDelegate:self] ;
        [[cell dataField] setOurPath:indexPath] ;

        [[cell dataField] setText:[person name]] ;
        [[cell dataField] setPlaceholder:@"Name"] ;
    }
    else if ( [indexPath section] == 1 )
    {
        // Sex switch;
        [cell setAccessoryType:UITableViewCellAccessoryNone] ;

        // get cell frame and put the sex switch in its place
        [sexSwitch setFrame:[cell frame]] ;
        [sexSwitch setAutoresizingMask:UIViewAutoresizingFlexibleWidth] ;

        [[cell contentView] addSubview:sexSwitch] ;
    }

    return cell ;
}

Upvotes: 1

Views: 5519

Answers (1)

rdelmar
rdelmar

Reputation: 104082

Your main problem is using the cell's frame to set the switch's frame. If you log cell.frame, you'll sometimes see a large number for its y value as you scroll up and down, so sometimes your switch is off the bottom of the screen. This is easy to fix, use bounds instead of frame.

You have another problem in that as the cells are reused, the switch could show up on other cells where it's not supposed to be. If you're going to add the switch in code, you need to remove it before you do your if statements so you're starting with a pristine cell. One way to do this, is give the switch a tag, and remove the view with that tag:

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

        SSSDataEntryTableCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SSSDataEntryTableCell"] ;
        [[cell.contentView viewWithTag:47] removeFromSuperview];
        [[cell dataField] setText:nil];
        [[cell dataField] setPlaceholder:@"Name"] ;

        if ( [indexPath section] == 0 )
        {
            [[cell dataField] setDelegate:self] ;
            [[cell dataField] setOurPath:indexPath] ;

            [[cell dataField] setText:[person name]] ;
        }
        else if ( [indexPath section] == 1 )
        {
            // Sex switch;
            [cell setAccessoryType:UITableViewCellAccessoryNone] ;
            // get cell frame and put the sex switch in its place
            [sexSwitch setFrame:[cell bounds]];
            [sexSwitch setAutoresizingMask:UIViewAutoresizingFlexibleWidth] ;
            sexSwitch.tag = 47;
            [[cell contentView] addSubview:sexSwitch] ;
        }
        return cell ;
    }

I'm not sure what you're doing with the placeholder, but you probably want to move it up before the if statements, and also set the text to nil there, so that it is back to an initial state as well.

Upvotes: 1

Related Questions