Swift, preventing tableview cell resueable - swift

How to solve the table view data overlapped issue?
I have searched some Object C version answer, but it seems not working for Swift. I tried to get cell==nil, but it gives me an error
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let current_patient = patients[indexPath.row]
let cell = myTable.cellForRowAtIndexPath(indexPath) as! PatientTableViewCell
if (cell){
let cell = myTable.dequeueReusableCellWithIdentifier("patientCell") as! PatientTableViewCell
}
let cell = myTable.dequeueReusableCellWithIdentifier("patientCell", forIndexPath: indexPath) as! PatientTableViewCell
if(cell != nil){
var subviews = cell.contentView.subviews
subviews.removeAll()
}
//configure cell
let type = current_patient.enrollable_type
cell.patientTypelbl.text = type
return cell
}
After two-days struggling, I figure it out finally. The key to solve it is to find which cell is been resued. What I am doing now is give a var identifier to cell.
class PatientTableViewCell: UITableViewCell {
#IBOutlet weak var followupBtn: UIButton!
#IBOutlet weak var viewBtn: UIButton!
#IBOutlet weak var titleType: UILabel!
#IBOutlet weak var titleID: UILabel!
#IBOutlet weak var patientTypelbl: UILabel!
#IBOutlet weak var patientIDlbl: UILabel!
**var identifier = false**
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let current_patient = patients[indexPath.row]
var cell = myTable.dequeueReusableCellWithIdentifier("patientCell") as! PatientTableViewCell
if(cell.identifier == true){
cell = myTable.dequeueReusableCellWithIdentifier("patientCell") as! PatientTableViewCell
}
//config cell
cell.identifier = true //important
I hope it can help someone else. :)

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let current_patient = patients[indexPath.row]
let cell: PatientTableViewCell! = tableView.dequeueReusableCellWithIdentifier("patientCell") as? PatientTableViewCell
//configure cell
let type = current_patient.enrollable_type
cell.patientTypelbl.text = type
return cell
}

Related

Swift UITableViewCell not showing Labels

I'm trying to create a custom cell view with some labels, I have created a subclass of UITableViewCell and connected the labels to it. Inside cellForRowAt method I dequeued the cell and cast it as YourCell subclass to access the labels and set text.
Setting class of cell to YourCell
However when running the app, nothing is showing up.
class YourCell: UITableViewCell {
#IBOutlet weak var label1: UILabel!
#IBOutlet weak var label2: UILabel!
#IBOutlet weak var label3: UILabel!
}
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
let array1 = ["Name1", "Name2","Name3","Name3"]
let array2 = ["1","2","3","4"]
let array3 = ["18","17","11","9"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
tableView.delegate = self
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "cell") as! YourCell
cell.label1.text = array1[indexPath.row]
cell.label2.text = array2[indexPath.row]
cell.label3.text = array3[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array2.count
}
}
You have conformed the UITableViewDelegate protocol correctly, the only thing you are missing is to set up your datasource by including this line in your viewDidLoad.
tableview.dataSource = self

How to set multiple UITableview in single ViewController

I'm trying to make two TableViews in one ViewController and
having a trouble in cellForRowAt indexPath
I tried var cell:UITableviewCell? , return cell!
and now let cell = UITableViewCell() but it's still not working
#IBOutlet weak var ButtonA: UIButton!
#IBOutlet weak var ATV: UITableView!
#IBOutlet weak var ButtonB: UIButton!
#IBOutlet weak var BTV: UITableView!
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
if tableView == self.ATV {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = Alist[indexPath.row]
let bgColorView = UIView()
bgColorView.backgroundColor = UIColor(red:0.93, green:0.60, blue:0.49, alpha:0.5)
cell.selectedBackgroundView = bgColorView
}
if tableView == self.BTV {
let cell1 = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath)
cell1.textLabel?.text = Blist[indexPath.row]}
return cell
}
I want each button to have a different list

Multiple custom cell in TableViewController

