How to switch custom xib cell when didSelect call? - swift

I have a tableView with 2 custom xib cells. I want to switch the custom cell when user tapped it also adjust the cell height. How do I achieve it? I tried to use container view but then the height would be the same. I want to know if it is possible to do it with two xib for tableView cell? Thank you.
var isContactView: Bool = true
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
tableView.register(UINib(nibName: "ContactTableViewCell", bundle: nil), forCellReuseIdentifier: "contactCell")
tableView.register(UINib(nibName: "DetailTableViewCell", bundle: nil), forCellReuseIdentifier: "detailCell")
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
//if ContactTableViewCell return 40
//if DetailTableViewCell return 150
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//by default the cell view is ContactTableViewCell.
//When user tapped the cell it will change to DetailTableViewCell.
if isContactView {
let cell = tableView.dequeueReusableCell(withIdentifier: "contactCell", for: indexPath) as! ContactTableViewCell
//do something...
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "detailCell", for: indexPath) as! DetailTableViewCell
//do something...
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//not sure how to change the xib in here.
//if cell view is ContactTableViewCell
cell view = tableView.dequeueReusableCell(withIdentifier: "detailCell", for: indexPath) as! DetailTableViewCell
isContactView = false
tableView.reloadData()
//else
cell view = tableView.dequeueReusableCell(withIdentifier: "contactCell", for: indexPath) as! ContactTableViewCell
isContactView = true
tableView.reloadData()
}

There are 2 cases:
If there's just single cell to be viewed, then just put the following code in didSelect:
isContactView = !isContactView
tableView.reloadData()
If there are multiple cells in which the condition is to be applied. Please put a key in your data model.
For example:
testArr is the array of objects that you are displaying in tableview. Then keep a key, say isContactView in this model. And put the login based upon this key.
Like in case of cellForRow:
if testArr[indexpath.row].isContactView {
let cell = tableView.dequeueReusableCell(withIdentifier: "contactCell", for: indexPath) as! ContactTableViewCell
//do something...
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "detailCell", for: indexPath) as! DetailTableViewCell
//do something...
}
And in didselect:
isContactView = !testArr[indexPath.row].isContactView

Related

How to disable/enable notifications in tablewiew by using UISwitch in Swift

I am working on a location-based reminder app. I show all reminders that user created on a table view. I have also UISwitch on every cell. I want that UISwitch disables/enables reminders individually, not all notifications. I couldn't figure it out.
extension MainViewController: UITableViewDataSource{
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.items?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//let cell = tableView.dequeueReusableCell(withIdentifier: "itemCell", for: indexPath)
let cell = tableView.dequeueReusableCell(withIdentifier: "itemCell", for: indexPath) as! itemTableViewCell
let item = self.items![indexPath.row]
cell.itemTitle?.text = item.itemName
cell.itemSubTitle?.text = item.itemDescription
//switch
let swicthView = UISwitch(frame: .zero)
swicthView.onTintColor = UIColor (named: "DingerBlue")
swicthView.setOn(true, animated: true)
swicthView.tag = indexPath.row
swicthView.addTarget(self, action: #selector(self.SwitchBtn(_:)), for: .valueChanged)
cell.accessoryView = swicthView
let itemToRemove = self.items![indexPath.row]
let notifToRemove: String = itemToRemove.notifID!
return cell
}
#objc func switchDidChanged(_ sender: UISwitch){
print("Switch value is \(sender.isOn)")
if(sender.isOn){
print("on")
UIApplication.shared.registerForRemoteNotifications()
}
else{
print("Off")
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [notifToRemove])
}
}
}
I believe your code is not working because cells are reused and actions on specific cells should be handled from the cell class rather than from ViewController. Move this code into the UITableViewCell code.
let swicthView = UISwitch(frame: .zero)
swicthView.onTintColor = UIColor (named: "DingerBlue")
swicthView.setOn(true, animated: true)
swicthView.tag = switchViewTag!
swicthView.addTarget(self, action: #selector(self.SwitchBtn(_:)), for: .valueChanged)
#objc func switchDidChanged(_ sender: UISwitch){
print("Switch value is \(sender.isOn)")
if(sender.isOn){
print("on")
UIApplication.shared.registerForRemoteNotifications()
}
else{
print("Off")
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [notifToRemove])
}
}
and add a new property in the UITableViewCell
weak var switchViewTag: Int?
Modify your cellForRowAt delegate method to
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//let cell = tableView.dequeueReusableCell(withIdentifier: "itemCell", for: indexPath)
let cell = tableView.dequeueReusableCell(withIdentifier: "itemCell", for: indexPath) as! itemTableViewCell
let item = self.items![indexPath.row]
cell.itemTitle?.text = item.itemName
cell.itemSubTitle?.text = item.itemDescription
cell.switchViewTag = indexPath.row
return cell
}

