DenVog
DenVog

Reputation: 4286

Adding Array of Buttons to Appropriate Table Rows

I am trying to populate a table with rows of buttons dynamically. When the table is launched, I pass it an array containing the correct buttons. The quantity of buttons, and thus rows, will vary. This works, until I need to create a new row (i.e. too many buttons to fit on the first row). Let's assume I limit it to 4 buttons per row. Then my buttons start on row 2, not row 1 like they should. They also get clipped on the right bounds.

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSInteger rows = 0;  // No rows if section is unknown!
    switch (section)
    {
        case TableViewSectionFormatButtons:
        {
            if ([[self fileTypeButtonsArray] count] % kButtonsPerRow)
                return ([[self fileTypeButtonsArray] count] / kButtonsPerRow) + 1;
            else
                return [[self fileTypeButtonsArray] count] / kButtonsPerRow;
        }
            break;
        case TableViewSectionExportSwitches:
            rows = 4;
            break;
        case TableViewSectionExportButton:
            rows = 1;
            break;
        default:
            break;
    }

    return rows;
}

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

    UITableViewCell *cellToReturn = nil;

    // Usage note: Both kinds of cells get created every time, which is arguably wasteful.  Since there aren't many rows involved
    // it's simpler just to ignore the one that we don't need.  Assign the one we want to cellToReturn.

    UITableViewCell *defaultCell = [tableView dequeueReusableCellWithIdentifier:defaultCellIdentifier]; // Image on left
    if (defaultCell == nil) {
        defaultCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:defaultCellIdentifier];
    }

    UITableViewCell *detailCell = [tableView dequeueReusableCellWithIdentifier:detailCellIdentifier]; // Text on right
    if (detailCell == nil) {
        detailCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:detailCellIdentifier];
    }

    // Clear old values
    defaultCell.textLabel.textAlignment = NSTextAlignmentLeft;
    defaultCell.accessoryType = UITableViewCellAccessoryNone;
    defaultCell.accessoryView = nil;
    defaultCell.imageView.image = nil;

    detailCell.accessoryType = UITableViewCellAccessoryNone;
    detailCell.imageView.image = nil;


    switch (indexPath.section) {
        case TableViewSectionFormatButtons: {

            for (int i = 0; i < [self.fileTypeButtonsArray count]; i++)
            {
                UIButton *currentButton = (UIButton *)[self.fileTypeButtonsArray objectAtIndex:i];
                [currentButton setTag:i];

                [currentButton setFrame:CGRectMake((kButtonPadding + (i * (kButtonWidth + kButtonPadding))), kButtonPadding, kButtonWidth, kButtonHeight)];
                [defaultCell.contentView addSubview:currentButton];
            }

            defaultCell.selectionStyle = UITableViewCellSelectionStyleNone;



            cellToReturn = defaultCell;
        }
            break;

        case TableViewSectionExportSwitches: {

            defaultCell.selectionStyle = UITableViewCellSelectionStyleNone;

            if (indexPath.row == 0) {
                defaultCell.textLabel.text = NSLocalizedString(@"synopsisSwitchLabel", @"Synopsis - Export switch label to indicate if Synopsis text should be included in export.");
                self.synopsisSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
                defaultCell.accessoryView = self.synopsisSwitch;
//                self.synopsisSwitch.on = [[NSUserDefaults standardUserDefaults] boolForKey:kUserDefaultsShowNotesIndicatorKey];

                [self.synopsisSwitch addTarget:self action:@selector(synopsisSwitchValueChanged:) forControlEvents: UIControlEventValueChanged];

            }

            else if (indexPath.row == 1)
            {
                defaultCell.textLabel.text = NSLocalizedString(@"bodySwitchLabel", @"Body - Export switch label to indicate if Body text should be included in export.");
                self.bodySwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
                defaultCell.accessoryView = self.bodySwitch;

//                self.bodySwitch.on = [[NSUserDefaults standardUserDefaults] boolForKey:kUserDefaultsShowNotesIndicatorKey];
                [self.bodySwitch addTarget:self action:@selector(bodySwitchValueChanged:) forControlEvents: UIControlEventValueChanged];
            }

            else if (indexPath.row == 2)
            {
                defaultCell.textLabel.text = NSLocalizedString(@"notesSwitchLabel", @"Notes - Export switch label to indicate if Notes should be included in export.");

            self.notesSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
                defaultCell.accessoryView = self.notesSwitch;

//                self.notesSwitch.on = [[NSUserDefaults standardUserDefaults] boolForKey:kUserDefaultsShowExpandedOutlineKey];
                [self.notesSwitch addTarget:self action:@selector(notesSwitchValueChanged:) forControlEvents: UIControlEventValueChanged];
            }

            else if (indexPath.row == 3)
            {
                defaultCell.textLabel.text = NSLocalizedString(@"imagesSwitchLabel", @"Images - Export switch label to indicate if Images should be included in export.");
                self.imagesSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
                defaultCell.accessoryView = self.imagesSwitch;

//                self.imagesSwitch.on = [[NSUserDefaults standardUserDefaults] boolForKey:kUserDefaultsStoryboardModeKey];
                [self.imagesSwitch addTarget:self action:@selector(imagesSwitchValueChanged:) forControlEvents: UIControlEventValueChanged];
            }

            cellToReturn = defaultCell;
        }
            break;

        case TableViewSectionExportButton:
        {
            defaultCell.textLabel.textAlignment = NSTextAlignmentCenter;
            if (indexPath.row == 0)
            {
                defaultCell.textLabel.text = NSLocalizedString(@"nextButtonTitle", @"Next - Button title indicating user is ready to proceed with Export.");
                defaultCell.textLabel.textColor = [UIColor blueColor];
            }

            cellToReturn = defaultCell;
        }
            break;

    }

    return cellToReturn;
}

