frederickk
frederickk

Reputation: 73

UITableView multiple sections with GUI Elements UIButton, UISwitch, etc

I have been racking my brain on this problem for a day or so now... I've searched this forum as well as google and other blogs etc. All to no avail.

What i'm doing is creating a UITableView with multiple sections and within each section, each row has a different GUI element (i.e. a settings screen)

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 3;
}

and all I'm looking to achieve is that each section to have various GUI elements in various cells. BUT as you can see in this screenshot:

http://twitpic.com/75qix5/full

Initially everything appears as it should, but after scrolling UP and DOWN once, the problems begin. Elements begin to shuffle around and the more/longer you scroll UP and DOWN the more the elements move around.

!["UITableView with GUI elements in sections and rows. Bug? Glitch? Ignorance?"][2]

Is this a bug? glitch? or ignorance? (probably the latter) - I've stripped out all other code except for the GUI code and if it means anything I'm creating the UITableView using a NIB

Also, here's the code for my cellForRowAtIndexPath method. I will be eternally grateful if someone could point me in the right direction or tell me what i'm doing wrong.

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

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
    }


    // Set up the cell
    // desired section
    if(indexPath.section == 0) {
        //
        //  Load Settings
        //

        // button
        UIButton * loadButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
        loadButton.frame = CGRectMake(0.0, 0.0, 300.0, 44.0);
        [loadButton setTitle:@"Load Image" forState:UIControlStateNormal];
        [loadButton setTitle:@"Load Image" forState:UIControlStateSelected];
        [loadButton addTarget:self action:@selector(loadImage:) forControlEvents:UIControlEventTouchUpInside];
        [cell.contentView addSubview:loadButton]; 


    } else if(indexPath.section == 1) {
        //
        //  Mode Settings
        //
        if(indexPath.row == 0) {
            cell.text = [mode objectAtIndex:indexPath.row];    
        } else if(indexPath.row == 1) {
            cell.text = [mode objectAtIndex:indexPath.row];    
        }


    } else if(indexPath.section == 2) {
        //
        //  Marker Settings
        //

        if(indexPath.row == 0) {
            // description text
            cell.text = [marker objectAtIndex:indexPath.row];    

            // switch
            UISwitch *markerSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
            cell.accessoryView = markerSwitch;
            [markerSwitch setOn:YES animated:NO];
            [markerSwitch addTarget:self action:@selector(markerToggle:) forControlEvents:UIControlEventValueChanged];
            [markerSwitch release];       

        } else if(indexPath.row == 1) {
            UISlider *markerGridSlider = [[UISlider alloc] initWithFrame:CGRectMake(0.0, 10.0, 284, 10.0)];
            cell.accessoryView = markerGridSlider;
            markerGridSlider.minimumValueImage = [UIImage imageNamed:@"size_icon_1x1.png"];
            markerGridSlider.maximumValueImage = [UIImage imageNamed:@"size_icon_8x8.png"];

            [markerGridSlider setMinimumValue:1.0];
            [markerGridSlider setMaximumValue:8.0];
            markerGridSlider.value = 8.0;
            [markerGridSlider addTarget:self action:@selector(markerGrid:) forControlEvents:UIControlEventValueChanged];
            [markerGridSlider release];       

        } else if(indexPath.row == 2) {
            UISlider *markerSpacingSlider = [[UISlider alloc] initWithFrame:CGRectMake(0.0, 10.0, 284, 10.0)];
            cell.accessoryView = markerSpacingSlider;
            markerSpacingSlider.minimumValueImage = [UIImage imageNamed:@"spacing_icon_min.png"];
            markerSpacingSlider.maximumValueImage = [UIImage imageNamed:@"spacing_icon_max.png"];

            [markerSpacingSlider setMinimumValue:1.0];
            [markerSpacingSlider setMaximumValue:(320.0/8.0)];
            markerSpacingSlider.value = 1.0;
            [markerSpacingSlider addTarget:self action:@selector(markerSpacing:) forControlEvents:UIControlEventValueChanged];
            [markerSpacingSlider release];       
        }
    }

    return cell;
}

thanks.

Ken


thanks alon for the help.

maybe i'm not understanding exactly what you mean, but i think i've implemented your suggestions properply. however i still get the glitch of the elements swapping places although now after about 5+ UP and DOWN swipes and my UISwitch is now placed in the top left corner.

here's my updated code:

- (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] autorelease];



        if([indexPath section] == 0) {
            //
            // Load Settings
            //

            // button
            UIButton *loadButton = [[UIButton buttonWithType:UIButtonTypeRoundedRect] autorelease];
            loadButton.frame = CGRectMake(0.0, 0.0, 300.0, 44.0);
            [loadButton addTarget:self action:@selector(loadImage:) forControlEvents:UIControlEventTouchUpInside];
            [loadButton setTag:1000];

            [cell.contentView addSubview:loadButton]; 

        } 



        if([indexPath section] == 1) {
            //
            // Mode Settings
            //
            if([indexPath row] == 0) {
                cell.text = [mode objectAtIndex:[indexPath row]];    
            }
            if([indexPath row] == 1) {
                cell.text = [mode objectAtIndex:[indexPath row]];    
            }
        } 



        if([indexPath section] == 2) {
            //
            // Marker Settings
            //
            if([indexPath row] == 0) {
                // switch
                UISwitch *markerSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
                [markerSwitch setOn:YES animated:NO];
                [markerSwitch addTarget:self action:@selector(markerToggle:) forControlEvents:UIControlEventValueChanged];
                [markerSwitch setTag:3000];

                [cell.contentView addSubview:markerSwitch]; 
                [markerSwitch release];

            }
            if([indexPath row] == 1) {
                // slider
                UISlider *markerGridSlider = [[UISlider alloc] initWithFrame:CGRectMake(0.0, 10.0, 284, 10.0)];
                markerGridSlider.minimumValueImage = [UIImage imageNamed:@"size_icon_1x1.png"];
                markerGridSlider.maximumValueImage = [UIImage imageNamed:@"size_icon_8x8.png"];

                [markerGridSlider setMinimumValue:1.0];
                [markerGridSlider setMaximumValue:8.0];
                [markerGridSlider setValue:8.0];
                [markerGridSlider addTarget:self action:@selector(markerGrid:) forControlEvents:UIControlEventValueChanged];
                [markerGridSlider setTag:3100];

                [cell.contentView addSubview:markerGridSlider]; 
                [markerGridSlider release];

            }
            if([indexPath row] == 2) {
                // slider
                UISlider *markerSpacingSlider = [[UISlider alloc] initWithFrame:CGRectMake(0.0, 10.0, 284, 10.0)];
                markerSpacingSlider.minimumValueImage = [UIImage imageNamed:@"spacing_icon_min.png"];
                markerSpacingSlider.maximumValueImage = [UIImage imageNamed:@"spacing_icon_max.png"];

                [markerSpacingSlider setMinimumValue:1.0];
                [markerSpacingSlider setMaximumValue:(320.0/8.0)];
                [markerSpacingSlider setValue:1.0];
                [markerSpacingSlider addTarget:self action:@selector(markerSpacing:) forControlEvents:UIControlEventValueChanged];
                [markerSpacingSlider setTag:3200];

                [cell.contentView addSubview:markerSpacingSlider]; 
                [markerSpacingSlider release];

            }
        }


    } // end cell == nil


    // Load
    UIButton *loadButton = (UIButton*)[cell.contentView viewWithTag:1000];
    [loadButton setTitle:@"Load Image" forState:UIControlStateNormal];
    [loadButton setTitle:@"Load Image" forState:UIControlStateSelected];

    // Mode

    // Marker
    UISwitch *markerSwitch = (UISwitch*)[cell.contentView viewWithTag:3000];
    UISlider *markerGridSlider = (UISlider*)[cell.contentView viewWithTag:3100];
    UISlider *markerSpacingSlider = (UISlider*)[cell.contentView viewWithTag:3200];


    return cell;
}

Upvotes: 1

Views: 2075

Answers (2)

Khalil Ghaus
Khalil Ghaus

Reputation: 251

change static NSString *CellIdentifier = @"Cell"; for each section like:

NSString *CellIdentifier; if(indexPath.section==0){ CellIdentifier= @"Cell"; }elseif(indexPath.section==2){ CellIdentifier=@"Cell2"; }

Upvotes: 1

Alon Amir
Alon Amir

Reputation: 5025

All the cells bound to a UITable in iOS are reusable. this is why you first get your cell with the function call "dequeueReusableCellWithIdentifier", the cell might not be nil, pointing to a cell that was loaded before. in your case, even if the cell is not nil, you add subviews to it. this will happen infinite times as you scroll up and down.

Here is a small example:

-(int)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 2;
}

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

    const NSInteger lblTag = 101;
    const NSInteger btnTag = 102;

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    //First init the cells
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

        //Initialize subviews of cells only in this block.

        if (indexPath.row == 0) {
            //Only the first cell on the top has a UILabel
            UILabel *lbl = [[[UILabel alloc] initWithFrame:CGRectMake(5, 5, 100, 20)] autorelease];
            lbl.tag = lblTag;    
            [cell.contentView addSubview:lbl];
        } else if (indexPath.row == 1) {
            //Only the 2nd cell has a UIButton
            UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
            btn.frame = CGRectMake(5, 5, 60, 20);
            btn.tag = btnTag;    
            [cell.contentView addSubview:btn];
        }
    }

    //Modify your cells here
    if (indexPath.row == 0) {
        //Only the first cell on the top has a UILabel
        UILabel *lbl = (UILabel*)[cell.contentView viewWithTag:lblTag];
        //Do stuff with our label

        lbl.text = [NSString stringWithFormat:@"%d",indexPath.row];

    } else if (indexPath.row == 1) {
        //Only the 2nd cell has a UIButton
        UIButton *btn = (UIButton*)[cell.contentView viewWithTag:btnTag];
        //Do stuff with our button
        [btn setTitle:[NSString stringWithFormat:@"%d",indexPath.row] forState:UIControlStateNormal];

    }

    return cell;

}