How to display UITextLabels like (checkmark) on cell when UITableViewCell tapped?

I'm working on a UITableView that acts like checklist. I have managed to display UITextLabel when UITableViewCell tapped and hide UITextLabel like (Checkmark) when UITableViewCell tapped again.
When I close the app it does display UITextLabel before tapped.
Took screenshots of the app:
Now I have some code that makes this work:
// 1
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CategoryCell", for: indexPath)
let category = categories[indexPath.row]
// cell.secondTextLabelType = hide/display
if category.done {
cell.textLabel?.text = category.name
} else {
cell.textLabel?.text = ""
}
return cell
}
// 2
//hide and display the TextField2
func setItemStatus(item:Category) {
let status = item.done ? false : true
item.done = status
}
// 3
//MARK - TableView Delegate Methods
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//categories goes here
let item = categories[indexPath.row]
//cell?.twoItems = hide/display
setItemStatus(item: item)
tableView.reloadData()
saveCategories()
}

How can I stop my UITableView from reusing cells?

I have a UITableView containing about 30 cells. The user is only able to select one. Once a cell is selected it shows a checkmark. But the problem is whenever I scroll down the UITableView it shows cells i never clicked with a checkmark beside them. What is the proper way to fix this?
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return breedNameArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Bcell")
let cell = tableView.dequeueReusableCell(withIdentifier: "Bcell", for: indexPath)
//cell.accessoryType = UITableViewCell.AccessoryType.checkmark
cell.textLabel?.text = breedNameArray[indexPath.item]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath)
tableView.register(UINib(nibName: "BBcell", bundle: nil), forCellReuseIdentifier: "Cell")
//let cell = tableView.dequeueReusableCell(withIdentifier: "Breeds", for: indexPath)
//tableView.deselectRow(at: tableView.indexPathForSelectedRow!, animated: true)
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Bcell")
//let cell = tableView.dequeueReusableCell(withIdentifier: "Breeds", for: indexPath)
tableView.cellForRow(at: indexPath)?.accessoryType = .none
}
The reason you are seeing cells getting checkmarks when scrolling is because the call to tableView.dequeueReusableCell(withIdentifier:"Bcell", for: indexPath) in cellForRowAt reuses already allocated UITableViewCell objects that have the identifier "Bcell". The UITableView does not automatically reset the properties of the reused UITableViewCell objects when reused in this way.
Since you are only allowing one UITableViewCell to be selected at a time, a simple solution would be to add a local variable to keep track of the selected IndexPath, and then use the local variable to set the accessoryType accordingly in cellForRowAt. Here is the code to illustrate what I mean:
// The local variable to keep track of the selected IndexPath
var selectedIndexPath = IndexPath()
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return breedNameArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Bcell")
let cell = tableView.dequeueReusableCell(withIdentifier: "Bcell", for: indexPath)
// Use selectedIndexPath to set the accessoryType as .checkmark or .none
if indexPath == selectedIndexPath {
cell.accessoryType = UITableViewCell.AccessoryType.checkmark
} else {
cell.accessoryType = UITableViewCell.AccessoryType.none
}
cell.textLabel?.text = breedNameArray[indexPath.item]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Set the selectedIndexPath
selectedIndexPath = indexPath
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath)
tableView.register(UINib(nibName: "BBcell", bundle: nil), forCellReuseIdentifier: "Cell")
//let cell = tableView.dequeueReusableCell(withIdentifier: "Breeds", for: indexPath)
//tableView.deselectRow(at: tableView.indexPathForSelectedRow!, animated: true)
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
// Un-Set the selectedIndexPath
selectedIndexPath = IndexPath()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Bcell")
//let cell = tableView.dequeueReusableCell(withIdentifier: "Breeds", for: indexPath)
tableView.cellForRow(at: indexPath)?.accessoryType = .none
}

