UISwitch in accessory view of a tableviewcell, passing a parameter with the selector to have selector function see the indexpath.row?
let lightSwitch = UISwitch(frame: CGRectZero) as UISwitch
lightSwitch.on = false
lightSwitch.addTarget(self, action: #selector(switchTriggered), forControlEvents: .ValueChanged)
lightSwitch.tag = indexpath.row
cell.accessoryView = lightSwitch
Let save your boolean value in Array
func switchTriggered(sender: UISwitch) {
sender.on ? array[sender.tag]=1 : array[sender.tag]=0
}
}
How can I capture events from a Switch in a UITableViewCell?
There are various solutions to this.
One is to set up a custom subclass of UITableView where the switch is linked to the cell. Then set up the cell to have a delegate property, and make the cell send a message to it's delegate when the user taps the switch.
Another option is to set the target/action on your cell's switches to invoke a method in your view controller in the cellForRow(at:)
method. However you need to leave the action blank in interface builder and use the control's allTargets property to check to see if the switch (or button or other UIControl) already has a target/action. (If you blindly add a target/action each time in cellForRow(at:)
you'll wind up with multiple target/actions, one for each time a cell gets recycled.
A third option is to set up a custom subclass of your control (UISwitch in this case) that takes has a closure property that it invokes when it's action is triggered. You'd make such a control set itself as the target and make the action invoke the closure if is was not nil. Your cellForRow(at:)
method could then install a custom closure that did whatever you want when the control is triggered.
Note that regardless of which approach you use you need a way to figure out which indexPath represents the switch who's value changed.
In my answer to this SO question I outline a general-purpose way to figure out which cell contains a view. It would work to figure out which cell contains the switch the user tapped in your case.
I outline a simple extension to UITableView
that lets you figure out which IndexPath
(if any) contains a particular UIView
.
The gist of it is that you can create a simple extension to UITableView
that lets you figure out the IndexPath
of the cell that contains any UIView
The code looks like this:
public extension UITableView {
/**
This method returns the indexPath of the cell that contains the specified view
- Parameter view: The view to find.
- Returns: The indexPath of the cell containing the view, or nil if it can't be found
*/
func indexPathForView(_ view: UIView) -> IndexPath? {
let origin = view.bounds.origin
let viewOrigin = self.convert(origin, from: view)
let indexPath = self.indexPathForRow(at: viewOrigin)
return indexPath
}
}
What is the action for custom accessory view button - swift
Why do you need to call willSelectRowAtIndexPath
? You have done everything right and to solve your unrecognized selector
error just make a function that will be called when you tap on the cell.accessoryView
. In your case:
func accessoryButtonTapped(){
print("Tapped")
}
Update
If you want to get the indexPath you could just
Add a tag to your cellAudioButton
:
cellAudioButton.tag = indexPath.row
In your addTarget
add a :
to pass a parameter
And in your function
func accessoryButtonTapped(sender : AnyObject){
print(sender.tag)
print("Tapped")
}
So the whole code:
let cellAudioButton = UIButton(type: .Custom)
cellAudioButton.frame = CGRect(x: 0, y: 0, width: 20, height: 20)
cellAudioButton.addTarget(self, action: "accessoryButtonTapped:", forControlEvents: .TouchUpInside)
cellAudioButton.setImage(UIImage(named: "blueSpeaker.png"), forState: .Normal)
cellAudioButton.contentMode = .ScaleAspectFit
cellAudioButton.tag = indexPath.row
cell.accessoryView = cellAudioButton as UIView
func accessoryButtonTapped(sender : AnyObject){
print(sender.tag)
print("Tapped")
}
How can I get text from row in the UITableView?
You can add a delegate to your YourCellClass
. When the switchView is toggled, call a delegate method something like this
class YourCellClass: UITableViewCell {
weak var delegate:YourCellClassDelegate?
var switchView: UISwitchView
init() {
...other stuff...
switchView.addTarget(self, action: #selector(self.switchChanged(_:)), for: .valueChanged)
...other stuff...
}
func switchChanged(_ sender : UISwitch!){
if let delegate = delegate {
delegate.cellDidToggleSwitch(self, isOn: sender.isOn)
}
}
}
protocol YourCellClassDelegate {
func cellDidToggleSwitch(_ cell: YourCellClass, isOn: Bool)
}
Then in the ViewController with the TableView
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 { // specific row showing switch
var cell = tableView.dequeueReusableCell(withIdentifier: "yourcellIdentifire", for: indexPath) as! YourCellClass
cell.textLabel?.text = "bad morning"
cell.delegate = self
return cell
}
return UITableViewCell()
}
func cellDidToggleSwitch(_ cell: YourCellClass, isOn: Bool) {
//here's your cell
}
UITableview: How to Disable Selection for Some Rows but Not Others
You just have to put this code into cellForRowAtIndexPath
To disable the cell's selection property: (while tapping the cell)
cell.selectionStyle = UITableViewCellSelectionStyleNone;
To enable being able to select (tap) the cell: (tapping the cell)
// Default style
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
// Gray style
cell.selectionStyle = UITableViewCellSelectionStyleGray;
Note that a cell with selectionStyle = UITableViewCellSelectionStyleNone;
will still cause the UI to call didSelectRowAtIndexPath
when touched by the user. To avoid this, do as suggested below and set.
cell.userInteractionEnabled = NO;
instead. Also note you may want to set cell.textLabel.enabled = NO;
to gray out the item.
Add a Selector from a UITableViewCell class to the UITableViewController class
In alternative to the accepted solution:
Depending on case you can try use delegate instead action/target
//Declare a delegate for the cell
protocol PlayerSelectionCellDelegate : class {
func playerSelectionCell(_ cell:PlayerSelectionCell, didChangeValue:Double)
func playerSelectionCell(_ cell:PlayerSelectionCell, expansionSelectionValueDidChange:Bool)
}
class PlayerSelectionCell: UITableViewCell {
weak var delegate : PlayerSelectionCellDelegate? //Set a weak var to allocate the delegate
@objc func stepperValueDidChange(_ sender: UIStepper) {
delegate?.playerSelectionCell(self, didChangeValue: sender.value)
}
@objc func expansionSelectionValueDidChange(_ sender: UISwitch) {
delegate?.playerSelectionCell(self, expansionSelectionValueDidChange: sender.isOn)
}
override func awakeFromNib() {
let stepper = UIStepper()
stepper.addTarget(self, action: #selector(stepperValueDidChange), for: .valueChanged)
//This line should be reference to the UISwitch Action
selectionSwitch.addTarget(self, action: #selector(expansionSelectionValueDidChange), for: .valueChanged)
self.accessoryView = stepper
}
}
In the ViewController you change the code to get in conformity to the delegate and set the ViewController as delegated to cell
class SetupViewController: UITableViewController {
@IBOutlet var setupTableView: UITableView!
override func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
switch section {
case 0:
return "Expansions"
case 1:
return "Players"
default:
return nil
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section {
case 0:
return Expansions.allCases.count
case 1:
return 3
default:
return 0
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "Expansion Selection", for: indexPath) as? ExpansionCell ?? ExpansionCell()
cell.textLabel?.text = Expansions.allCases[indexPath.row].rawValue
return cell
} else if indexPath.section == 1 && indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "Player Selection", for: indexPath) as? PlayerSelectionCell ?? PlayerSelectionCell()
cell.delegate = self //Set the ViewController to be delegated by cell
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "Player Detail", for: indexPath) as? PlayerCell ?? PlayerCell()
cell.textLabel?.text = "Player \(indexPath.row)"
return cell
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
//Remove the actions and implements the delegate methods
func playerSelectionCell(_ cell: PlayerSelectionCell, didChangeValue players: Double) {
print("Value Players: \(players)")
}
func playerSelectionCell(_ cell: PlayerSelectionCell, expansionSelectionValueDidChange selected: Bool) {
print("Value Selected: \(selected)")
}
}
Related Topics
Array of Multiple Url's Nsfilemanager Swift
Itunes Connect: Can't See Build
How to Remove All References for Outlet
Nsinteralinconsistencyexception - Uikeyboardlayoutalignmentview
The 'Pods' Target Has Transitive Dependencies That Include Static Binaries' When Installing Gcm
Usage of String.Range in Swift 3.0
Cannot Create PDF Document with 400+ Pages on iOS
Xcode Duplicate Symbols for Architecture Error After Updating Cocoa Pods
Detect When a Unicode Character Cannot Be Displayed Correctly
Remote Image Size Without Downloading
Perform Action by Clicking on Some Word in Uitextview or Uilabel
How to Query Nearest Users in Firebase with Swift
How to Get the Modulus or Exponent from a Seckeyref Object in Swift
Cameranode Rotate as iOS Device Moving
Setting Up a Plist to Store Application Data (Not Settings) for an iPhone Game