CellForItemAt: index path not updating variable - ios

I am working with a UITableView that has a cell with a UISwitch in it. I have four tableViewCells, each from this same prototype cell. However, when I toggle the switch, the only way that the variables in the TableView CellForItemAt: section is when I pull the tableView so that it goes out of the screen, and the Reusable Cells are Reloaded. How can I make these variables refresh when the switches are toggled?
Here is my code:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "onOffCell", for: indexPath) as! SettingsCellTableViewCell
if indexPath.section == 0 {
cell.textLabel?.text = OLLItems![indexPath.row]._text
if indexPath.row == 0 {
GlobalData.AllGlobalData.OLLImageState = cell.state //GlobalData.AllGlobalData.OLLImageState is an struct in another file
print("OLLImageState \(GlobalData.AllGlobalData.OLLImageState)")
}
if indexPath.row == 1 {
GlobalData.AllGlobalData.OLLAlgState = cell.state
print("OLLAlgState \(GlobalData.AllGlobalData.OLLAlgState)")
}
}
if indexPath.section == 1 {
cell.textLabel?.text = PLLItems![indexPath.row]._text
if indexPath.row == 0 {
GlobalData.AllGlobalData.PLLImageState = cell.state
print("PLLImageState \(GlobalData.AllGlobalData.PLLImageState)")
}
if indexPath.row == 1 {
GlobalData.AllGlobalData.PLLAlgState = cell.state
print("PLLAlgState \(GlobalData.AllGlobalData.PLLAlgState)")
}
}
return cell
}

Try doing it this way
Below code works properly in my repo but I changed it a bit to justify your scenario
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "switchCell", for: indexPath) as! SwitchContainingTableViewCell
cell.mySwitch.addTarget(self, action: #selector(switchChanged(_:)), for: .valueChanged)
return cell
}
func switchChanged(_ mySwitch: UISwitch) {
guard let cell = mySwitch.superview?.superview as? SwitchContainingTableViewCell else {
return // or fatalError() or whatever
}
self.value = mySwitch.isOn //define var value in your controller or do it locally
let indexPath = itemTable.indexPath(for: cell)
if indexPath.section == 0 {
if indexPath.row == 0 {
GlobalData.AllGlobalData.OLLImageState = self.value
}
}
}
I have added a target of the switch and in the target I'm getting the changed state of the switch. The same can be done within the cellForItemAt: by using state = mySwitch.isOn
Hope this helps!

Related

How to manage with custom SegmentControllCell to tableview cell?

I tried to manage from custom segment control cell into ViewController's tableview cell.
This is My custom segment control class:
protocol SegmentControllerCellDelegate: AnyObject {
func manageSegmentControl(cell: SegmentControllerCell)}
class SegmentControllerCell: UITableViewCell, ReusableView, NibLoadableView {
#IBOutlet weak var segmentController: UISegmentedControl!
weak var delegate: SegmentControllerCellDelegate?
override func awakeFromNib() {
super.awakeFromNib()
setupUI()
}
#IBAction func tappedSegmentControll(_ sender: UISegmentedControl) {
self.delegate?.manageSegmentControl(cell: self )
}}
And this is my view controller:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch BrandSection(rawValue: indexPath.section)! {
case .profile:
guard let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: BrandTableViewCell.self), for: indexPath) as? BrandTableViewCell else { return UITableViewCell() }
cell.cellType = .brandPage
return cell
case .segment:
guard let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SegmentControllerCell.self), for: indexPath) as? SegmentControllerCell else { return UITableViewCell() }
cell.delegate = self
return cell
case .products:
guard let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: BrandProductionsCell.self), for: indexPath) as? BrandProductionsCell else { return UITableViewCell() }
return cell
}
}
extension BrandProfileVC: SegmentControllerCellDelegate {
func manageSegmentControl(cell: SegmentControllerCell) {
if cell.segmentController.selectedSegmentIndex == 0 {
self.brandTableView.reloadData()
print("index 0")
} else if cell.segmentController.selectedSegmentIndex == 1 {
self.brandTableView.reloadData()
print("index 1")
}
}}
I just want to show when I clicked segment control tab, different cell under the segment control.
Please try to set the cell.tag as indexPath.row from cellForRow and then try to print the cell.tag inside the manageSegmentControl in your ViewController
This is the Code:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch BrandSection(rawValue: indexPath.section)! {
case .profile:
guard let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: BrandTableViewCell.self), for: indexPath) as? BrandTableViewCell else { return UITableViewCell() }
cell.cellType = .brandPage
cell.tag = indexPath.row
return cell
case .segment:
guard let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SegmentControllerCell.self), for: indexPath) as? SegmentControllerCell else { return UITableViewCell() }
cell.delegate = self
cell.tag = indexPath.row
return cell
case .products:
guard let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: BrandProductionsCell.self), for: indexPath) as? BrandProductionsCell else { return UITableViewCell() }
cell.tag = indexPath.row
return cell
}
}
extension BrandProfileVC: SegmentControllerCellDelegate {
func manageSegmentControl(cell: SegmentControllerCell) {
if cell.segmentController.selectedSegmentIndex == 0 {
self.brandTableView.reloadData()
print(cell.tag)
} else if cell.segmentController.selectedSegmentIndex == 1 {
self.brandTableView.reloadData()
print(cell.tag)
}
}
}

