I am relatively new to UIKit. Currently, I am trying to create a UISwitch
that will show up on a specific UITableView
cell. However, I can't seem to figure out how to do this. Instead, I am getting a UISwitch
on every single cell in the UITableView
.
My code is below:
import UIKit
class SettingsVC: UIViewController {
var tableView = UITableView(frame: .zero, style: .insetGrouped)
let cells = ["Change Accent Color", "Change Currency Symbol", "Vibrations"]
let cellReuseIdentifier = "cell"
override func viewDidLoad() {
super.viewDidLoad()
createTableView()
setTableViewDelegates()
}
func createTableView() {
view.addSubview(tableView)
tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellReuseIdentifier)
tableView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.leftAnchor.constraint(equalTo: view.leftAnchor),
tableView.rightAnchor.constraint(equalTo: view.rightAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
}
func setTableViewDelegates() {
tableView.delegate = self
tableView.dataSource = self
}
}
extension SettingsVC: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cells.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell") else {
return UITableViewCell()
}
cell.textLabel?.text = cells[indexPath.row]
let switchView = UISwitch(frame: .zero)
switchView.setOn(false, animated: true)
cell.accessoryView = switchView
return cell
}
}
This is how my UITableView looks currently in the simulator.
This is how I would like the UITableView to look.
How would I be able to achieve the look I'm going for? Any help would be greatly appreciated.
CodePudding user response:
The method tableView(_:cellForRowAt:)
is used to create all cells for a table, so the code inside this method is called for each cell. You need to figure out a condition that distinguishes the cell with a UISwitch
and run the corresponding piece conditionally. Conceptually, something like this:
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell") else {
return UITableViewCell()
}
cell.textLabel?.text = cells[indexPath.row]
if isSwitchNeeded { // Here.
let switchView = UISwitch(frame: .zero)
switchView.setOn(false, animated: true)
}
cell.accessoryView = switchView
return cell
}
There are some architectural options that might allow you do that. One of them is to rely on the index path. For instance, this should work in your raw example:
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell") else {
return UITableViewCell()
}
cell.textLabel?.text = cells[indexPath.row]
if indexPath.row == 2 {
let switchView = UISwitch(frame: .zero)
switchView.setOn(false, animated: true)
}
cell.accessoryView = switchView
return cell
}
And a million other ways.
CodePudding user response:
First of all most likely you want to save the value of the switch, so create a property on the top level of the view controller
var enableVibrations = false
Second of all cells are reused. Even if there are only three cells it's good practice to set all UI elements to a defined state, that means to set the accessory view to nil
if there is no switch.
And there is a dequeueReusableCell
API which returns a non-optional cell.
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let title = cells[indexPath.row]
cell.textLabel?.text = title
if title == "Vibrations" {
let switchView = UISwitch(frame: .zero)
switchView.setOn(enableVibrations, animated: true)
switchView.addTarget(self, action: #selector(toggleVibrations), for: .valueChanged)
cell.accessoryView = switchView
} else {
cell.accessoryView = nil
}
return cell
}
And add the action method
@objc func toggleVibrations(_ sender : UISwitch) {
self.enableVibrations = sender.isOn
}