A sub view in UITableview gets disappear once the row is been clicked.

I'm working on a project in swift 3.0 where I have a UIView inside a UITableViewCell. For some reason once a row is been selected the view gets disappear, and once a a new row is been selected the view of the previous cell shows up and the view of the newly selected one gets disappear.Name of the view that gets disappear is redView(reference of the code bellow). My code and UITableView delegates as follow.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let backgroundView = UIView()
backgroundView.backgroundColor = UIColor.clear
cell.selectedBackgroundView = backgroundView
let data = self.mediaList[indexPath.row] as! NSDictionary
let redView = cell.viewWithTag(TABLE_CELL_TAGS.redView)!
let reducedPriceLabel = cell.viewWithTag(TABLE_CELL_TAGS.reducedpricelable) as! UILabel
Utils.setTableCellLabelText(cell: cell, labelTag: TABLE_CELL_TAGS.title, text: data["title"] ?? "title...")
if let reducedPrice = data["mediaValue"] as? Int{
reducedPriceText = "$\(String(reducedPrice))"
redView.isHidden = false
reducedPriceLabel.isHidden = false
}else{
redView.isHidden = true
reducedPriceLabel.isHidden = true
}
Utils.setTableCellLabelText(cell: cell, labelTag: TABLE_CELL_TAGS.reducedpricelable, text: reducedPriceText)
return cell;
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let mP3ViewController = self.storyboard?.instantiateViewController(withIdentifier:"MP3ViewController") as! MP3ViewController
mP3ViewController.mediaDetails = mediaList[indexPath.row] as? NSDictionary
self.navigationController?.pushViewController(mP3ViewController, animated:true)
}
Go to the storyboard setting of tableViewcell set selection to None. then I think it will work for you.
Try this and let me know.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let mP3ViewController = self.storyboard?.instantiateViewController(withIdentifier:"MP3ViewController") as! MP3ViewController
mP3ViewController.mediaDetails = mediaList[indexPath.row] as? NSDictionary
self.navigationController?.pushViewController(mP3ViewController, animated:true)
}

How to add two custom cell into tableview in storyboard in Swift?

I have a tableView with two different custom cell. One cell have a switch and other a image, I have Two separated custom class for the cells, identifiers.. but I can't see this. i don't know if I need change the configuration in story board to dynamic or other thing.. Can I show two different custom cells
Thanks!
Check the criteria for showing each specific custom cell, then cast to that cell as needed:
override func tableView(tableView: UITableView?, cellForRowAtIndexPath indexPath: NSIndexPath?) -> UITableViewCell? {
if (criteria for cell 1) {
let cell = tableView!.dequeueReusableCellWithIdentifier("cell1", forIndexPath: indexPath) as? Cell1
return (cell)
}
else {
let cell = tableView!.dequeueReusableCellWithIdentifier("cell2", forIndexPath: indexPath) as? Cell2
return (cell)
}
}
Swift 3
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath -> UITableViewCell {
if (criteria for cell 1) {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath) as! Cell1
return cell
}
else {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell2", for: indexPath) as! Cell2
return cell
}
}
override func tableView(tableView: UITableView?,cellForRowAtIndexPath indexPath: NSIndexPath?) -> UITableViewCell? {
if (...) {
let cell : Mycell1 = tableView!.dequeueReusableCellWithIdentifier("Mycell1", forIndexPath: indexPath) as? Mycell1
return cell
}
else {
let cell : Mycell2 = tableView!.dequeueReusableCellWithIdentifier("Mycell2", forIndexPath: indexPath) as? Mycell2
return cell
}
}