Predictive tableView swift 4

I have 2 tableView with 2 tableView first to display data & sec for predictive texts and I'm using textField as searchBar so when I set the cell for the sec tableView is give me that error when I try to return the cell at cellForRowAt method
Cannot convert return expression of type UITableViewCell.Type to return type UITableViewCell
and that's my code
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == tableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "SearchCell", for: indexPath) as! searchCell
//cell.pics = receiveData[indexPath.item]
cell.titleCell.text = receiveData[indexPath.row].adeTitle
cell.cityCell.text = receiveData[indexPath.row].city
cell.dateCell.text = receiveData[indexPath.row].date
cell.distanceCell.text = receiveData[indexPath.row].distance
cell.priceCell.text = receiveData[indexPath.row].adePrice
if receiveData[indexPath.row].typ == "2" {
cell.kindCell.text = "used"
cell.kindCell.backgroundColor = UIColor.darkGray
cell.kindCell.textColor = UIColor.white
} else if receiveData[indexPath.row].typ == "1" {
cell.kindCell.text = "New"
} else {
cell.kindCell.text = "none"
cell.kindCell.backgroundColor = UIColor.darkGray
cell.kindCell.textColor = UIColor.white
}
} else {
var cell = searchTableView.dequeueReusableCell(withIdentifier: "Cell" )
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")
}
cell?.textLabel?.text = inputs[indexPath.row]
}
return UITableViewCell
}
Looks like UITableViewCell's instance is not returned in your cellForRowAt method,
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == tableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "SearchCell", for: indexPath) as! searchCell
...
// do your stuffs with cell
...
return cell
}
return UITableViewCell()
}

Check box check and unchecked not persisting in my table view

My task I am trying to show tableView with check box button inside the popup viewcontroller.
Whenever user click the button it is changing check and uncheck but I need to do when I click done button I have to keep user checked and if click cancel it should uncheck(which is user checked before click cancel). I need to understand and fix this task.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:MyCustomCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as! MyCustomCell
cell.myCellLabel.text = self.animals[indexPath.row]
if selectedRows.contains(indexPath)
{
cell.checkBox.setImage(UIImage(named:"check.png"), for: .normal)
}else{
cell.checkBox.setImage(UIImage(named:"uncheck.png"), for: .normal)
}
cell.checkBox.tag = indexPath.row
cell.checkBox.addTarget(self, action: #selector(checkBoxSelection(_:)), for: .touchUpInside)
return cell
}
// method to run when table view cell is tapped
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let cell = tableView.cellForRow(at: indexPath) as? MyCustomCell else {
return
}
if self.selectedRows.contains(indexPath) {
self.selectedRows.remove(at: self.selectedRows.index(of: indexPath)!)
cell.checkBox.setImage(UIImage(named:"uncheck.png"), for: .normal)
} else {
self.selectedRows.append(indexPath)
cell.checkBox.setImage(UIImage(named:"check.png"), for: .normal)
let indexPath = tableView.indexPathForSelectedRow //optional, to get from any UIButton for example
let currentCell = tableView.cellForRow(at: indexPath!) as! MyCustomCell
}
}
#IBAction func cancelPopup(_ sender: Any) {
self.removeAnimate()
}
#IBAction func donePopUp(_ sender: AnyObject) {
self.removeAnimate()
}
You may consider using basic taleview cell with setting acessoryType . Putting checkbox and labels all at the left seems giving poor UX
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "DefectCell", for: indexPath)
let category = defectSet [indexPath.section]
let item = category.items[indexPath.row]
cell.textLabel?.text = item.name
cell.selectionStyle = .none
let isFound = User.shared.selectedDefect.filter{ $0.id == item.id }.count > 0
if (isFound)
{
cell.accessoryType = .checkmark
}
else
{
cell.accessoryType = .none
}
return cell
}

