Xcode tableview how to select ONE row in EACH section
Asked Answered
H

3

13

I have a tableview with 2 sections. I want only one row to be selected per each section. Right now I have it working to select one row, but it is for the entire table. Ultimately, I want 2 rows selected, but only ONE per SECTION. I have been stuck on this for days and can not figure it out. Is this possible?? I am new to Xcode so any help would be very much appreciated. Thanks in advance!

Here is my code:

//  OptionsViewController.h

#import <UIKit/UIKit.h>

@interface OptionsViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
{
    NSArray *themeDataArray;
    NSArray *levelDataArray;
    NSIndexPath *selectedRowIndex;
}

@property (weak, nonatomic) NSArray *themeDataArray;
@property (weak, nonatomic) NSArray *levelDataArray;
@property (weak, nonatomic) NSIndexPath *selectedRowIndex;
@property (weak, nonatomic) IBOutlet UITableView *tableView;

@end


//  OptionsViewController.m

#import "OptionsViewController.h"
@interface OptionsViewController ()
@end

@implementation OptionsViewController

- (void)viewDidLoad
{
    themeDataArray = [[NSArray alloc] initWithObjects:@"Classic",@"Animals",@"Dinosaurs",@"Cars", nil];
    levelDataArray = [[NSArray alloc] initWithObjects:@"Easy",@"Medium",@"Hard", nil];

    //set default rows on startup
    NSIndexPath *indexPath=[NSIndexPath indexPathForRow:0 inSection:0];
    [self.tableView selectRowAtIndexPath:indexPath animated:YES  scrollPosition:UITableViewScrollPositionTop];

    NSIndexPath *indexPath2=[NSIndexPath indexPathForRow:0 inSection:1];
    [self.tableView selectRowAtIndexPath:indexPath2 animated:YES  scrollPosition:UITableViewScrollPositionNone];

    [super viewDidLoad];
}

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

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection (NSInteger)section
{
    //For each section, return header label
    if(section == 0) return @"Themes";
    if(section == 1) return @"Difficulty Level";
    return nil;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    //For each section, return number of rows in section
    if(section == 0) return [themeDataArray count];
    if(section == 1) return [levelDataArray count];
    return 0;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell1 = nil;

    //recycles cells to save memory
    cell1 = [tableView dequeueReusableCellWithIdentifier:@"cell1"];

    if (cell1 == nil)
    {
        cell1 = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell1"];
    }

    cell1.textLabel.text=[themeDataArray objectAtIndex:indexPath.row];
    return cell1;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [tableView reloadData];
    switch (indexPath.section)
    {
        case 0:
        {
            if (self.selectedRowIndex)
            {
                UITableViewCell *deselectCell = [tableView cellForRowAtIndexPath:self.selectedRowIndex];
                deselectCell.highlighted = FALSE;
                [tableView reloadData];
            }

            //select new row and assign new indexPath
            UITableViewCell *newCell = [tableView cellForRowAtIndexPath:indexPath];
            newCell.highlighted = TRUE;

            self.selectedRowIndex = indexPath;
            break;
        }
        case 1:
        {
            if (self.selectedRowIndex)
            {
                UITableViewCell *deselectCell = [tableView cellForRowAtIndexPath:self.selectedRowIndex];
                deselectCell.highlighted = FALSE;
            }

            //select new row and assign new indexPath
            UITableViewCell *newCell = [tableView cellForRowAtIndexPath:indexPath];
            newCell.highlighted = TRUE;

            self.selectedRowIndex = indexPath;
            break;
        }
        default:
            break;
    }
}

@end
Hepza answered 27/1, 2013 at 22:59 Comment(0)
G
26

So, you'd like no more than 1 row to be selected at a time in each section? Then a solution is to, whenever the user touches a row, deselect any selected rows in the same section.

- (NSIndexPath*)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath*)indexPath {
    for ( NSIndexPath* selectedIndexPath in tableView.indexPathsForSelectedRows ) {
        if ( selectedIndexPath.section == indexPath.section )
            [tableView deselectRowAtIndexPath:selectedIndexPath animated:NO] ;
    }
    return indexPath ;
}
Grenadier answered 27/1, 2013 at 23:15 Comment(3)
Wow that was exactly what I was looking for thanks! I totally over thought thatHepza
This works nicely but the only problem I found with this approach is that the user can deselect a row by tapping on it, leaving nothing selected. Simply add the following to prevent this: -(NSIndexPath *)tableView:(UITableView *)tableView willDeselectRowAtIndexPath:(NSIndexPath *)indexPath { return nil; }Whosoever
@Whosoever it still has the caveat of deselecting a selected cell not firing a didSelectRowAtIndexPath though. To go around it, you can instead adopt tableView:didDeselectRowAtIndexPath: and manually call the datasource method tableView:didSelectRowAtIndexPath:.Retort
R
7

Here's the Swift 3 equivalent of John Sauer's answer above (in case anyone else stumbles upon this question like I just did):

func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
    if let selectedIndexPaths = tableView.indexPathsForSelectedRows {
        for selectedIndexPath in selectedIndexPaths {
            if selectedIndexPath.section == indexPath.section {
                tableView.deselectRow(at: selectedIndexPath, animated: true)
            }
        }
    }
    return indexPath
}
Rosenblum answered 24/7, 2017 at 23:47 Comment(2)
dont forget to set tableView.allowsMultipleSelection = truePorterhouse
You could also eliminate the outer if let and replace the for loop iterator with tableView.indexPathsForSelectedRows ?? [].Sophisticate
C
2

I think this is more Swifty styled code of the answer above.

func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
    tableView.indexPathsForSelectedRows?
        .filter { $0.section == indexPath.section }
        .forEach { tableView.deselectRow(at: $0, animated: true) }
    return indexPath
}
Contradiction answered 13/10, 2018 at 9:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.