Visal Sambo
Visal Sambo

Reputation: 1490

How to add another section based on row input (alphabet) in UITableView - swift

I am a new iOS programming. I am creating a sample app which similar to contact app. I wonder how that real application works. For example, Our tableview display names based on alphabet like name starts with A will stays in A section and B will stays in B section and so on. And when user input some names which not exist in section then, new section will be auto created. I wonder how can i achieve something like this.

This is how i created UITableView programmatically. Not using storyboard

private let cellId = "cellId"
private let array = ["Aname", "Bname", "Cname", "Dname"]
override func viewDidLoad() {
    super.viewDidLoad()

    tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellId)
}

Here is how i custom display data

// Table View

extension ContactListController {

override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

    let label = UILabel()
    label.backgroundColor = .gray
    label.text = "A"
    return label

}
override func numberOfSections(in tableView: UITableView) -> Int {
    return 2
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {


    return array.count


}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {


    let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)


    cell.textLabel?.text = array[indexPath.row]



    return cell

}

}

For my desire output i would like to display name starts with A should be in A section and so on...

Thank for your explanation.

Upvotes: 2

Views: 148

Answers (2)

vadian
vadian

Reputation: 285150

The easiest solution is the method Dictionary(grouping: by:)

  • Create an array for the sections (keys), a dictionary for the names (people) and make array mutable

    var keys = [String]()
    var people = [String : [String]]()
    
    private var array = ["Aname", "Bname", "Cname", "Dname"]
    
  • Add a method to group the data

    func groupData()
    {
        people = Dictionary(grouping: array, by: {String($0.first!)})
        keys = people.keys.sorted()
        tableView.reloadData()
    }
    

    If you want to restrict the grouping to consider only capital letters write

    people = Dictionary(grouping: array, by: {$0.range(of: "^[A-Z]", options: .regularExpression) != nil ? String($0.first!) : "Unknown"})
    
  • in viewDidLoad call the method

    override func viewDidLoad() {
        super.viewDidLoad()
    
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellId)
        groupData()
    }
    
  • Instead of viewForHeaderInSection implement titleForHeaderInSection

    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return keys[section]
    }
    
  • The other relevant table view datasource and delegate methods are

    override func numberOfSections(in tableView: UITableView) -> Int {
        return keys.count
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        let letter = keys[section]
        return people[letter]!.count
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
        let letter = keys[indexPath.section]
        let item = people[letter]![indexPath.row]
        cell.textLabel!.text = item
        return cell
    }
    

To add a new item append the name to array and call groupData

If you want a more sophisticated solution with animations when the sections and rows are inserted you have to write the logic yourself. The design array for the keys and dictionary for the names can be used as well as a custom struct including the letter index and an array for the rows.

Upvotes: 1

user3295568
user3295568

Reputation: 1

You should gouup data contact before show in table view,Each key will a section in tableview, i have sample code group data:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    NSArray *arrNameContact = @[@"Aname",@"Bname",@"Cname",@"Dname",@"Dname1",@"Aname1",@"Ename1",@"Bname1"];
    NSMutableArray *arrKey = [self getArrayKeyFromArrayName:arrNameContact];

    NSMutableDictionary *dict =@{}.mutableCopy;

    for (NSString *key in arrKey) {
        NSMutableArray *arrContactWithKey = [[NSMutableArray alloc]init];
        for (NSString *name in arrNameContact) {
            if ([name hasPrefix:key]) {
                [arrContactWithKey addObject:name];
            }
        }
        [dict setObject:arrContactWithKey forKey:key];
    }
    NSLog(@"%@",dict);
}

// Get All alphabet
- (NSMutableArray *) getArrayKeyFromArrayName:(NSArray *)arrName {
    NSMutableArray *arrKey = @[].mutableCopy;
    for (int i = 0; i < arrName.count; i++) {
        NSString *strFirstCharacter = [arrName[i] substringToIndex:1];
        if (arrKey.count == 0) {
            [arrKey addObject:strFirstCharacter];
        } else {
            if (![self checkItemExistKey:strFirstCharacter inArray:arrKey]) {
                [arrKey addObject:strFirstCharacter];
            }
        }
    }
    return arrKey;
}

- (BOOL) checkItemExistKey:(NSString *) key inArray:(NSArray *)arrKey {
    for (NSString *keyCheck in arrKey) {
        if ([keyCheck isEqualToString:key]) {
            return TRUE;
        }
    }
    return FALSE;
}

result after group data:

Printing description of dict:
{
    A =     (
        Aname,
        Aname1
    );
    B =     (
        Bname,
        Bname1
    );
    C =     (
        Cname
    );
    D =     (
        Dname,
        Dname1
    );
    E =     (
        Ename1
    );
}

Good luck!

Upvotes: 0

Related Questions