Alphabetical sections in table table view in swift
This is how I recently implemented sorted list in a tableView in Swift programmatically,
import UIKit
class BreedController: UITableViewController{
var breeds = ["A": ["Affenpoo", "Affenpug", "Affenshire", "Affenwich", "Afghan Collie", "Afghan Hound"], "B": ["Bagle Hound", "Boxer"]]
struct Objects {
var sectionName : String!
var sectionObjects : [String]!
}
var objectArray = [Objects]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
tableView.registerClass(UITableViewCell.classForCoder(), forCellReuseIdentifier: "Cell")
// SORTING [SINCE A DICTIONARY IS AN UNSORTED LIST]
var sortedBreeds = sorted(breeds) { $0.0 < $1.0 }
for (key, value) in sortedBreeds {
println("\(key) -> \(value)")
objectArray.append(Objects(sectionName: key, sectionObjects: value))
}
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return objectArray.count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objectArray[section].sectionObjects.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
// SETTING UP YOUR CELL
cell.textLabel?.text = objectArray[indexPath.section].sectionObjects[indexPath.row]
return cell
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return objectArray[section].sectionName
}
}
In Swift 4 Dictionary(grouping:by:) was introduced to group a sequence to a dictionary by an arbitrary predicate.
This example maps the grouped dictionary to a custom struct Section
struct Section {
let letter : String
let names : [String]
}
...
let usernames = ["John", "Nancy", "James", "Jenna", "Sue", "Eric", "Sam"]
var sections = [Section]()
override func viewDidLoad() {
super.viewDidLoad()
// group the array to ["N": ["Nancy"], "S": ["Sue", "Sam"], "J": ["John", "James", "Jenna"], "E": ["Eric"]]
let groupedDictionary = Dictionary(grouping: usernames, by: {String($0.prefix(1))})
// get the keys and sort them
let keys = groupedDictionary.keys.sorted()
// map the sorted keys to a struct
sections = keys.map{ Section(letter: $0, names: groupedDictionary[$0]!.sorted()) }
self.tableView.reloadData()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellID = "cell"
let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath)
let section = sections[indexPath.section]
let username = section.names[indexPath.row]
cell.textLabel?.text = username
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sections[section].names.count
}
func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
func sectionIndexTitles(for tableView: UITableView) -> [String]? {
return sections.map{$0.letter}
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sections[section].letter
}
You can put your arrays with names into dictionary with letter keys.
For example
var names = ["a": ["and", "array"], "b": ["bit", "boring"]]; // dictionary with arrays setted for letter keys
then you need to access values in your dictionary in the next way
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return names[usernames[section]].count; // maybe here is needed to convert result of names[...] to NSArray before you can access count property
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let cellID = "cell"
let cell: UITableViewCell = self.tv.dequeueReusableCellWithIdentifier(cellID) as UITableViewCell
cell.textLabel?.text = names[usernames[indexPath.section]][indexPath.row]; // here you access elements in arrray which is stored in names dictionary for usernames[indexPath.section] key
return cell
}
Download CountryList Json file and put in side your project
https://gist.github.com/keeguon/2310008
var json = NSArray()
var arr_name = NSArray()
var arrIndexSection : NSArray = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]
override func viewDidLoad() {
let path = Bundle.main.path(forResource: "countries", ofType: "json")
let data = NSData(contentsOfFile: path! )
json = (try! JSONSerialization.jsonObject(with: data as! Data, options: JSONSerialization.ReadingOptions.mutableContainers)) as! NSArray
arr_name = json.value(forKey: "name") as! NSArray;
tableview.reloadData()
super.viewDidLoad()
}
// Side List in tableview
public func numberOfSections(in tableView: UITableView) -> Int {
return 26
}
public func sectionIndexTitles(for tableView: UITableView) -> [String]? {
return self.arrIndexSection as? [String] //Side Section title
}
public func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int
{
return index
}
public func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return arrIndexSection.object(at: section) as? String
}
// number of rows in table view
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
let predicate = NSPredicate(format: "SELF beginswith[c] %@", arrIndexSection.object(at: section) as! CVarArg)
let arrContacts = (arr_name as NSArray).filtered(using: predicate)
return arrContacts.count;
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell : TableViewCell=self.tableview.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
let predicate = NSPredicate(format: "SELF beginswith[c] %@", arrIndexSection.object(at: indexPath.section) as! CVarArg)
let arrContacts = (arr_name as NSArray).filtered(using: predicate) as NSArray
cell.textLabel?.text = arrContacts.object(at: indexPath.row) as? String
return cell
}