Problems updating UITableView cell and SwiftyPickerPopover - ios

The problem is that when I am selecting some value (in the field picker -SwiftyPickerPopover-) in a row, the action updates the same value (selected in picker) for all rows.
The code that I am using for this for the ViewController (with UITableView inside):
func btnExpenseTypePressed(at index: IndexPath) {
var tiposGasto: [String] = [String]()
for gasto in dataManager.expensesType {
tiposGasto.append(gasto.tipoGasto!)
}
let cell = tableView.dequeueReusableCell(withIdentifier: "cellIdentifier", for: index) as! ExpenseDetailCell
StringPickerPopover.appearFrom(
originView: cell.btnExpenseType,
baseViewController: self,
title: "Tipos de Gasto",
choices: tiposGasto,
initialRow:0,
doneAction: { selectedRow, selectedString in
print("Seleccion \(selectedString)")
//self.valueSelected = selectedString
cell.btnExpenseType.setTitle(selectedString, for: .normal)
self.tableView.reloadData()
} ,cancelAction: { print("cancel")}
)
}
func btnCostCenterPressed(at index: IndexPath) {
var centroCoste: [String] = [String]()
for centro in dataManager.costsCenter {
centroCoste.append(centro.centroCoste!)
}
let cell = tableView.dequeueReusableCell(withIdentifier: "cellIdentifier", for: index) as! ExpenseDetailCell
StringPickerPopover.appearFrom(
originView: cell.btnCostCenter,
baseViewController: self,
title: "Centro de Coste",
choices: centroCoste,
initialRow:0,
doneAction: { selectedRow, selectedString in
print("Seleccion \(selectedString)")
//self.valueSelected = selectedString
cell.btnCostCenter.setTitle(selectedString, for: .normal)
self.tableView.reloadData()
} ,cancelAction: { print("cancel")}
)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : UITableViewCell? = UITableViewCell()
if tableView == self.tableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellIdentifier", for: indexPath) as! ExpenseDetailCell
cell.selectionStyle = .none
cell.delegate = self
debugPrint("First table load \(firstTableLoad)")
if firstTableLoad {
cell.btnCostCenter.setTitle(dataManager.costsCenter[0].centroCoste, for: .normal)
cell.btnExpenseType.setTitle(dataManager.expensesType[0].tipoGasto, for: .normal)
firstTableLoad = false
}
return cell
}
if tableView == self.tableViewImages {
let cell = tableView.dequeueReusableCell(withIdentifier: "imagesCellIdentifier", for: indexPath) as! ExpenseImageCell
cell.imageView?.image = UIImage(named: "imgPlaceholder")
cell.selectionStyle = .none
return cell
}
return cell!
}
The btnExpenseTypePressed and btnCostCenterPressed methods are delegate from the ExpenseDetailCell:
protocol ExpenseDetailDelegate {
func switchChanged(at index: IndexPath)
func amountEditedChanged(at index: IndexPath)
func btnExpenseTypePressed(at index: IndexPath)
func btnCostCenterPressed(at index: IndexPath)
}
class ExpenseDetailCell: UITableViewCell {
var delegate: ExpenseDetailDelegate!
var indexPath: IndexPath!
var dataManager = DataManager.sharedInstance
#IBOutlet weak var txtAmountNumber: UITextField!
#IBOutlet weak var txtId: UITextField!
#IBOutlet weak var txtAmountPercent: UITextField!
#IBOutlet weak var lblTotal: UILabel!
#IBOutlet weak var lblSeparator: UILabel!
#IBOutlet weak var lblPercent: UILabel!
#IBOutlet weak var btnExpenseType: UIButton!
#IBOutlet weak var btnCostCenter: UIButton!
#IBOutlet weak var switchID: UISwitch!
#IBAction func btnExpenseTypePressed(_ sender: Any) {
debugPrint("En btnExpenseTypePressed")
self.delegate?.btnExpenseTypePressed(at: indexPath)
debugPrint("El INDEX \(indexPath)")
}
#IBAction func btnCostCenterPressed(_ sender: Any) {
debugPrint("En btnCostCenterPressed")
self.delegate?.btnCostCenterPressed(at: indexPath)
debugPrint("El INDEX \(indexPath)")
}
#IBAction func amountEditedChanged(_ sender: Any) {
debugPrint("En amountEditedChanged")
self.delegate?.amountEditedChanged(at: indexPath)
lblTotal.text = txtAmountNumber.text
}
#IBAction func switchChanged(_ sender: Any) {
debugPrint("En value changed")
self.delegate?.switchChanged(at: indexPath)
if switchID.isOn {
debugPrint("Dentro if")
txtId.text = ""
txtId.isEnabled = false
} else {
txtId.isEnabled = true
}
}
}
I am using SWIFT 3.