UITableviewCell toggling only one custom checkmark state not working - Swift 3

I have reviewed this link and the solutions were not working for me.
I am trying to select one row and when I do select it, it adds a checkmark to the label. If another row is selected while there is an existing checkmark, it will uncheck the previous one which is stored in a selectedIndexPath variable.
It works in the beginning, however when scrolling through the tableview several times, I occasionally see a cell selected that should not be as indicated in this image:
What I am doing when a user selects a cell:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) as? CustomCell {
let customCell = customCellData[indexPath.row]
customCell.toggleSelected()
cell.configureCheckmark(with: customCell)
}
if let oldIndexPath = selectedIndexPath, let cell = tableView.cellForRow(at: oldIndexPath) as? CustomCell, oldIndexPath.row != indexPath.row {
let customCell = customCellData[oldIndexPath.row]
customCell.toggleSelected()
cell.configureCheckmark(with: customCell)
}
if let selected = selectedIndexPath, selected.row == indexPath.row {
selectedIndexPath = nil
tableView.deselectRow(at: indexPath, animated: true)
} else {
selectedIndexPath = indexPath
}
}
and in for cellForRowAt: (is it redundant to check the selectedIndexPath and the state in the model?)
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell
let customCell = customCellData[indexPath.row]
cell.customCell = customCell
if selectedIndexPath == indexPath {
cell.checkLabel.text = "✔️"
} else {
cell.checkLabel.text = ""
}
return cell
}
and finally in the CustomCell:
var customCell: CustomCell? {
didSet {
if let customCell = customCell {
configureCheckmark(with: customCell)
}
}
}
func configureCheckmark(with customCell: CustomCellData) {
if customCell.isSelected {
checkLabel.text = "✔️"
} else {
checkLabel.text = ""
}
}
In CustomCellData I toggle the state as follows:
class CustomCellData {
var isSelected = false
func toggleSelected() {
isSelected = !isSelected
}
}
I am scratching my head on this and unsure what to do, any help would be great.
The easiest solution is to reduce didSelectRowAt to
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
selectedIndexPath = indexPath
tableView.reloadData()
}
This updates all visible cells properly.
Or more sophisticated version which updates only the affected rows and checks if the cell is already selected
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
if selectedIndexPath != indexPath {
let indexPathsToReload = selectedIndexPath == nil ? [indexPath] : [selectedIndexPath!, indexPath]
selectedIndexPath = indexPath
tableView.reloadRows(at: indexPathsToReload, with: .none)
} else {
selectedIndexPath = nil
tableView.reloadRows(at: [indexPath], with: .none)
}
}
The code in cellForRowAt does the rest.

switch between cells when segmentedControl has changed