Scenario
| First Cell |
| Second Cell |
| SWITCH |
| |
| Third Cell |
| TextField |
I created a dynamic table view with three different classes: SecondTableCell (inside it has the outlet of a switch) and ThirdTableCell (inside it has an outlet of a textField)
The switch is Off.
I need to see textField.isUserInteractionEnabled = false then the switch is turned on.
How can I do this?
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var customTableView: UITableView!
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellSwitch = tableView.dequeueReusableCell(withIdentifier: "cellSwitch")! as! SwitchTableViewCell
let cellText = tableView.dequeueReusableCell(withIdentifier: "cellText")! as! TextFieldTableViewCell
}
class SwitchTableViewCell: UITableViewCell {
#IBOutlet weak var switchOutlet: UISwitch!
#IBAction func switchAction(_ sender: UISwitch) {
if sender.isOn == true{
print("swithOn")
}else{
print("swithOff")
}
}
}
class TextFieldTableViewCell: UITableViewCell {
#IBOutlet weak var textFieldColor: UITextField!
}
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, SwitchDelegate {
#IBOutlet weak var customTableView: UITableView!
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellSwitch = tableView.dequeueReusableCell(withIdentifier: "cellSwitch")! as! SwitchTableViewCell
let cellText = tableView.dequeueReusableCell(withIdentifier: "cellText")! as! TextFieldTableViewCell
cellSwitch.delegate = self
cellText.delegate = self
}
func valueDidChange(isOn: Bool) {
tableView.visibleCells.forEach { cell
if let cell = cell as? TextFieldTableViewCell {
cell.textField.isUserInteractionEnabled = false
}
}
}
}
protocol SwitchDelegate {
func valueDidChange(isOn: Bool)
}
class SwitchTableViewCell: UITableViewCell {
#IBOutlet weak var switchOutlet: UISwitch!
var delegate: SwitchDelegate?
#IBAction func switchAction(_ sender: UISwitch) {
delegate?.valueDidChange(isOn: sender.isOn)
}
}
class TextFieldTableViewCell: UITableViewCell {
#IBOutlet weak var textField: UITextField!
}
When you setup the cells in the tableviewcontroller, you can define at view row you want to use which tableviewcell class. Just like in my below example:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if ((indexPath.row < 25 && counter > 25) || (indexPath.row < counter)) {
let cell = tableView.dequeueReusableCell(withIdentifier: "SaleItems", for: indexPath) as! MyTableCellTableViewCell
let TapRecognize = UITapGestureRecognizer(target: self, action: #selector(self.PictureTap(sender:)))
TapRecognize.numberOfTapsRequired = 1
TapRecognize.name = jSonData[indexPath.row]["advid"]
// Configure the cell...
cell.Megnevezes.text=jSonData[indexPath.row]["advdescription"]!
cell.EladasiAr.text=jSonData[indexPath.row]["advprice"]! + " " + jSonData[indexPath.row]["advpricecur"]!
cell.addGestureRecognizer(TapRecognize)
cell.LoadPicture(AdvID: Int(jSonData[indexPath.row]["advid"]!)!)
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "PagerCell", for: indexPath) as! ChangePageCell
cell.delegate = self
return cell
}
}
In my example the last row of the tableview is different. It is not exactly clear from your explanation what do you really want to do with the switch cell. But you should ensure that you can identify the cells and their classes to know where to pass the action's.
In my case the gestureRecognizer gets a name, which contains a relevant advertisement ID to load the photos, linked to that advertisement details.
When you tap on the cell, it calls the tap recogniser's action and name can be used to identify which cell is touched.

Swift - Increment Label with Stepper in TableView Cell

