Добавление разделов по датам в UITableView в Swift
Я полный новичок в программировании Swift и iOS, поэтому вам придется простить простой вопрос.
Я создал tableView, который отображает содержимое массива (строки) нажатием кнопки.
Теперь я хотел бы "группировать" эти строки в разделах tableView, отсортированных по дате.
Подробнее: Когда пользователь нажимает кнопку, строка должна быть вставлена в индекс 0 массива и отображаться в разделе с заголовком текущей даты. Если в массиве есть значения старше сегодняшней даты, они должны отображаться в отдельном разделе для этой даты. Каждый раздел должен соответствовать 24-часовому дню и отображать все строки, добавленные в течение этого дня.
Вот пример кода, который я достиг до сих пор:
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
}
Я действительно не знаю, как управлять частью раздела. Надеюсь, кто-то может указать мне в правильном направлении. Спасибо!
Ответы
Ответ 1
Обычно я делаю это с помощью Core Data и NSFetchedResultsController, поскольку у него есть встроенные методы для получения разделов.
Однако я отвечу на вопрос без использования Core Data. Код немного грязнее, но здесь мы идем...
Сначала вам нужно создать объект, в котором будут храниться как дата, так и текст. TestArray будет массивом этих объектов, а не массивом String. Например:
class DateTextItem: NSObject {
var text: String = ""
var insertDate: NSDate = NSDate()
}
var testArray = [DateTextItem]()
Затем, когда нажимается saveButton, мы создадим и добавим объект DateTextItem. Мы также добавим дату в sectionInTable, если она еще не существует.
@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 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()
}
Затем я создал функцию для получения элементов в секции, так как нам это нужно в пару мест.
func getSectionItems(section: Int) -> [DateTextItem] {
var sectionItems = [DateTextItem]()
// loop through the testArray to get the items for this sections 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 date equals the section date then add it
if dateString == sectionsInTable[section] as NSString {
sectionItems.append(dateTextItem)
}
}
return sectionItems
}
Наконец, вот как выглядят методы источника данных Table View
// 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]
}
Ответ 2
Мне было нужно что-то подобное, и в то время как Рон Фесслер работал, когда было много секций/строк, для таблицы потребовалось очень много времени загружать данные, и даже после этого он не очень отзывчив. Основная проблема там, я думаю, это функция getSectionItems, поскольку она всегда будет проходить через все элементы...
Мое решение:
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()
}
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]
}
Ответ 3
Вы должны создать массив для каждого дня (например, dayArray []) и добавить его в sectionInTable [] и сделать что-то вроде этого:
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
}
Извините, если я ошибался, я не знаком с быстрым, но я думаю, что эта идея может помочь.
Ответ 4
Я реализовал универсальный алгоритм для сортировки любых объектов, которые могут быть идентифицированы к тому или иному дню. Я думаю, было бы полезно в таких случаях:
protocol DayCategorizable {
var identifierDate: Date { get }
}
extension Array where Element: DayCategorizable {
var daySorted: [Date: [Element]] {
var result: [Date: [Element]] = [:]
let calendar = Calendar.current
self.forEach { item in
let i = calendar.startOfDay(for: item.identifierDate)
if result.keys.contains(i) {
result[i]?.append(item)
} else {
result[i] = [item]
}
}
return result
}
}