Home > Enterprise >  How to show/hide label in a different view when UISwitch isOn in swift?
How to show/hide label in a different view when UISwitch isOn in swift?

Time:09-23

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
}
  • Related