UITableView: Unterschied zwischen den Versionen
| (11 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
| Zeile 3: | Zeile 3: | ||
== Quickstart == | == Quickstart == | ||
| − | * Öffne dein Storyboard oder deine XIB-Datei und ziehe ein '''UITableView-Element''' aus der Bibliothek auf dein View. | + | * Öffne dein Storyboard oder deine XIB-Datei und ziehe ein '''UITableView-Element''' aus der Bibliothek auf dein View. |
| + | ** Alternativ kannst du auch einen kompletten TableViewController nutzen. Der spart einige der folgenden Schritte. | ||
* Ziehe ein '''UITableCell-Element''' in das UITableView-Element | * Ziehe ein '''UITableCell-Element''' in das UITableView-Element | ||
** Vergebe einen '''Identifier für das Cell-Element''' z.B. ReusableCell | ** Vergebe einen '''Identifier für das Cell-Element''' z.B. ReusableCell | ||
* Erstelle ein '''Outlet''' für den das UITableView-Element | * Erstelle ein '''Outlet''' für den das UITableView-Element | ||
| − | * Implementiere das '''UITableViewDataSource-Protokoll''' in deiner Klasse. Hierdurch wird der tableView wenn er geladen wird einen Datenrequest ausführen. | + | * Implementiere das '''UITableViewDataSource-Protokoll''' in deiner Klasse. Hierdurch wird der tableView wenn er geladen wird einen Datenrequest ausführen. |
| − | |||
* In der viewDidLoad Funktion delegiere die DataSource des TableViews auf den Controller | * In der viewDidLoad Funktion delegiere die DataSource des TableViews auf den Controller | ||
tableView.dataSource = self | tableView.dataSource = self | ||
| + | |||
| + | == TableView und Cell konfigurieren und füllen == | ||
| + | Es bietet sich für bessere Übersichtlichkeit an die Funktionalität in eine Extension des Controllers zu packen. | ||
| + | extension MyViewController: UITableViewDataSource{} | ||
| + | |||
| + | Die wesentlichen Schritte: | ||
| + | # TableView mit der Anzahl benötigter Zellen und der Datenquelle vorbereiten | ||
| + | # Zellen füllen | ||
| + | # Benötigte Aktionen konfigurieren (Löschen von Zellen, hinzufügen...) | ||
| + | |||
| + | === Anzahl der benötigten Zellen übergeben === | ||
| + | Dazu überschreibt man die tableView Funktion folgendermaßen. fileList ist in diesem Beispiel ein Array das Dateinamen enthält, die aufgelistet werden sollen. | ||
| + | <syntaxhighlight lang="swift"> | ||
| + | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { | ||
| + | return fileList.count | ||
| + | } | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | === Zellen füllen === | ||
| + | '''Layout:''' Der Zellenprototyp kann im einfachsten Fall z.b. ein Label enthalten. Im Propertymanager gibt es auch vorgefertigte Layouts die man nutzen kann. | ||
| + | |||
| + | Mit dieser Funktion füllt man die Liste / Tabelle. Sie wird vom Tableview für jede Zelle ausgeführt. Über den Parameter '''indexPath.row''' erhält mit die aktuelle Zellennummer. Mit der Funktion dequeueReusableCell legt man die Vorlage fest die genutzt wird. Den Namen (hier MyCell) vergibt man im Storyboard im Propertymanager unter identifier. Im Beispiel wurde der Zelle ein Label "textLabel" hinzugefügt und in diesem wird "cell [Nummer]" ausgegeben. | ||
| + | <syntaxhighlight lang="swift"> | ||
| + | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { | ||
| + | let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) | ||
| + | cell.textLabel?.text = String("cell: \(indexPath.row)") | ||
| + | return cell | ||
| + | } | ||
| + | </syntaxhighlight> | ||
== Beispiele == | == Beispiele == | ||
=== Basic UITableView === | === Basic UITableView === | ||
| − | Siehe auch Quickstart | + | Siehe auch Quickstart. Im Storyboard steuern wir den TableView in einer normalen UIViewController Klasse. Deshalb müssen wir den Delegate des TableView zuerst übernehmen. |
<syntaxhighlight lang="swift"> | <syntaxhighlight lang="swift"> | ||
| Zeile 80: | Zeile 109: | ||
===== iOS13 and higher version ===== | ===== iOS13 and higher version ===== | ||
| − | You're right, in iOS 13 and later UITableViewRowAction has been deprecated and replaced by the UIContextualAction and related classes. | + | You're right, in iOS 13 and later '''UITableViewRowAction has been deprecated and replaced by the UIContextualAction and related classes.''' |
| − | |||
| − | |||
| − | + | To implement a delete gesture on a table view cell in iOS 13 and later, you can use the '''UIContextualAction''' class along with the '''UISwipeActionsConfiguration''' class. | |
Here's an example of how you can implement a delete gesture for a table view in iOS 13 and later: | Here's an example of how you can implement a delete gesture for a table view in iOS 13 and later: | ||
| + | <syntaxhighlight lang="swift"> | ||
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { | func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { | ||
let delete = UIContextualAction(style: .destructive, title: "Delete") { (action, view, completion) in | let delete = UIContextualAction(style: .destructive, title: "Delete") { (action, view, completion) in | ||
| Zeile 99: | Zeile 127: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| − | In this example it creates an instance of UIContextualAction and set its style to be .destructive and its title to be "Delete" . Then it removes the data from the data source and call deleteRows to remove the corresponding row from the table view. completion(true) will indicate that the action was performed and the row can be dismissed. | + | In this example it creates an '''instance of UIContextualAction''' and set its style to be .destructive and its title to be "Delete" . Then it removes the data from the data source and call deleteRows to remove the corresponding row from the table view. completion(true) will indicate that the action was performed and the row can be dismissed. |
| − | It also creates an instance of UISwipeActionsConfiguration class, it's a configuration object that you use to define the actions to display when the user swipes left on a table view row. | + | It also creates an '''instance of UISwipeActionsConfiguration''' class, it's a configuration object that you use to define the actions to display when the user swipes left on a table view row. |
| − | You can also customize the title, background color and other properties of the UIContextualAction. | + | You can also '''customize''' the title, background color and other properties of the UIContextualAction. |
| − | As always, it's important to handle all edge cases that may happen during the deletion process and also it's worth noting that you can also define leading swipe actions, i.e actions that will be shown when the user swipes to the right by using leadingSwipeActionsConfigurationForRowAt method | + | As always, it's important to handle all edge cases that may happen during the deletion process and also it's worth noting that you can also define '''leading swipe actions''', i.e actions that will be shown when the user swipes to the right by using leadingSwipeActionsConfigurationForRowAt method |
| + | |||
| + | You do not need to set the isEditing property. In the previous versions (see below) when you set the table view's isEditing property to true, it enabled the ability for the table view to display the delete button when swiped on a cell. But using the UIContextualAction and UISwipeActionsConfiguration classes, you have more flexibility and more control over the swipe actions and their behavior. | ||
===== Pre iOS 13 Version ===== | ===== Pre iOS 13 Version ===== | ||
| Zeile 147: | Zeile 177: | ||
That's it, now when you swipe on a cell in your table view, the "Delete" action will be displayed, and when tapped, the corresponding row will be deleted from the table view. | That's it, now when you swipe on a cell in your table view, the "Delete" action will be displayed, and when tapped, the corresponding row will be deleted from the table view. | ||
It is important to note that this is just an example and your implementation may vary depending on your specific use case and the data model you are using. | It is important to note that this is just an example and your implementation may vary depending on your specific use case and the data model you are using. | ||
| + | |||
| + | === Beispiel Songlist === | ||
| + | Todo Erklärungen | ||
| + | <syntaxhighlight lang="swift"> | ||
| + | //MARK: - UITableViewDataSource Protocol | ||
| + | extension MetronomeViewController: UITableViewDataSource{ | ||
| + | /** | ||
| + | Implement UITableViewDataSource Protocol which is responsible for telling tableview how many cells needed and how to fill them | ||
| + | */ | ||
| + | // Setup Number of rows | ||
| + | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { | ||
| + | return setlistManager.currentSetlist.songs.count | ||
| + | } | ||
| + | // Setup cells | ||
| + | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { | ||
| + | |||
| + | let cell = tableView.dequeueReusableCell(withIdentifier: "currentSetlistCell", for: indexPath) | ||
| + | let strSongNumber = String(format:"%d",(indexPath.row + 1)) | ||
| + | cell.textLabel?.text = "\(strSongNumber) \(setlistManager.currentSetlist.songs[indexPath.row].title)" | ||
| + | let strFrequency = String(format:"%.1f bpm",setlistManager.currentSetlist.songs[indexPath.row].frequency) | ||
| + | cell.detailTextLabel?.text = strFrequency | ||
| + | return cell | ||
| + | } | ||
| + | } | ||
| + | |||
| + | //MARK: - UITableViewDelegate Extension | ||
| + | extension MetronomeViewController: UITableViewDelegate{ | ||
| + | /** | ||
| + | Implement UITableViewDelegate | ||
| + | Methods for managing selections, configuring section headers and footers, deleting and reordering cells, and performing other actions in a table view. | ||
| + | */ | ||
| + | // SELECT CELL | ||
| + | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { | ||
| + | let song = self.setlistManager.currentSetlist.songs[indexPath.row] | ||
| + | print("selected row: \(indexPath.row) Title: \(song.title) \(song.frequency)") | ||
| + | metronome.stop() | ||
| + | setFrequency(song: song) | ||
| + | // metronome.start() // Todo make setting startOnListTapped | ||
| + | } | ||
| + | |||
| + | // SWIPE ACTION SETUP | ||
| + | func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { | ||
| + | let delete = UIContextualAction(style: .destructive, title: "Delete") { (action, view, completion) in | ||
| + | // Delete the row from the data source | ||
| + | self.setlistManager.currentSetlist.songs.remove(at: indexPath.row) | ||
| + | tableView.deleteRows(at: [indexPath], with: .fade) | ||
| + | self.currentTableView.reloadData() | ||
| + | self.setlistManager.persistSetlist(setlist: self.setlistManager.currentSetlist) | ||
| + | completion(true) | ||
| + | } | ||
| + | return UISwipeActionsConfiguration(actions: [delete]) | ||
| + | } | ||
| + | |||
| + | // Manage REORDERING of the tableView items | ||
| + | func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { | ||
| + | let movedSong = setlistManager.currentSetlist.songs[sourceIndexPath.row] | ||
| + | setlistManager.currentSetlist.songs.remove(at: sourceIndexPath.row) | ||
| + | setlistManager.currentSetlist.songs.insert(movedSong, at: destinationIndexPath.row) | ||
| + | } | ||
| + | } | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | == UITableViewController == | ||
| + | |||
| + | Eine UITableViewController ist eine Unterklasse von UIViewController, die '''speziell für die Verwaltung einer Tabelle''' entwickelt wurde. Es bietet eine bequeme Möglichkeit, eine Tabelle in einem View-Controller einzurichten, sowie eine Reihe von Methoden und Eigenschaften, die es einfacher machen, die Tabelle und ihre Daten zu verwalten. | ||
| + | |||
| + | Zum Beispiel implementiert die Klasse UITableViewController die Protokolle UITableViewDelegate und UITableViewDataSource standardmäßig, so dass Sie leicht die erforderlichen Daten und das Verhalten für die Tabelle bereitstellen können, wie die Anzahl der Zeilen, der Inhalt der Zellen und das Verhalten, wenn eine Zeile ausgewählt wird. | ||
| + | |||
| + | Den Editiermodus für die Tabelle kann man allein durch das Erstellen eines Editbuttons in der NavigationBar erreichen. | ||
| + | |||
| + | self.navigationItem.rightBarButtonItem = self.editButtonItem | ||
| + | |||
| + | Der TableViewController checkt das automatisch und ruft die entsprechende Delegatfunktion auf ohne dass man noch Actions für den Button erstellen muss. | ||
| + | |||
| + | Außerdem stellt XCode gleich eine Reihe von üblicherweise genutzten Codebeispielen bereit. | ||
| + | |||
| + | === Beispiel mit UITableViewController === | ||
| + | TODO | ||
| + | |||
| + | == Weitere Table View Snippets == | ||
| + | === Multiple Loading verhindern === | ||
| + | Wenn der View das erste mal geladen wird werden oft mehrere Aufrufe getätigt. Damit soll sichergestellt werden, dass der View immer die Korrekte Zahl an Elementen enthält. Das ist wohl auch kein Performance Problem. Jedoch wenn du sicherstellen möchtest, dass der View nur einmal geladen wird, kannst du das so lösen: | ||
| + | |||
| + | <syntaxhighlight lang="swift"> | ||
| + | var dataLoaded = false | ||
| + | |||
| + | override func viewDidAppear(_ animated: Bool) { | ||
| + | super.viewDidAppear(animated) | ||
| + | if !dataLoaded { | ||
| + | dataLoaded = true | ||
| + | tableView.reloadData() | ||
| + | } | ||
| + | } | ||
| + | |||
| + | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { | ||
| + | if dataLoaded { | ||
| + | // Return the actual number of rows | ||
| + | } else { | ||
| + | return 0 | ||
| + | } | ||
| + | } | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | In this example, the dataLoaded flag is initially set to false. When the viewDidAppear method is called, the flag is checked. If the flag is false, it means that the data has not yet been loaded, so the dataLoaded flag is set to true and the tableView.reloadData() method is called. This will trigger the func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int method to be called once, with the actual number of rows. | ||
| + | |||
| + | With this approach, the func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int method will only be called once when the UITableView first appears on screen, instead of being called multiple times. | ||
Aktuelle Version vom 3. Februar 2023, 20:11 Uhr
Links[Bearbeiten]
UIKit Framework
Quickstart[Bearbeiten]
- Öffne dein Storyboard oder deine XIB-Datei und ziehe ein UITableView-Element aus der Bibliothek auf dein View.
- Alternativ kannst du auch einen kompletten TableViewController nutzen. Der spart einige der folgenden Schritte.
- Ziehe ein UITableCell-Element in das UITableView-Element
- Vergebe einen Identifier für das Cell-Element z.B. ReusableCell
- Erstelle ein Outlet für den das UITableView-Element
- Implementiere das UITableViewDataSource-Protokoll in deiner Klasse. Hierdurch wird der tableView wenn er geladen wird einen Datenrequest ausführen.
- In der viewDidLoad Funktion delegiere die DataSource des TableViews auf den Controller
tableView.dataSource = self
TableView und Cell konfigurieren und füllen[Bearbeiten]
Es bietet sich für bessere Übersichtlichkeit an die Funktionalität in eine Extension des Controllers zu packen.
extension MyViewController: UITableViewDataSource{}
Die wesentlichen Schritte:
- TableView mit der Anzahl benötigter Zellen und der Datenquelle vorbereiten
- Zellen füllen
- Benötigte Aktionen konfigurieren (Löschen von Zellen, hinzufügen...)
Anzahl der benötigten Zellen übergeben[Bearbeiten]
Dazu überschreibt man die tableView Funktion folgendermaßen. fileList ist in diesem Beispiel ein Array das Dateinamen enthält, die aufgelistet werden sollen.
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fileList.count
}
Zellen füllen[Bearbeiten]
Layout: Der Zellenprototyp kann im einfachsten Fall z.b. ein Label enthalten. Im Propertymanager gibt es auch vorgefertigte Layouts die man nutzen kann.
Mit dieser Funktion füllt man die Liste / Tabelle. Sie wird vom Tableview für jede Zelle ausgeführt. Über den Parameter indexPath.row erhält mit die aktuelle Zellennummer. Mit der Funktion dequeueReusableCell legt man die Vorlage fest die genutzt wird. Den Namen (hier MyCell) vergibt man im Storyboard im Propertymanager unter identifier. Im Beispiel wurde der Zelle ein Label "textLabel" hinzugefügt und in diesem wird "cell [Nummer]" ausgegeben.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath)
cell.textLabel?.text = String("cell: \(indexPath.row)")
return cell
}
Beispiele[Bearbeiten]
Basic UITableView[Bearbeiten]
Siehe auch Quickstart. Im Storyboard steuern wir den TableView in einer normalen UIViewController Klasse. Deshalb müssen wir den Delegate des TableView zuerst übernehmen.
import UIKit
struct Song {
let title: String
let frequency: Float
}
import UIKit
class EditViewController: UIViewController {
// Model-Objekte
var frequency: Double? // will receive actual frequency from MetronomeViewController
//var songs = [Song]()
var songs: [Song] = [
Song(title: "Arm aber reich", frequency: 124),
Song(title: "Rebell", frequency: 82.5),
Song(title: "Herz hat recht", frequency: 98)
]
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self // catch datasource delegate
tableView.delegate = self // catch view delegate
}
}
/**
Implement UITableViewDataSource Protocol which is responsible for telling tableview how many cells needed and how to fill them
*/
extension EditViewController: UITableViewDataSource{
// How many rows we need?
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return songs.count
}
// Called for every dataitem -> let's create a cell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SongCell", for: indexPath)
let strSongNumber = String(format:"%d / %d",(indexPath.row + 1), (indexPath.count + 1) )
cell.textLabel?.text = "\(strSongNumber) \(songs[indexPath.row].title)"
let strFrequency = String(format:"%.1f bpm",songs[indexPath.row].frequency)
cell.detailTextLabel?.text = strFrequency
return cell
}
}
/**
Implement UITableViewDelegate
Methods for managing selections, configuring section headers and footers, deleting and reordering cells, and performing other actions in a table view.
*/
extension EditViewController: UITableViewDelegate{
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("row: \(indexPath.row) ")
}
}
Swipe Actions[Bearbeiten]
How can I implement a delete gesture to a table view?[Bearbeiten]
iOS13 and higher version[Bearbeiten]
You're right, in iOS 13 and later UITableViewRowAction has been deprecated and replaced by the UIContextualAction and related classes.
To implement a delete gesture on a table view cell in iOS 13 and later, you can use the UIContextualAction class along with the UISwipeActionsConfiguration class.
Here's an example of how you can implement a delete gesture for a table view in iOS 13 and later:
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let delete = UIContextualAction(style: .destructive, title: "Delete") { (action, view, completion) in
// Delete the row from the data source
self.songs.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
completion(true)
}
return UISwipeActionsConfiguration(actions: [delete])
}
In this example it creates an instance of UIContextualAction and set its style to be .destructive and its title to be "Delete" . Then it removes the data from the data source and call deleteRows to remove the corresponding row from the table view. completion(true) will indicate that the action was performed and the row can be dismissed.
It also creates an instance of UISwipeActionsConfiguration class, it's a configuration object that you use to define the actions to display when the user swipes left on a table view row.
You can also customize the title, background color and other properties of the UIContextualAction.
As always, it's important to handle all edge cases that may happen during the deletion process and also it's worth noting that you can also define leading swipe actions, i.e actions that will be shown when the user swipes to the right by using leadingSwipeActionsConfigurationForRowAt method
You do not need to set the isEditing property. In the previous versions (see below) when you set the table view's isEditing property to true, it enabled the ability for the table view to display the delete button when swiped on a cell. But using the UIContextualAction and UISwipeActionsConfiguration classes, you have more flexibility and more control over the swipe actions and their behavior.
Pre iOS 13 Version[Bearbeiten]
You can implement a delete gesture for a table view in iOS using the UITableViewDelegate protocol and the editActionsForRowAt method.
First, you will need to set your table view's delegate to your view controller and conform to the UITableViewDelegate protocol:
class MyViewController: UIViewController, UITableViewDelegate {
...
}
Then, in the implementation of your view controller, you can implement the editActionsForRowAt method to return an array of UITableViewRowAction objects that will be displayed when the user swipes on a table view cell. Here is an example that shows a "Delete" action that will delete the selected row when tapped:
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let delete = UITableViewRowAction(style: .destructive, title: "Delete") { (action, indexPath) in
// Delete the row from the data source
self.songs.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
}
return [delete]
}
You can also customize the title, background color and other properties of the UITableViewRowAction The closure passed to the UITableViewRowAction constructor will be called when the user taps on the delete action. In this example it removes the data from the data source and call deleteRows to remove the corresponding row from the table view.
Finally, you also need to set the table view's isEditing property to true. It can be done in the viewDidLoad of the view controller:
override func viewDidLoad() {
super.viewDidLoad()
tableView.isEditing = true
}
That's it, now when you swipe on a cell in your table view, the "Delete" action will be displayed, and when tapped, the corresponding row will be deleted from the table view. It is important to note that this is just an example and your implementation may vary depending on your specific use case and the data model you are using.
Beispiel Songlist[Bearbeiten]
Todo Erklärungen
//MARK: - UITableViewDataSource Protocol
extension MetronomeViewController: UITableViewDataSource{
/**
Implement UITableViewDataSource Protocol which is responsible for telling tableview how many cells needed and how to fill them
*/
// Setup Number of rows
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return setlistManager.currentSetlist.songs.count
}
// Setup cells
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "currentSetlistCell", for: indexPath)
let strSongNumber = String(format:"%d",(indexPath.row + 1))
cell.textLabel?.text = "\(strSongNumber) \(setlistManager.currentSetlist.songs[indexPath.row].title)"
let strFrequency = String(format:"%.1f bpm",setlistManager.currentSetlist.songs[indexPath.row].frequency)
cell.detailTextLabel?.text = strFrequency
return cell
}
}
//MARK: - UITableViewDelegate Extension
extension MetronomeViewController: UITableViewDelegate{
/**
Implement UITableViewDelegate
Methods for managing selections, configuring section headers and footers, deleting and reordering cells, and performing other actions in a table view.
*/
// SELECT CELL
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let song = self.setlistManager.currentSetlist.songs[indexPath.row]
print("selected row: \(indexPath.row) Title: \(song.title) \(song.frequency)")
metronome.stop()
setFrequency(song: song)
// metronome.start() // Todo make setting startOnListTapped
}
// SWIPE ACTION SETUP
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let delete = UIContextualAction(style: .destructive, title: "Delete") { (action, view, completion) in
// Delete the row from the data source
self.setlistManager.currentSetlist.songs.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
self.currentTableView.reloadData()
self.setlistManager.persistSetlist(setlist: self.setlistManager.currentSetlist)
completion(true)
}
return UISwipeActionsConfiguration(actions: [delete])
}
// Manage REORDERING of the tableView items
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
let movedSong = setlistManager.currentSetlist.songs[sourceIndexPath.row]
setlistManager.currentSetlist.songs.remove(at: sourceIndexPath.row)
setlistManager.currentSetlist.songs.insert(movedSong, at: destinationIndexPath.row)
}
}
UITableViewController[Bearbeiten]
Eine UITableViewController ist eine Unterklasse von UIViewController, die speziell für die Verwaltung einer Tabelle entwickelt wurde. Es bietet eine bequeme Möglichkeit, eine Tabelle in einem View-Controller einzurichten, sowie eine Reihe von Methoden und Eigenschaften, die es einfacher machen, die Tabelle und ihre Daten zu verwalten.
Zum Beispiel implementiert die Klasse UITableViewController die Protokolle UITableViewDelegate und UITableViewDataSource standardmäßig, so dass Sie leicht die erforderlichen Daten und das Verhalten für die Tabelle bereitstellen können, wie die Anzahl der Zeilen, der Inhalt der Zellen und das Verhalten, wenn eine Zeile ausgewählt wird.
Den Editiermodus für die Tabelle kann man allein durch das Erstellen eines Editbuttons in der NavigationBar erreichen.
self.navigationItem.rightBarButtonItem = self.editButtonItem
Der TableViewController checkt das automatisch und ruft die entsprechende Delegatfunktion auf ohne dass man noch Actions für den Button erstellen muss.
Außerdem stellt XCode gleich eine Reihe von üblicherweise genutzten Codebeispielen bereit.
Beispiel mit UITableViewController[Bearbeiten]
TODO
Weitere Table View Snippets[Bearbeiten]
Multiple Loading verhindern[Bearbeiten]
Wenn der View das erste mal geladen wird werden oft mehrere Aufrufe getätigt. Damit soll sichergestellt werden, dass der View immer die Korrekte Zahl an Elementen enthält. Das ist wohl auch kein Performance Problem. Jedoch wenn du sicherstellen möchtest, dass der View nur einmal geladen wird, kannst du das so lösen:
var dataLoaded = false
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if !dataLoaded {
dataLoaded = true
tableView.reloadData()
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if dataLoaded {
// Return the actual number of rows
} else {
return 0
}
}
In this example, the dataLoaded flag is initially set to false. When the viewDidAppear method is called, the flag is checked. If the flag is false, it means that the data has not yet been loaded, so the dataLoaded flag is set to true and the tableView.reloadData() method is called. This will trigger the func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int method to be called once, with the actual number of rows.
With this approach, the func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int method will only be called once when the UITableView first appears on screen, instead of being called multiple times.