i have a custom UITableViewCell which contains an segmentedControl. This segmentedControl is suppose to control the second cell. When the index in segmentedControl has changed it should switch to another custom cell. How can i do something like this? i've tried implementing a IBAction in the viewController, but then i cant connect it to the segmentedControl in the xib file. If i put that method in the segmentedViewCell then i cant change the cells subclass. How can i obtain this?
Here is a little illustration. segmentedControl and the bottom view is in different cells.
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCellWithIdentifier("ImageViewCell", forIndexPath: indexPath) as ImageViewCell
cell.itemImage.image = itemFile
cell.separatorInset = UIEdgeInsetsMake(0, cell.bounds.size.width, 0, 0)
cell.selectionStyle = UITableViewCellSelectionStyle.None
return cell
} else if indexPath.row == 1 {
let cell = tableView.dequeueReusableCellWithIdentifier("UtilityViewCell", forIndexPath: indexPath) as UtilityViewCell
cell.titleLabel.text = itemTitle
cell.selectionStyle = UITableViewCellSelectionStyle.None
cell.separatorInset = UIEdgeInsetsMake(0, cell.bounds.size.width, 0, 0)
return cell
} else if indexPath.row == 2 {
let cell = tableView.dequeueReusableCellWithIdentifier("DescViewCell", forIndexPath: indexPath) as DescViewCell
cell.selectionStyle = UITableViewCellSelectionStyle.None
cell.separatorInset = UIEdgeInsetsMake(0, cell.bounds.size.width, 0, 0)
return cell
}
return nil
}
Here is a step by step. In your project's storyboard, create a UITableViewController scene. Add UITableViewCells in it as indicated in the image below. Change your first cell's style to "custom" and add a UISegmentedControl with non-ambiguous auto layout constraints in it.
Before setting your code,
Make sure that your UITableViewController scene has its class set
to "TableViewController".
Make sure to select Prototype Cells and Grouped TableView Style for your UITableView in Attributes Inspector.
Make sure that your UISegmentedControl has a view tag set to 1 (see image).
Make sure that the cell that contains the UISegmentedControl has
its identifier set to "SegmentCell".
Make sure that the second cell has its identifier set to "CellZero".
Make sure that the third cell has its identifier set to "CellOne".
Make sure that the fourth cell has its identifier set to "CellTwo".
Finally, your UITableViewController class file will contain the following code:
import UIKit
class TableViewController: UITableViewController {
var segment = 0
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func segmentAction(sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case 0:
segment = 0
case 1:
segment = 1
case 2:
segment = 2
default:
break
}
tableView.reloadData()
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: UITableViewCell!
if indexPath.row == 0 {
cell = tableView.dequeueReusableCellWithIdentifier("SegmentCell", forIndexPath: indexPath) as UITableViewCell
cell.selectionStyle = .None //if necessary
let segmentControl = cell.viewWithTag(1) as UISegmentedControl
segmentControl.selectedSegmentIndex = segment
segmentControl.addTarget(self, action: "segmentAction:", forControlEvents: .ValueChanged)
} else {
switch segment {
case 0:
cell = tableView.dequeueReusableCellWithIdentifier("CellZero", forIndexPath: indexPath) as UITableViewCell
case 1:
cell = tableView.dequeueReusableCellWithIdentifier("CellOne", forIndexPath: indexPath) as UITableViewCell
case 2:
cell = tableView.dequeueReusableCellWithIdentifier("CellTwo", forIndexPath: indexPath) as UITableViewCell
default:
break
}
}
return cell
}
}
Ok, this might take an iteration until I better understand your need.
This from a demo project of some flash cards and I use a segmented control to decide to display all the historical games or just those of a certain type (addition, subtraction, etc.) I had to deal with the issue of where to put the segmented control. Inside the table or above the table. The problem with inside the table is in my case the view reloads after each change.
But I do use he segmented control to change both the header and the cell contents.
So I can post the code for all this, or I can create a short demo code for the segmented control within a table cell (not sure how that will play out).
override func numberOfSections(in intableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func segmentAction(_ sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case 0:
segment = 0
case 1:
segment = 1
case 2:
segment = 2
default:
break
}
tableView.reloadData()
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell: UITableViewCell!
if indexPath.row == 0 {
cell = tableView.dequeueReusableCell(withIdentifier: "SegmentCell", for: indexPath as IndexPath) as UITableViewCell
// cell.selectionStyle = .none //if necessary
let segmentControl = cell.viewWithTag(1) as! UISegmentedControl
segmentControl.selectedSegmentIndex = segment
segmentControl.addTarget(self, action: #selector(JobReportTableViewController.segmentAction(_:)), for: .valueChanged)
} else {
switch segment {
case 0:
cell = tableView.dequeueReusableCell(withIdentifier: "CellZero", for: indexPath as IndexPath) as UITableViewCell!
case 1:
cell = tableView.dequeueReusableCell(withIdentifier: "CellOne", for: indexPath as IndexPath) as UITableViewCell!
case 2:
cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath)as UITableViewCell!
default:
break
}
}
return cell
}
}

Resources