In your very specific case, you would write this-

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{
    if (section == 0) {
        return 1;
    } else if (section == 1) {
        return 2;
    } else if (section == 2) {
        return 3;
    } else {
        return 0;
    }
}

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

    static NSString *CellIdentifier = @"Cell";



    const NSInteger
    sec0BtnTag = 101,
    markerSwitchTag = 102,
    markerGridSliderTag = 103,
    markerSpacingSliderTag = 104;

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];



        if([indexPath section] == 0) {
            //
            // Load Settings
            //

            // button
            UIButton *loadButton = [[UIButton buttonWithType:UIButtonTypeRoundedRect] autorelease];
            loadButton.frame = CGRectMake(0.0, 0.0, 300.0, 44.0);
            [loadButton addTarget:self action:@selector(loadImage:) forControlEvents:UIControlEventTouchUpInside];
            [loadButton setTag:sec0BtnTag];

            [cell.contentView addSubview:loadButton]; 

        } 



        else if([indexPath section] == 2) {
            //
            // Marker Settings
            //
            if([indexPath row] == 0) {
                // switch
                UISwitch *markerSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
                [markerSwitch setOn:YES animated:NO];
                [markerSwitch addTarget:self action:@selector(markerToggle:) forControlEvents:UIControlEventValueChanged];
                [markerSwitch setTag:markerSwitchTag];

                [cell.contentView addSubview:markerSwitch]; 
                [markerSwitch release];

            }
            else if([indexPath row] == 1) {
                // slider
                UISlider *markerGridSlider = [[UISlider alloc] initWithFrame:CGRectMake(0.0, 10.0, 284, 10.0)];
                markerGridSlider.minimumValueImage = [UIImage imageNamed:@"size_icon_1x1.png"];
                markerGridSlider.maximumValueImage = [UIImage imageNamed:@"size_icon_8x8.png"];

                [markerGridSlider setMinimumValue:1.0];
                [markerGridSlider setMaximumValue:8.0];
                [markerGridSlider setValue:8.0];
                [markerGridSlider addTarget:self action:@selector(markerGrid:) forControlEvents:UIControlEventValueChanged];
                [markerGridSlider setTag:markerGridSliderTag];

                [cell.contentView addSubview:markerGridSlider]; 
                [markerGridSlider release];

            }
            else if([indexPath row] == 2) {
                // slider
                UISlider *markerSpacingSlider = [[UISlider alloc] initWithFrame:CGRectMake(0.0, 10.0, 284, 10.0)];
                markerSpacingSlider.minimumValueImage = [UIImage imageNamed:@"spacing_icon_min.png"];
                markerSpacingSlider.maximumValueImage = [UIImage imageNamed:@"spacing_icon_max.png"];

                [markerSpacingSlider setMinimumValue:1.0];
                [markerSpacingSlider setMaximumValue:(320.0/8.0)];
                [markerSpacingSlider setValue:1.0];
                [markerSpacingSlider addTarget:self action:@selector(markerSpacing:) forControlEvents:UIControlEventValueChanged];
                [markerSpacingSlider setTag:markerSpacingSliderTag];

                [cell.contentView addSubview:markerSpacingSlider]; 
                [markerSpacingSlider release];

            }
        }


    } // end cell == nil

    //Load specific cell row values

    if([indexPath section] == 0) {
        //
        // Load Settings
        //

        // button
        UIButton *loadButton = (UIButton*)[cell.contentView viewWithTag:sec0BtnTag];
        [loadButton setTitle:@"Load Image" forState:UIControlStateNormal];
        [loadButton setTitle:@"Load Image" forState:UIControlStateSelected];
        //do other stuff with the button here according to the specific row & section

    } 



    if([indexPath section] == 1) {
        //
        // Mode Settings
        //
        if([indexPath row] == 0) {
            cell.text = [mode objectAtIndex:[indexPath row]];    
        }
        if([indexPath row] == 1) {
            cell.text = [mode objectAtIndex:[indexPath row]];    
        }
    } 



    if([indexPath section] == 2) {
        //
        // Marker Settings
        //
        if([indexPath row] == 0) {
            // switch
            UISwitch *markerSwitch = (UISwitch*)[cell.contentView viewWithTag:markerSwitchTag];
            //do stuff with the switch here according to the specific row & section
        }
        if([indexPath row] == 1) {
            // slider
            UISlider *markerGridSlider = (UISlider*)[cell.contentView viewWithTag:markerGridSliderTag];
            //do stuff with the slider here according to the specific row & section
        }
        if([indexPath row] == 2) {
            // slider
            UISlider *markerSpacingSlider = (UISlider*)[cell.contentView viewWithTag:markerSpacingSliderTag];
            //do stuff with the slider here according to the specific row & section



        }
    }


    return cell;
}

Upvotes: 1

Related Questions