Example Buttons exceeding 1 row - bad enter image description here

Example Buttons fit on 1 row - good enter image description here

I realize I'm just telling it to keep adding buttons to the right of each other. I'm stumped how I tell it which rows to put them in. Also stumped why they start in the second row (index 1), instead of top row (index 0). Thanks for any assistance.

Upvotes: 0

Views: 108

Answers (1)

Lyndsey Scott
Lyndsey Scott

Reputation: 37290

In the numberOfRowsInSection: method your TableViewSectionFormatButtons: tacks on an additional row if the buttons fit neatly into the row, i.e. if ([[self fileTypeButtonsArray] count] % kButtonsPerRow); but this sounds like the exact opposite of what you want to do. It sounds as if you only want to tack on an extra row if you have buttons that can't fit neatly in the row above it, in which case, I suggest doing this instead with one line:

case TableViewSectionFormatButtons: {
    return ([[self fileTypeButtonsArray] count] + kButtonsPerRow - 1) / kButtonsPerRow;
}

to simply round up the integer division.

As for your cellForRowAtIndexPath: method, (1) you need to account for the number of buttons per row, i.e. have kButtonsPerRow in your algorithm, (2) you need to know which row you're adding to, and (3) using that info you only want to put the buttons that belong in the current row in that current row, so you don't want that loop to start at 0 and go all the way to the end of your buttons array. For example:

case TableViewSectionFormatButtons: {

    // Calculate the index of the first button in the current row
    int firstButtonIndex = indexPath.row * kButtonsPerRow;

    // Then starting from that index place kButtonsPerRow within that row
    for (int i = firstButtonIndex ; i < firstButtonIndex + kButtonsPerRow ; i++) {

        if (self.fileTypeButtonsArray.count > i) {
            UIButton *currentButton = (UIButton *)[self.fileTypeButtonsArray objectAtIndex:i];
            [currentButton setTag:i];
            [currentButton setFrame:CGRectMake((kButtonPadding + ((i-firstButtonIndex) * (kButtonWidth + kButtonPadding))), kButtonPadding, kButtonWidth, kButtonHeight)];
            [defaultCell.contentView addSubview:currentButton];
        }
    }

    defaultCell.selectionStyle = UITableViewCellSelectionStyleNone;
    cellToReturn = defaultCell;
}

Something like that should work.

P.S. The fact that you're both reusing cells and adding buttons as subviews during each cellForRowAtIndexPath: will probably lead to some problems going forward. If you're going to clear out the old values in the way that you've already done in your code, perhaps you should also remove old buttons in that same place, ex:

// Clear old values
defaultCell.textLabel.textAlignment = NSTextAlignmentLeft;
defaultCell.accessoryType = UITableViewCellAccessoryNone;
defaultCell.accessoryView = nil;
defaultCell.imageView.image = nil;

for (UIView *view in [defaultCell subviews]) {
    if ([view isKindOfClass:[UIButton class]]) {
        [view removeFromSuperview];
    }
}

Upvotes: 1

Related Questions