web-dev-qa-db-fra.com

Ajout de sections, séparées par des dates, à UITableView dans Swift

Je suis un débutant à la programmation Swift et iOS, vous devrez donc pardonner la question peut-être simple. 

J'ai créé un tableau qui affiche le contenu d'un tableau (chaînes) à la simple pression d'un bouton. Maintenant, j'aimerais "grouper" ces chaînes dans les sections tableView, triées par date.

Plus en détail: lorsque l'utilisateur appuie sur le bouton, la chaîne doit être insérée à l'index 0 du tableau et affichée dans une section avec un en-tête de date aujourd'hui. S'il existe des valeurs antérieures à la date d'aujourd'hui dans le tableau, elles doivent être affichées dans une section distincte pour cette date. Chaque section doit correspondre à une journée de 24 heures et afficher toutes les chaînes ajoutées au cours de la journée.

Voici un exemple de code de ce que j'ai réalisé jusqu'à présent:

var testArray[String]()
var sectionsInTable[String]()

@IBOutlet weak var testTable: UITableView!

@IBAction func saveButton(sender: AnyObject) {

testArray.insert("\(strTest)", atIndex: 0)
testTable.reloaddata()

}

func numberOfSectionsInTableView(tableView: UITableView) -> Int {

    return sectionsInTable.count

}

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

    return testArray.count

}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    var cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")

    cell.textLabel.text = String(testArray[indexPath.row])        

    return cell
}

Je ne sais vraiment pas comment gérer la partie des sections. J'espère que quelqu'un pourra me diriger dans la bonne direction. Merci!

16
maxpetter

Je le ferais généralement avec Core Data et NSFetchedResultsController car il possède des méthodes intégrées pour obtenir des sections.

Cependant, je vais répondre à la question sans utiliser Core Data. Le code est un peu en désordre mais c'est parti ...

Tout d'abord, vous devez créer un objet qui stockera à la fois la date et le texte. Le tableau de test sera un tableau de ces objets, au lieu d'un tableau de chaînes. Par exemple:

class DateTextItem: NSObject {
    var text: String = ""
    var insertDate: NSDate = NSDate()    
}

var testArray = [DateTextItem]()

Ensuite, lorsque le bouton de sauvegarde est atteint, nous allons créer et ajouter l'objet DateTextItem. Nous ajouterons également la date aux sectionsInTable si elle n'existe pas déjà.

@IBAction func saveButton(sender: AnyObject) {
    let newItem = DateTextItem()
    newItem.text = "Test \(testArray.count)"

    // this is for development only
    // increment the date after 2 records so we can test grouping by date
    if testArray.count >= (testArray.count/2) {
        let incrementDate = NSTimeInterval(86400*(testArray.count/2))
        newItem.insertDate = NSDate(timeIntervalSinceNow:incrementDate)
    }

    testArray.append(newItem)

    // this next bit will create a date string and check if it's in the sectionInTable
    let df = NSDateFormatter()
    df.dateFormat = "MM/dd/yyyy"
    let dateString = df.stringFromDate(newItem.insertDate)

    // create sections NSSet so we can use 'containsObject'
    let sections: NSSet = NSSet(array: sectionsInTable)

    // if sectionsInTable doesn't contain the dateString, then add it
    if !sections.containsObject(dateString) {
        sectionsInTable.append(dateString)
    }

    self.tableView.reloadData()
}

Ensuite, j'ai créé une fonction pour obtenir les éléments d'une section, car nous en avons besoin à plusieurs endroits.

func getSectionItems(section: Int) -> [DateTextItem] {
    var sectionItems = [DateTextItem]()

    // loop through the testArray to get the items for this sections's date
    for item in testArray {
        let dateTextItem = item as DateTextItem
        let df = NSDateFormatter()
        df.dateFormat = "MM/dd/yyyy"
        let dateString = df.stringFromDate(dateTextItem.insertDate)

        // if the item's date equals the section's date then add it
        if dateString == sectionsInTable[section] as NSString {
            sectionItems.append(dateTextItem)
        }
    }

    return sectionItems
}

Enfin, voici à quoi ressemblent les méthodes de source de données de vue tableau

// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return sectionsInTable.count
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.getSectionItems(section).count
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    // Configure the cell...
    var cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")

    // get the items in this section
    let sectionItems = self.getSectionItems(indexPath.section)
    // get the item for the row in this section
    let dateTextItem = sectionItems[indexPath.row]

    cell.textLabel.text = dateTextItem.text

    return cell
}

// print the date as the section header title
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return sectionsInTable[section]
}
19
Ron Fessler

J'avais besoin de quelque chose de similaire, et bien que la solution de Ron Fessler fonctionne, quand il y a beaucoup de sections/rangées, le chargement de données par une table est très long, et même après beaucoup réactif. Je pense que le problème principal est le fonctionnement de getSectionItems car il passe toujours en revue tous les éléments ...

Ma solution:

struct TableItem {
    let title: String
    let creationDate: NSDate
}

var sections = Dictionary<String, Array<TableItem>>()
var sortedSections = [String]()

@IBAction func saveButton(sender: AnyObject) {

    let date:String = "your date in string..."

    //if we don't have section for particular date, create new one, otherwise we'll just add item to existing section
    if self.sections.indexForKey(date) == nil {
        self.sections[date] = [TableItem(title: name, creationDate: date)]
    }
    else {
        self.sections[date]!.append(TableItem(title: name, creationDate: date))
    } 

    //we are storing our sections in dictionary, so we need to sort it 
    self.sortedSections = self.sections.keys.array.sorted(>)
    self.tableView.reloadData()
}

méthodes tableView dataSource:

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return sections.count
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return sections[sortedSections[section]]!.count
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    var cell = tableView.dequeueReusableCellWithIdentifier("Cell")        

    let tableSection = sections[sortedSections[indexPath.section]]
    let tableItem = tableSection![indexPath.row]

    cell.titleLabel?.text = tableItem.title

    return cell
}

override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return sortedSections[section]
}
23
Adam Bardon

Vous devez créer un tableau pour chaque jour (appelé dayArray [] par exemple) et l'ajouter à sectionInTable [] et faire quelque chose comme ça:

func numberOfSectionsInTableView(tableView: UITableView) -> Int {

    return sectionsInTable.count

}

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

    return sectionsInTable.objectAtIndex(section).count

}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    var cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")

    cell.textLabel.text = String(sectionInTable.objectAtIndex(indexPath.section).objectAtIndex(indexPath.row))        

    return cell
}

Désolé si j'ai commis des erreurs, je ne connais pas bien Swift, mais je pense que l'idée peut aider.

0
Vincent