I believe the error comes from a missunderstanding of what you want to do and what you are acctually doing.
You want: Change one value in one cell
You do: Change one value in all cells ON cell creation.
When you call: self.tableView.reloadData() in unc btnExpenseTypePressed(at index: IndexPath) iOS calls
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) again and again skipping the `firstTableLoad = false` and loading all the tableviewCells with the same value.
You have also set the index to 0 in DataManager.costsCenter[0] which will mean that all the cells on creation will have the same value.
My suggestion: Do your changes in:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
}
If by any chance this doesn't help you check clean the cell in :
override func prepareForReuse()
{
super.prepareForReuse()
}
or just set it like this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : UITableViewCell? = UITableViewCell()
if tableView == self.tableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellIdentifier", for: indexPath) as! ExpenseDetailCell
cell.selectionStyle = .none
cell.delegate = self
cell.setMyCustomText("")...
}
return cell
}

Related

Swift make wishlist feature

so I want to make this simple wishlist feature for when the user tapped the "heart" button it will add that data from view to wishlist view. just like this :
so when the user tapped that heart button, that movie will show in this wishlist view like this :
now, my question is how do I notify my wishlistVc so that it knows there's a new "wishlist" that the user tapped from the movie list. I have an idea that I should use a delegate, but still, I can't figure out how to implement a delegate in this case.
and I use "var movieList" to store all the data in HomeVc, and my idea is when the user tapped that heart button in tableview, that data that user tapped with will move into my "let wishlist", so i can populate it on my wishlistVC ( but I don't know how to do this so I need help)
so far this is my code :
class DefaultTableViewCell: UITableViewCell {
#IBOutlet weak var moviePosterImage: UIImageView!
#IBOutlet weak var movieTitleLabel: UILabel!
#IBOutlet weak var wishlistButton: UIButton!
var indexPath: IndexPath!
var delegate: DefaultTableViewDelegate?
var wishlistFlag:Bool = false
override func layoutSubviews() {
super.layoutSubviews()
wishlistButton.titleLabel?.text = ""
wishlistButton.addTarget(self, action: #selector(wishlistTapped(_:)), for: .valueChanged)
}
#IBAction func wishlistTapped(_ sender: UIButton) {
wishlistFlag = !wishlistFlag
delegate?.wishlistTrigger(row: indexPath.row)
if wishlistFlag == true {
wishlistButton.setImage(UIImage(named: "heart_fill"), for: .normal)
}else if wishlistFlag == false {
wishlistButton.setImage(UIImage(named: "heart"), for: .normal)
}
}
}
HomeVc (the vc that shows the movie list):
var movieList : [Movie] = []
extension HomeVC: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return movieList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let data = movieList[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "DefaultTableViewCell", for: indexPath) as! DefaultTableViewCell
cell.indexPath = indexPath
cell.movieTitleLabel.text = data.title
cell.moviePosterImage.sd_setImage(with: data.imageUrl)
cell.delegate = self
return cell
}
}
protocol DefaultTableViewDelegate {
func wishlistTrigger(row: Int)
}
this is my wishlistVc:
let wishlist : [Movie] = []
extension WishlistVc: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return wishlist.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let data = wishlist[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "DefaultTableViewCell", for: indexPath) as! DefaultTableViewCell
cell.movieTitleLabel.text = data.title
cell.moviePosterImage.sd_setImage(with: data.imageUrl)
cell.wishlistButton.titleLabel?.text = ""
cell.indexPath = indexPath
return cell
}
}
I've been stuck for 2 whole days now I still don't know how to figure this out. I appreciate anyone that can help me. Thanks
Implement func like:
func wishlistTrigger(row: Int) {
self.myWishlistedItem.append(self.movieList[row]) //Add that wishlisted item in array
self.tableView.reloadData() //Now reload Table
}

I m getting 4 times values of same data in tableview cell, so kindly help to pass the data with one value

