I have a UISwitch component in my CreateSomethingViewController. This component is on a xib file. In my SomethingTableViewCell, I have a label called existsLabel. When I create my something, I can select as Existent (if I turn my UISwitch component on) or not (if Switch is off).
If my existsLabel was in my CreateSomethingViewController, I would do something like this:
@IBAction func changeSomethingExistence(_ sender: UISwitch) {
let isExistent = sender.isOn
existsLabel.isHidden = false
if isExistent {
existsLabel.isHidden = true
}
}
How can I do this (show my existsLabel on my SomethingTableViewCell) when my UISwitch isOn? Using swift.
CodePudding user response:
I think, you already knew the index or position of your updated objects. So We can reload only visible cells row after updating on particular objects to the index position of your cell.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? YourTableViewCell
cell?.yourSwitch.isOn = yourList[indexPath.row].switchIsOne
cell?.yourSwitch.tag = indexPath.row
cell?.yourSwitch.addTarget(self, action: #selector(changeSomethingExistence), for:UIControl.Event.valueChanged)
cell?.existsLabel.isHidden = !yourList[indexPath.row].switchIsOne
return cell!
}
Here is your Switch update actions:
@objc func changeSomethingExistence(mySwitch: UISwitch) {
yourList[mySwitch.tag].switchIsOne = mySwitch.isOn
self.updateCell(indexRow: mySwitch.tag)
}
Call this function from anywhere with your selected index and update the same.
func updateCell(indexRow: Int) {
let updatedIndexPath = IndexPath(row: indexRow, section: 0)
self.tableView.reloadRows(at: [updatedIndexPath], with: .automatic)
}
CodePudding user response:
Here's an example. Instead of hiding and showing a view, I set the background color of the cells. The basic ideas are the same.
Essentially you need an object to store the value that the switch controls. In this case I store that data in the same object that I used as the UITableViewDataSource
. When the switch is flipped, you tell that object to change the value. It will broadcast the change to all the cells that are currently listening for the change.
There are lots of ways you could observe the change. You could use the Target Action pattern, you could broadcast the change using the NSNotificationCenter
. You could use key/value observers, etc. In this case the object holding the value has an @Published
property and the cells subscribe to that property.
One critical thing to do is implement prepareForReuse
. When a cell is scrolled off the view, it is put in a reuse queue. Rather than create a new cell the system might hand you one out of the reuse buffer. If it does that, you want to be sure the cell is listening to the right source of information for things that change dynamically.
You should be able to copy/paste this code into an iOS Playground:
//: A UIKit based Playground for presenting user interface
import UIKit
import PlaygroundSupport
import Combine
class CustomCell : UITableViewCell {
var cancelBackgrounds : AnyCancellable?
override func prepareForReuse() {
cancelBackgrounds?.cancel()
cancelBackgrounds = nil
// ALWAYS call super... this can cause hard to identify bugs
super.prepareForReuse()
}
func observeFancyBackground(dataSource: TableData) {
// Set up to observe when the fanch Background value changes
// If this cell was listening to someone else, stop listening to them
// and start listeneing to the new guy.
// This may not be necessary - its a safety check.
cancelBackgrounds?.cancel()
cancelBackgrounds = nil
// Start listening to the new information source
cancelBackgrounds = dataSource.$showFancyBackgrounds.sink(receiveValue: {
isOn in
self.setBackground(isOn)
})
}
private func setBackground(_ showFancy: Bool) {
if showFancy {
self.backgroundConfiguration?.backgroundColor = UIColor.yellow
} else {
self.backgroundConfiguration?.backgroundColor = UIColor.white
}
}
}
class TableData : NSObject, UITableViewDataSource {
let tableData = (1...1000).map { "\(Int($0))" }
@Published var showFancyBackgrounds = false
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.textLabel?.text = tableData[indexPath.row]
cell.observeFancyBackground(dataSource: self)
return cell
}
}
class MyViewController : UIViewController {
let switchView = UISwitch()
let tableView = UITableView(frame: CGRect(x: 0, y: 200, width: 320, height: 100), style: .plain)
let tableData = TableData()
// This is the action called when the switch is toggled.
@objc func switchFlipped(sender: UISwitch) {
tableData.showFancyBackgrounds = sender.isOn
}
// This just sets things up to be pretty.
override func loadView() {
let view = UIView()
switchView.translatesAutoresizingMaskIntoConstraints = false
switchView.addTarget(self, action: #selector(switchFlipped), for: .valueChanged)
tableView.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .white
tableView.register(CustomCell.self, forCellReuseIdentifier: "CustomCell")
tableView.dataSource = tableData
view.addSubview(switchView)
view.addSubview(tableView)
self.view = view
let viewIDs = ["switch" : switchView,
"table" : tableView]
let constraints = [
NSLayoutConstraint.constraints(
withVisualFormat: "V:|-8-[switch]-[table]-|",
options: [],
metrics: nil,
views: viewIDs),
NSLayoutConstraint.constraints(
withVisualFormat: "|-[switch]-|",
options: [],
metrics: nil,
views: viewIDs),
NSLayoutConstraint.constraints(
withVisualFormat: "|-0-[table]-0-|",
options: [],
metrics: nil,
views: viewIDs),
].flatMap { $0 }
view.addConstraints(constraints)
}
}
let myViewController = MyViewController()
PlaygroundPage.current.liveView = myViewController
CodePudding user response:
You can do this by reloading the tableView
when the switch
is changed.
var isExistent: Bool
@IBAction func changeSomethingExistence(_ sender: UISwitch) {
isExistent = sender.isOn
//reload the table
tableView.reloadData()
}
In your UITableViewDataSource
you can check which cell.label
need to be hidden or not and accordingly hide/show the label of those cells
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//decide which cells needs to be hide/show based on the indexPath and switchValue
//then you can call cell.existsLabel.isHidden = isExistent
}