Select one row in each section of UITableView ios?

前端 未结 3 671
慢半拍i
慢半拍i 2021-01-15 02:50

Scenario:

I have made 2 sections in one UITableView and the user needs to select a row in each section as shown in the screenshot below.

Expected Outcome:

3条回答
  •  傲寒
    傲寒 (楼主)
    2021-01-15 03:29

    I wrote a sample code where a compound datasource holds datasource objects for each section. Sounds complicated but actually provides an easy to extend architecture. And keeps your view controller small.

    The advantages of this approach:

    • Small ViewController
    • ViewController set ups view and handles user interaction — as it should be in MVC
    • Reusable datasources
    • by using different datasources per section easy to customize cells for each section

    the base datasource architecture

    This provides easy extension and is simple to reuse.


    @import UIKit;
    
    @interface ComoundTableViewDataSource : NSObject
    @property (nonatomic,strong, readonly) NSMutableDictionary *internalDictionary;
    
    
    -(void) setDataSource:(id)dataSource forSection:(NSUInteger)section;
    -(instancetype)initWithTableView:(UITableView *)tableView;
    @end
    

    #import "ComoundTableViewDataSource.h"
    
    
    @interface ComoundTableViewDataSource () 
    @property (nonatomic,strong, readwrite) NSMutableDictionary *internalDictionary;
    @property (nonatomic, weak) UITableView *tableView;
    @end
    
    @implementation ComoundTableViewDataSource
    -(instancetype)initWithTableView:(UITableView *)tableView
    {
        self = [super init];
        if (self) {
            _tableView = tableView;
            tableView.dataSource = self;
            _internalDictionary = [@{} mutableCopy];
            [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"Cell"];
    
        }
        return self;
    }
    
    -(void)setDataSource:(id)dataSource forSection:(NSUInteger)section
    {
        self.internalDictionary[@(section)] = dataSource;
        [self.tableView reloadData];
    
    }
    
    -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
        return [[self.internalDictionary allKeys] count];
    }
    
    -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        id sectionDataSource = self.internalDictionary[@(section)];
        return [sectionDataSource tableView:tableView numberOfRowsInSection:section];
    }
    
    -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        id sectionDataSource = self.internalDictionary[@(indexPath.section)];
        return [sectionDataSource tableView:tableView cellForRowAtIndexPath:indexPath];
    
    }
    
    
    -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
    {
        id sectionDataSource = self.internalDictionary[@(section)];
        return [sectionDataSource tableView:tableView titleForHeaderInSection:section];
    }
    @end
    

    @import UIKit;
    
    @interface SingleSectionDataSource : NSObject 
    @property (nonatomic, strong, readonly) NSArray *array;
    @property (nonatomic, strong, readonly) UITableView *tableView;
    
    - (instancetype)initWithArray:(NSArray *)array;
    @end
    

    #import "SingleSectionDataSource.h"
    
    @interface SingleSectionDataSource ()
    @property (nonatomic, strong, readwrite) NSArray *array;
    @property (nonatomic, strong, readwrite) UITableView *tableView;
    
    @end
    
    @implementation SingleSectionDataSource
    
    - (instancetype)initWithArray:(NSArray *)array
    {
        self = [super init];
        if (self) {
            self.array = array;
        }
        return self;
    }
    -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
        return 1;
    }
    
    -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        self.tableView = tableView;
        return self.array.count;
    }
    
    -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
        cell.textLabel.text = self.array[indexPath.row];
        return cell;
    }
    
    -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
    {
        return [@(section) stringValue];
    }
    
    @end
    

    the selection datasource architecture

    We extend the classes from above to allow one selection per section

    #import "ComoundTableViewDataSource.h"
    
    @interface OnSelectionPerSectionComoundTableViewDataSource : ComoundTableViewDataSource
    -(void)selectedCellAtIndexPath:(NSIndexPath *)indexPath;
    
    @end
    

    #import "OnSelectionPerSectionComoundTableViewDataSource.h"
    #import "SingleSelectionSingleSectionDataSource.h"
    
    @implementation OnSelectionPerSectionComoundTableViewDataSource
    
    
    -(instancetype)initWithTableView:(UITableView *)tableView
    {
        self = [super initWithTableView:tableView];
        if(self){
            [tableView setAllowsMultipleSelection:YES];
        }
        return self;
    }
    
    -(void)selectedCellAtIndexPath:(NSIndexPath *)indexPath
    {
        SingleSelectionSingleSectionDataSource *sectionDataSource = self.internalDictionary[@(indexPath.section)];
        [sectionDataSource selectedCellAtIndexPath:indexPath];
    }
    @end
    

    View Controller Implementation

    As promised, a very slim view controller:

    @interface ViewController () 
    @property (weak, nonatomic) IBOutlet UITableView *tableView;
    @property (nonatomic, strong) OnSelectionPerSectionComoundTableViewDataSource *tableViewDataSource;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        self.tableViewDataSource = [[OnSelectionPerSectionComoundTableViewDataSource alloc] initWithTableView:self.tableView];
        self.tableView.delegate = self;
        [self.tableViewDataSource setDataSource:[[SingleSelectionSingleSectionDataSource alloc] initWithArray:@[@"Hallo", @"Welt"]] forSection:0];
        [self.tableViewDataSource setDataSource:[[SingleSelectionSingleSectionDataSource alloc] initWithArray:@[@"Hello", @"World", @"!"]] forSection:1];
        [self.tableViewDataSource setDataSource:[[SingleSelectionSingleSectionDataSource alloc] initWithArray:@[@"Hola", @"Mundo", @"!", @"¿Que tal?"]] forSection:2];
    }
    
    -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
        [self.tableViewDataSource selectedCellAtIndexPath:indexPath];
    }
    @end
    

    You will want to add methods to the datasources to get the selected rows.

    get the example: https://github.com/vikingosegundo/CompoundDatasourceExample

    Note This code has a cell reuse issue. It is fixed on GitHub.

提交回复
热议问题