Search code examples
swiftuitableviewuislider

Swift: How to get the value of a slider in a custom cell in a dynamic UITableView?


I have a problem with the following scenario:

I have an UITableView with dynamic cells. Among others, I use a custom UITableViewCell with a UISlider. How can I get the values of the sliders?

I created the following example: (The project file can be downloaded here: Link)

SliderClass.swift

import UIKit

class SliderClass: NSObject {
    var title: String
    var subtitle: String
    var sliderMinimum: Float
    var sliderMaximum: Float

    init(title: String, subtitle: String, sliderMinimum: Float, sliderMaximum: Float) {
        self.title = title
        self.subtitle = subtitle
        self.sliderMinimum = sliderMinimum
        self.sliderMaximum = sliderMaximum

    }
}

SliderTableViewCell.swift

import UIKit

class SliderTableViewCell: UITableViewCell {

    @IBOutlet weak var cellTextLabel: UILabel!
    @IBOutlet weak var cellDetailTextLabel: UILabel!
    @IBOutlet weak var cellSlider: UISlider!

    override func awakeFromNib() {
        super.awakeFromNib()
    }

    override func setSelected(selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
    }
}

TableViewController.swift

import UIKit

class TableViewController: UITableViewController {

    var slider: [SliderClass] = []

    override func viewDidLoad() {
        super.viewDidLoad()
        title = "Slider"

        let slider1 = SliderClass(title: "Title1", subtitle: "Subtitle1", sliderMinimum: 0, sliderMaximum: 100)
        let slider2 = SliderClass(title: "Title2", subtitle: "Subtitle2", sliderMinimum: 0, sliderMaximum: 200)

        slider = [slider1, slider2]
    }

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return slider.count
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("sliderCell", forIndexPath: indexPath) as! SliderTableViewCell

        let slider: SliderClass
        slider = self.slider[indexPath.row]

        cell.cellTextLabel.text = slider.title
        cell.cellDetailTextLabel?.text = slider.subtitle
        cell.cellSlider.minimumValue = slider.sliderMinimum
        cell.cellSlider.maximumValue = slider.sliderMaximum

        return cell
    }

    func sliderValueChange() {
     // I need help here:
     // Which slider changed to which value?

     // var slider = ...
     // var sliderValue = ...
     // NSLog("Value of slider:%@ changed to:%i", slider, sliderValue)
    }
}

Here is a screenshot of the UITableView created with the code above. Screenshot


Solution

  • Try adding this to your cellForRowAtIndexPath function:

    cell.cellSlider.tag = indexPath.row
    cell.cellSlider.addTarget(self, action: "sliderValueChange:", forControlEvents: .ValueChanged)
    

    And then outside of the table function add something like:

    func sliderValueChange(sender: UISlider) {
        // Get the sliders value
        var currentValue = Int(sender.value)
        var sliderRow = sender.tag
    
        // Do whatever you want with the value :)
        // And now the row of the slider!
    }
    

    Make sure the action name for cellSlider's target is the same as the function's name! And since it takes one argument, don't forget the colon at the end.

    So just to summarise, here's a really simply example of the above in action:

    import UIKit
    
    class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    
        func numberOfSectionsInTableView(tableView: UITableView) -> Int {
            return 1
        }
    
        func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return 2    // 2 rows in the cell, for demo purposes
        }
    
        func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! TableViewCell
    
            cell.slider.tag = indexPath.row
            cell.slider.addTarget(self, action: "sliderChange:", forControlEvents: .ValueChanged)
    
            return UITableViewCell()
        }
    
        func sliderChange(sender: UISlider) {
            let currentValue = sender.value    // get slider's value
            let row = sender.tag               // get slider's row in table
    
            print("Slider in row \(row) has a value of \(currentValue)")
            // example output - Slider in row 1 has a value of 0.601399
        }
    
    }
    
    class TableViewCell: UITableViewCell {
    
        @IBOutlet var slider: UISlider!
    
    }