How can I embed a UISwitch programmatically in a tableView cell in Swift?
I'm doing it like that
let shareLocationSwitch = UISwitch()
cell.accessoryView = shareLocationSwitch
Here is way you can embed a UISwitch on a UITableView cell.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "yourcellIdentifire", for: indexPath) as! YourCellClass
//here is programatically switch make to the table view
let switchView = UISwitch(frame: .zero)
switchView.setOn(false, animated: true)
switchView.tag = indexPath.row // for detect which row switch Changed
switchView.addTarget(self, action: #selector(self.switchChanged(_:)), for: .valueChanged)
cell.accessoryView = switchView
return cell
}
here is switch call beck method
func switchChanged(_ sender : UISwitch!){
print("table row switch Changed \(sender.tag)")
print("The switch is \(sender.isOn ? "ON" : "OFF")")
}
#LeoDabus Great! explanation.
Note: if your tableview may have more than one section then You should create a CustomCell subclassing UITableViewCell and configure your accessoryView inside UITableViewCell awakeFromNib method instead of table view cellForRowAt method. When dequeuing the reusable cell cast it to your CustomCell Here is sample from #LeoDabus
if you update the array with 3 elements and refreshing the table using self.tableView.reloadData() (for example after 2 second) you can see that with Xcode13 the switch values will be swapped and the example doesn't work. I have similar issue with my App when Xcode has been released to 13. try this: https://drive.google.com/file/d/1_1HuI_JFIYusNmsdyekGBWXsGznneiQ7/view?usp=sharing
Related
I am very confused on the reuse of the cells.
I have a table, each cell is a cell with a switch on it. If I toggle a switch I set the background color of that cell to a different color. However every time I scroll these changes don't persist.
I am subclassing UITalbeViewCell to create my own custom cell. Each cell has a different identifier. However when I scroll through the table, whatever changes I made to the cell still doesn't save. I've read similar questions but none of them worked.. Some suggested subclass which I did, some suggested use different identifier which I also did...
Here is the code of my tableview.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let key = Array(dataSource[indexPath.section].keys)[indexPath.row]
let cell = CellWithSwitch.init(style: .subtitle, reuseIdentifier: key)
cell.awakeFromNib()
let val = Array(dataSource[indexPath.section].values)[indexPath.row]
cell.switchView?.addTarget(self, action: #selector(self.switchChanged(_:)), for: .valueChanged)
if let index = key.firstIndex(of: "."){
cell.textLabel?.text = String(key.suffix(from: key.index(index, offsetBy: 1)))
}else{
cell.textLabel?.text = key;
}
cell.switchView?.setOn(val, animated: true)
return cell
}
You can change array value in switchChange action
lets i take array for switch as below:
var arrSwitch = [false,false,false,false,false,false,false,false,false,false]
Below is my cellForRowAt Method
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "customCell") as! customCell
cell. switchView.setOn(self.arrSwitch[indexPath.row], animated: false)
cell. switchView.tag = indexPath.row
cell. switchView.addTarget(self, action: #selector(self.onSwitchTap(_:)), for: .valueChanged)
return cell
}
Here is my onSwitchTap Action
#IBAction func onSwitchTap(_ sender: UISwitch) {
self.arrSwitch[sender.tag] = !self.arrSwitch[sender.tag]
}
Now on scroll it will persist last changes you have done.
I have problem which trying to solve for hours.
I have tableView with multiple cells.
I don't use StoryBoard.
My problem is this:
Number of cells in tableView depends on size of array. When app start, tableView and its cells loads perfectly. Even when i insert into ViewDidLoad this:
arrayOfCategory.append(Category(nameOfCategory: "Example", ColorOfCategory: .white))
tableView.reloadData()
it works. But when i try insert voids into button's target
#objc func handle(sender: UIButton) {
arrayOfCategory.append(Category(nameOfCategory: "Sdsdd", ColorOfCategory: .white))
tableView.reloadData()
}
my app will crash with error:
TaskList[59513:1886772] Could not cast value of type 'TaskList.SwitchCell' (0x1073bd808) to 'TaskList.CategoryShowCell' (0x1073bd500).
Here is cellForRow:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch indexPath.section {
case 0:
tableView.register(CategoryShowCell.self, forCellReuseIdentifier: categoryShowID)
let cell = tableView.dequeueReusableCell(withIdentifier: categoryShowID, for: indexPath) as! CategoryShowCell
cell.setCell(category: Category(nameOfCategory: "sdsd", ColorOfCategory: .white))
return cell
case 1:
tableView.register(SwitchCell.self, forCellReuseIdentifier: swichCellID)
let cell = tableView.dequeueReusableCell(withIdentifier: swichCellID, for: indexPath) as! SwitchCell
return cell
default:
tableView.register(SwitchCell.self, forCellReuseIdentifier: swichCellID)
let cell = tableView.dequeueReusableCell(withIdentifier: swichCellID, for: indexPath) as! SwitchCell
return cell
}
}
Does anyone know where is problem?
Xcode point into this line:
let cell = tableView.dequeueReusableCell(withIdentifier: categoryShowID, for: indexPath) as! CategoryShowCell
in cellForRow bude one line above i register right cell.
Your problem is in different types of registered cell and type you're trying to force cast it to. Like Xcode says you - TaskList.SwitchCell to TaskList.CategoryShowCell. Force casting happens at as! CategoryShowCell this place.
I suspect, that you are reregistering SwitchCell.self for categoryShowID. It can happen if your categoryShowID is equal to swichCellID.
Check this out and keep in mind, that registering one cell multiple times in cellForRow is a bad idea
I have a EDIT2 UItableView, in Swift, with the normal labels and relevant Information. I have added a Image to the cell and all is working except when I click on the image I would like to open another ViewController with that particular cells relevant information. I have used:
let popup: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.popupalrmcontrnt))
cell.alrmwarning.addGestureRecognizer(popup);
as the means for calling the pushViewController function, But the Viewcontoller requires a parameter AlarmID to be set Beforehand. Said Viewcontroller needs AlarmID to fetch its relevant information.
Edit1 The parameter is dependant on the selected cell.
Create a closure variable in cell:
class SomeCell: UITableViewCell {
var imageClicked: (() -> Void)?
}
then in action of your tap gesture self.popupalrmcontrnt
add this line
func popupalrmcontrnt() {
self.imageClicked?()
}
then in your cellForRow, you can access this as:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)
(cell as? SomeCell)?.imageClicked = {
//Navigate to your view controller here
}
return cell
}
Hope it helps!!
Better use UIButton. you can set image to the button as background image. Also you can pass relevant info as an object to the new ViewController.
Basically, I have a custom table view cell that lists potential employees. This cell includes a few labels and a button. What I want is for the button to remove the cell, but all I can find is this :
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == UITableViewCellEditingStyle.Delete {
numbers.removeAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
}
}
Which only allows you to delete the cell if you swipe then choose "delete"
I'm thinking I should create a function in my tableViewController.swift file that will delete the cell at a given row, and in my custom cell class create an IBAction that will call said function.
What would the function to delete a cell at given row look like? But in this case, does the cell also know which row it is in or is that a job for the tableViewController?
In your cellForRowAtIndexPath set the cell.button.tag = indexPath.row
Add a target to the button: cell.button addTarget:...
In the button method, remove the item in your dataArray at index button.tag. Then refresh the tableView self.tableView reloadData
You can use the tag property of UIButton to store the index of the cell that you want to delete and use that tag property in the handler to locate the correct cell. In my sample code, I just made an assumption
that you only have one section that is why it is set to zero.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
...
...
cell.button.tag = indexPath.row
let tapGesture = UITapGestureRecognizer(target: self, action: Selector("handleDeleteTap:"))
cell.button.addGestureRecognizer(tapGesture)
}
func handleDeleteTap(sender: UITapGestureRecognizer)
{
if let button = sender.view as? UIButton
{
let indexPath = NSIndexPath(forRow: button.tag, inSection: 0)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
}
}
1) You have to define an action for your button in cellForRowAtIndexPath:
...
myButton.addTarget(self, action: "buttonTappedDelete:", forControlEvents: .TouchUpInside)
...
2) You have to implement the selector:
2.1) Get the cell in which the button is located.
2.2) Get the index path of the cell.
2.3) Remove the cell from the table view and update your data.
func buttonTappedDelete(sender: UIButton) {
let cell = sender.superview!.superview as! UITableViewCell
let indexPath = self.tableView.indexPathForCell(cell)!
self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
// update your data model, call `self.tableView.reloadData()`
}
I have a UITableView with custom cells. In function tableView(cellForRowAtIndexPath:) I populate cells from an object's array in this way
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "Cell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as CustomTableViewCell
cell.txtOne.text = array[indexPath.row].firstText
cell.txtTwo.text = array[indexPath.row].secondText
return cell
}
Now I want to add to the UITextField a UILongPressGestureRecognizer that changes the property .enabled of each UITextField (in this way I can make the UITextField editable).
I have no idea how to do.
I tried adding the UILongPressGestureRecognizer into the Main.Storyboard but I can't catch the action on the UITextField, I can only on the cell.
Can anyone help me?
I use Xcode Version 6.1.1