import UIKit
class ViewController: UIViewController,UITableViewDelegate, UITableViewDataSource, pass {
var array = [String]()
#IBOutlet weak var tblView: UITableView!
#IBOutlet weak var btnPush: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as!TableViewCell
cell.lblName.text = array[indexPath.row]
cell.lblFullName.text = array[indexPath.row]
cell.lblRollno.text = array[indexPath.row]
cell.lblClass.text = array[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 200
}
#IBAction func btnPush(_ sender: UIButton) {
let vc = storyboard?.instantiateViewController(withIdentifier: "SecondVC") as!SecondVC
vc.mac = self
self.navigationController?.pushViewController(vc, animated: true)
}
func Datapass(Name: String, FullName Address: String, Rollno: String, Class: String) {
self.array.append(Name)
self.array.append(Address)
self.array.append(Rollno)
self.array.append(Class)
tblView.reloadData()
}
}
import UIKit
protocol pass {
func Datapass(Name:String, FullName:String, Rollno:String, Class:String)
}
class SecondVC: UIViewController {
#IBOutlet weak var textFldName: UITextField!
#IBOutlet weak var txtFldFullName: UITextField!
#IBOutlet weak var txtFldRollno: UITextField!
#IBOutlet weak var txtFldClass: UITextField!
var mac:pass?
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func btnAdd(sender: UIButton) {
mac?.Datapass(Name: textFldName.text!, FullName: txtFldFullName.text!, Rollno: txtFldRollno.text!, Class: txtFldClass.text!)
self.navigationController?.popViewController(animated: true)
}
}
your adding data to your array the wrong way. your adding 4 parameter
and your array will be like this:
array: 0:name|1:Address|2:Rollno|3:Class
and when your reading this from table every time you map this:
cell.lblName.text = array[0]
cell.lblFullName.text = array[0]
cell.lblRollno.text = array[0]
cell.lblClass.text = array[0]
every time table only reads one element of array for 4 times! you are not changing indexpath.row , it will change it's number after loading 1 cell.
the right way to do this is code below:
struct DbModel{
var name:String
var address:String
var rollno:String
var `class`:String
}
var array :[DbModel] = []
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as! TableViewCell
let model = array[indexPath.row]
cell.lblName.text = model.name
cell.lblFullName.text = model.address
cell.lblRollno.text = model.rollno
cell.lblClass.text = model.class
return cell
}
func Datapass(Name: String, FullName Address: String, Rollno: String, Class: String) {
let model = DbModel(name: Name, address: Address, rollno: Rollno, class: Class)
self.array.append(model)
tblView.reloadData()
}

Need to implement delegate method in viewDidLoad in tableView with custom cells

Im trying to implement BEMCheckBox and the myCheckBox.delegate = self needs to be se in viewDidLoad.
How do I do this in a tableView?
I have done this to my cells and tableView:
Cell file for the tableView:
import UIKit
import BEMCheckBox
protocol SizeSelectionDelegate: NSObjectProtocol {
func didChooseSmall(cell: SizeSelectorCell)
func didChooseLarge(cell: SizeSelectorCell)
}
class SizeSelectorCell: UITableViewCell {
#IBOutlet weak var smallSizeCheckBox: BEMCheckBox!
#IBOutlet weak var largeSizeCheckBox: BEMCheckBox!
#IBOutlet weak var smallSizePriceLabel: UILabel!
#IBOutlet weak var largeSizePriceLabel: UILabel!
weak var delegate: SizeSelectionDelegate?
func didTap(_ checkBox: BEMCheckBox) {
if checkBox.tag == 0 {
delegate?.didChooseSmall(cell: self)
}
if checkBox.tag == 1 {
delegate?.didChooseLarge(cell:self)
}
}
}
TableViewController:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "InfoCell") as! InfoTableViewCell
cell.nameLabel.text = name
cell.detailLabel.text = detail
cell.smallPriceLabel.text = String (smallPrice)
cell.largePriceLabel.text = String (largePrice)
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "SizeSelector") as! SizeSelectorCell
cell.smallSizePriceLabel.text = String (smallPrice)
cell.largeSizePriceLabel.text = String (largePrice)
return cell
}
}
extension InfoTableViewController: SizeSelectionDelegate
{
func didChooseSmall(cell: SizeSelectorCell) {
size = "Small"
print(size)
}
func didChooseLarge(cell: SizeSelectorCell) {
size = "Large"
print(size)
}
}
You need to set the delegate cell.delegate = self inside cellForRowAt
let cell = tableView.dequeueReusableCell(withIdentifier: "SizeSelector") as! SizeSelectorCell
cell.delegate = self
cell.smallSizePriceLabel.text = String (smallPrice)
cell.largeSizePriceLabel.text = String (largePrice)
return cell

Save textField value to cell textLabel (name) [SWIFT]