Another Swift beginner here. I simply want a Stepper in each of my TableView cells that increments a label in the same cell.
I have found a couple of questions on this topic, but they include other elements and I haven't been able to extract the basic concept.
Swift Stepper Action that changes UITextField and UILabel within same cell
Stepper on tableview cell (swift)
So far I have connected IBOutlets for my Label and Stepper, as well as an IBAction for my Stepper in my cell class.
class BuyStatsCell: UITableViewCell{
//these are working fine
#IBOutlet weak var category: UILabel!
#IBOutlet weak var average: UILabel!
#IBOutlet weak var price: UILabel!
//Outlet for Label and Stepper - How do I make these work?
#IBOutlet weak var purchaseAmount: UILabel!
#IBOutlet weak var addSubtract: UIStepper!
//Action for Stepper - And this?
#IBAction func stepperAction(_ sender: UIStepper) {
self.purchaseAmount.text = Int(sender.value).description
}
}
And I understand the concept of reusing the cell in the cellForRowAt indexPath
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "BuyStatsTabCell", for: indexPath) as! BuyStatsCell
cell.isUserInteractionEnabled = false
//these are working
cell.category.text = categories[indexPath.row]
cell.price.text = String(prices[indexPath.row])
cell.average.text = String(averages[indexPath.row])
//but is there something I need to add here to keep the correct Stepper and Label for each class?
return cell
}
One of the already asked questions includes a protocol and another function in the ViewController like this
protocol ReviewCellDelegate{
func stepperButton(sender: ReviewTableViewCell)
}
func stepperButton(sender: ReviewTableViewCell) {
if let indexPath = tableView.indexPathForCell(sender){
print(indexPath)
}
}
I don't know if this is the approach I should be trying to take. I am looking for the simplest solution, but I am having trouble putting the pieces together.
Any help is appreciated.
Thanks.
Easiest solution (simplyfied):
Create a model BuyStat with a property purchaseAmount (it's crucial to be a class).
You are strongly discouraged from using multiple arrays as data source
class BuyStat {
var purchaseAmount = 0.0
init(purchaseAmount : Double) {
self.purchaseAmount = purchaseAmount
}
}
In the view controller create a data source array
var stats = [BuyStat]()
In viewDidLoad create a few instances and reload the table view
stats = [BuyStat(purchaseAmount: 12.0), BuyStat(purchaseAmount: 20.0)]
tableView.reloadData()
In the custom cell create a property buyStat to hold the current data source item with an observer to update stepper and label when buyStat is set
class BuyStatsCell: UITableViewCell {
#IBOutlet weak var purchaseAmount: UILabel!
#IBOutlet weak var addSubtract: UIStepper!
var buyStat : BuyStat! {
didSet {
addSubtract.value = buyStat.purchaseAmount
purchaseAmount.text = String(buyStat.purchaseAmount)
}
}
#IBAction func stepperAction(_ sender: UIStepper) {
buyStat.purchaseAmount = sender.value
self.purchaseAmount.text = String(sender.value)
}
}
In cellForRowAtIndexPath get the data source item and pass it to the cell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "BuyStatsTabCell", for: indexPath) as! BuyStatsCell
cell.buyStat = stats[indexPath.row]
return cell
}
The magic is: When you are tapping the stepper the label as well as the data source array will be updated. So even after scrolling the cell will get always the actual data.
With this way you don't need protocols or callback closures. It's only important that the model is a class to have reference type semantics.
NOTE: MY Cell class is just normal..All changes are in viewcontroller class
class cell: UITableViewCell {
#IBOutlet weak var ibAddButton: UIButton!
#IBOutlet weak var ibStepper: UIStepper!
#IBOutlet weak var ibCount: UILabel!
#IBOutlet weak var ibLbl: UILabel!
}
1.define empty int array [Int]()
var countArray = [Int]()
2.append countArray with all zeros with the number of data u want to populate in tableview
for arr in self.responseArray{
self.countArray.append(0)
}
3.in cell for row at
func tableView(_ tableView: UITableView, cellForRowAt indexPath:
IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! cell
let dict = responseArray[indexPath.row] as? NSDictionary ?? NSDictionary()
cell.ibLbl.text = dict["name"] as? String ?? String()
if countArray[indexPath.row] == 0{
cell.ibAddButton.tag = indexPath.row
cell.ibStepper.isHidden = true
cell.ibAddButton.isHidden = false
cell.ibCount.isHidden = true
cell.ibAddButton.addTarget(self, action: #selector(addPressed(sender:)), for: .touchUpInside)
}else{
cell.ibAddButton.isHidden = true
cell.ibStepper.isHidden = false
cell.ibStepper.tag = indexPath.row
cell.ibCount.isHidden = false
cell.ibCount.text = "\(countArray[indexPath.row])"
cell.ibStepper.addTarget(self, action: #selector(stepperValueChanged(sender:)), for: .valueChanged)}
return cell
}
4.objc functions
#objc func stepperValueChanged(sender : UIStepper){
if sender.stepValue != 0{
countArray[sender.tag] = Int(sender.value)
}
ibTableView.reloadData()
}
#objc func addPressed(sender : UIButton){
countArray[sender.tag] = 1//countArray[sender.tag] + 1
ibTableView.reloadData()
}

UIlabel text alignment in UITableViewCell not working

Sorry for the Chinese characters, but the UILabel text alignment displayed as right side NO MATTER which option (left, center and etc.) it is set. Please help.
// This is the function that populates the cell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath) as! WordLibraryTableViewCell
let key = Int(dataSource[indexPath.section][indexPath.row])
let value = levelDict[key!]! as String
cell.wordLibLabel.text = value
return cell
}
// This is the cell class
class WordLibraryTableViewCell: UITableViewCell {
#IBOutlet weak var bookimageView: UIImageView!
#IBOutlet weak var wordLibLabel: UILabel!
}