I'm going to do something like this https://i.stack.imgur.com/jAGsk.png
So if user input points - it'll save points to the user's name. How to do it? I paste textField in the tableViewCell with a functions.
Here is code from the tableViewCell file
#IBOutlet weak var inputScore: UITextField!
public func configure(text: Int?, placeholder: String) {
inputScore.text = String(text!)
inputScore.placeholder = placeholder
inputScore.accessibilityValue = String(text!)
inputScore.accessibilityLabel = placeholder
}
And here is code from the VC file
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "InputScore") as! InputScoreTableViewCell
cell.textLabel?.text = usersIn[indexPath.row]
cell.configure(text: 100, placeholder: "Score")
return cell
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return usersIn.count
}
So how to save it to the user's name?
Use DidSelectRowAtIndexPath method to get cell textLable text in textField.
Below Sample Code for That:
import UIKit
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet var btnOK: UIButton!
#IBOutlet var txtValue: UITextField!
#IBOutlet var tblData: UITableView!
let arrResult = NSMutableArray()
override func viewDidLoad() {
super.viewDidLoad()
tblData.dataSource = self
tblData.delegate = self
btnOK.tag = 57775
btnOK.addTarget(self, action: #selector(applyEdit(sender:)), for: .touchUpInside)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrResult.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
cell.textLabel?.text = arrResult[indexPath.row] as? String ?? ""
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
btnOK.tag = indexPath.row
let cell: UITableViewCell = tableView.cellForRow(at: indexPath)!
txtValue.text = cell.textLabel?.text
setTitle()
}
func setTitle() {
if btnOK.tag == 57775 {
btnOK.setTitle("Add", for: .normal)
}else{
btnOK.setTitle("Update", for: .normal)
}
}
func applyEdit(sender: UIButton) {
if sender.tag == 57775 {
arrResult.add(txtValue.text ?? "")
}else{
arrResult.removeObject(at: sender.tag)
arrResult.insert(txtValue.text ?? "", at: sender.tag)
sender.tag = 57775
setTitle()
}
txtValue.text = ""
tblData.reloadData()
}
}
output:
You have to create a data model for your users:
class User: NSObject {
var points = 0
}
And then create an array of users in your view controller:
var users = [User]()
That way, you can do something like this
var user = users[indexPath.row]
user.points = 100
print(user.points) // 100
You can then display your users' points in your table view. You can also assign a tag to your text fields equal to the indexPath.row so that you can easily work with them.
In top of use user model provided by #Cesare we need to modified the cellForRowAtIndexPath method and your cell's implementation, adding a closure for data change event, and using it
#IBOutlet weak var inputScore: UITextField!
fileprivate var fnDataWasUpdated : (Int?) -> Void = {_ in} //closure for data change notification
public func configure(text: Int?, placeholder: String,_ fnListener: #escaping (Int?) -> Void) {
inputScore.text = String(text!)
inputScore.placeholder = placeholder
inputScore.accessibilityValue = String(text!)
inputScore.accessibilityLabel = placeholder
//added delegate implementation for UITextField
inputScore.delegate = self
self.fnDataWasUpdated = fnListener
}
also is needed that your cell adopts UITextFieldDelegate protocol
extension InputScoreTableViewCell : UITextFieldDelegate
{
func textFieldDidEndEditing(_ textField: UITextField)
{
if let intValue = Int(textField.text)
{
self.fnDataWasUpdated(intValue)
}
}
}
Finally we use the new closure in your cell
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "InputScore") as! InputScoreTableViewCell
let currUser = self.users[indexPath.row]
cell.configure(text: currUser.points, placeholder: "Score",{ (newIntValue) in
currUser.points = newIntValue
})
return cell
}
This code was not tested but I had been using the main concept in several projects, so if you have any kind of problems please let me know
I hope this helps you

hide button in a collectionview cell when trigger

i have collectionview that contain del button and add
cell.coupon_add.tag = indexPath.row
cell.coupon_add?.layer.setValue(id, forKey: "coupon_id")
cell.coupon_add?.layer.setValue(uID, forKey: "user_id")
cell.coupon_add?.addTarget(self, action: #selector(ViewController.addItem(_:)), forControlEvents: UIControlEvents.TouchUpInside)
func addItem(sender:UIButton) {
let point : CGPoint = sender.convertPoint(CGPointZero, toView:collectionview)
let indexPath = collectionview!.indexPathForItemAtPoint(point)
let cell = collectionview.dequeueReusableCellWithReuseIdentifier("listcell", forIndexPath: indexPath!) as! ListCell
let coupon_id : String = (sender.layer.valueForKey("coupon_id")) as! String
let user_id : String = (sender.layer.valueForKey("user_id")) as! String
if user_id == "empty" {
self.login()
}else{
print("adding item**",indexPath)
cell.coupon_add.hidden = true
cell.coupon_del.hidden = true
let buttonRow = sender.tag
print(buttonRow)
}
}
i want to hide the add button when trigger. i just get the value of the indexPath but i dont know how to hide it without refresh the collectionview
Create a custom cell
class CustomCell: UICollectionViewCell {
#IBOutlet weak var label: UILabel!
#IBOutlet weak var delButton: UIButton!
#IBOutlet weak var addButton: UIButton!
#IBAction func addTapped(sender: AnyObject) {
delButton.removeFromSuperview()
addButton.removeFromSuperview()
}
}
Typical CollectionView Controller
class ViewController: UICollectionViewController {
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10;
}
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! CustomCell
cell.label.text = "Cell \(indexPath.row)"
return cell
}
}
And your button will gone, when you hit them

Resources