How to increment and decrement value of label in tableview and make total price from label value in swift? - ios

now cell value are dynamically and its look after calling api.
I want to make total of all tickets price at last. I refer this link How do I increment/decrement a label value with two buttons pressed in tableview Swift and make changes in my code but didn't work for me.
struct Product {
var price = 0
}
class TicketBookingVC: UIViewController , UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tblView: UITableView!
#IBOutlet weak var mainTblView: UIView!
var bookingDetails = NSDictionary()
var productArray = [Product]()
var product : Product!
private var counterValue = 1
var productIndex = 0
var counterLbl = UILabel()
#IBOutlet weak var bookBtn: UIButton!
#IBOutlet weak var eventImg: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
tblView.delegate = self
tblView.dataSource = self
for _ in 0...10{
productArray.append(Product(price: 1))
}
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 3
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return 1
}
else if section == 1{
return 4
}
else{
return 1
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellfirst", for: indexPath)
cell.selectionStyle = .none
return cell
}
else if indexPath.section == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellsecond", for: indexPath)
let mainViewCell = cell.contentView.viewWithTag(2000) as! UIView
let normalView = cell.contentView.viewWithTag(2001) as! UIView
let eventName = cell.contentView.viewWithTag(2003) as! UILabel
let eventPrice = cell.contentView.viewWithTag(2004) as! UILabel
counterLbl = cell.contentView.viewWithTag(2007) as! UILabel
let decrementBtn = cell.contentView.viewWithTag(2005) as! UIButton
let incrementBtn = cell.contentView.viewWithTag(2006) as! UIButton
decrementBtn.addTarget(self, action:#selector(self.decrementbuttonClicked), for: .touchUpInside)
incrementBtn.addTarget(self, action:#selector(self.incrementbuttonClicked), for: .touchUpInside)
product = productArray[indexPath.row]
counterLbl.text = "\(product.price)"
cell.selectionStyle = .none
return cell
}
else {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellthird", for: indexPath)
cell.selectionStyle = .none
return cell
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 0{
return UITableView.automaticDimension
}
else{
return 80
//return UITableView.automaticDimension
}
}
#objc func decrementbuttonClicked() {
print("Button decrement")
if(counterValue != 1){
counterValue -= 1;
}
self.counterLbl.text = "\(counterValue)"
product.price = counterValue
}
#objc func incrementbuttonClicked() {
counterValue += 1;
self.counterLbl.text = "\(counterValue)"
product.price = counterValue
}
func addProductToCart(product: Product, atindex: Int) {
productArray[atindex] = product
calculateTotal()
}
func calculateTotal()
{
var totalValue = 0
for objProduct in productArray {
totalValue += objProduct.price
}
self.eventPrice.text = "Total \(totalValue)"
}
}
when I increment or decrement value of first cell it reflect in 4th cell. please help. I am new at swift.

This is due to cell reuse. You should set a model for each cell

Related

plus or minus button values is not updated in swift

I working on cart view controller I tried some of code, it's show like below image.
values updating every row in tableview, if I click on product1 plusbutton count is increase showing 1 .when I click on product2 plusbutton value is showing 2.count is increasing.minus every time minusbutton also working same like that.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell") as! CustomTableViewCell
cell.minusButton.tag = indexPath.row
cell.plusbutton.tag = indexPath.row
cell.minusButton.addTarget(self, action: #selector(minusbuttonClick), for: .touchUpInside)
cell.plusbutton.addTarget(self, action: #selector(plusButtonClick), for: .touchUpInside)
return cell
}
#objc func minusbuttonClick(sender : UIButton)
{
let cell = Tableview.cellForRow(at: NSIndexPath(row: sender.tag, section: 0) as IndexPath) as! CustomTableViewCell
if(count > 0){
count -= 1
}
let myString = String(count)
cell.countLabel.text = myString
if count == 0{
cell.countLabel.text = ""
}
self.Tableview.reloadData()
}
#objc func plusButtonClick(sender : UIButton)
{
let cell = Tableview.cellForRow(at: NSIndexPath(row: sender.tag, section: 0) as IndexPath) as! CustomTableViewCell
count += 1
let myString = String(count)
cell.countLabel.text = myString
self.Tableview.reloadData()
}
I have to show when I click product1 value should be 1, if I click on product2 value as 1
minus also decrease same like that
first thing to do is create a struct to hold your data
struct ProductData {
var count : Int
var name : String
}
and you can use that in your ViewController
var productData : [ProductData] = []
the, of course, you need to add some data - here's a simple set to get started
override func viewDidLoad() {
super.viewDidLoad()
// set up some data.
productData.append(ProductData(count: 0, name: "product 1"))
productData.append(ProductData(count: 0, name: "product 2"))
productData.append(ProductData(count: 0, name: "product 3"))
productData.append(ProductData(count: 0, name: "product 4"))
}
using the delegate model described earlier swift: how to get the indexpath.row when a button in a cell is tapped? update your custom table view cell
protocol TableViewCellCustomDelegate: class {
func buttonTapped(index : Int, delta : Int)
}
class TableViewCellCustom: UITableViewCell {
weak var delegate: TableViewCellCustomDelegate?
#IBOutlet weak var minusButton: UIButton!
#IBOutlet weak var plusButton: UIButton!
#IBOutlet weak var countLabel: UILabel!
#IBOutlet weak var productLabel: UILabel!
override func prepareForReuse() {
super.prepareForReuse()
self.delegate = nil
}
#IBAction func minusButtonClick(_ sender: UIButton) {
delegate?.buttonTapped(index: sender.tag, delta : -1)
}
#IBAction func plusButtonClick(_ sender: UIButton) {
delegate?.buttonTapped(index: sender.tag,delta : +1)
}
}
update the delegate methods in your view controller. I've done it here with a single method to add or delete, but you could split it out if you want to do other things as well.
extension ViewController: TableViewCellCustomDelegate {
func buttonTapped(index: Int, delta : Int)
{
productData[index].count += delta
if productData[index].count < 0
{
productData[index].count = 0
}
tableView.reloadRows(at: [IndexPath(row: index, section: 0)], with: .automatic)
}
}
and update your cellForRowAt definition
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell", for: indexPath) as! TableViewCellCustom
cell.countLabel.text = "\(productData[indexPath.row].count)"
cell.productLabel.text = productData[indexPath.row].name
cell.minusButton.tag = indexPath.row
cell.plusButton.tag = indexPath.row
cell.delegate = self
return cell
}

How to show a parent view which is outside tableview and is scrollable?

I have a scenario where I need to show a parent view with shadow and corner radius containing a long list of reusable items. I used a tableView to display items. But I stuck at making my tableview expand as much as its contentSize. It works but not accurate. Any solutions?
Edit:
Desired result:
I used the following reference for self sizing tableview.
Self Sizing UITableView
I made a few modifications as below:
final class SelfSizedTableView: UITableView {
var maxHeight = CGFloat.greatestFiniteMagnitude
override func reloadData() {
super.reloadData()
self.invalidateIntrinsicContentSize()
self.layoutIfNeeded()
}
override var intrinsicContentSize: CGSize {
let height = min(contentSize.height, maxHeight)
let size = CGSize(width: contentSize.width, height: height)
return size
}
}
I used a parent tableView with a cell having my containerView and embedding this self sized tableView.
class MyContainerViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
// MARK: - IBOutlets
#IBOutlet weak var parentTableView: UITableView!
// MARK: - Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
}
private func estimateDataHeight() -> CGFloat {
let detailCellHeight: CGFloat = 32
let headingCellHeight: CGFloat = 43
let headings: CGFloat = headingCellHeight*2
let detailsHeight: CGFloat = detailCellHeight*4
let baseHeight = headings + detailsHeight
let membersHeight =
CGFloat(sectionsArray.count) * detailCellHeight
return baseHeight + membersHeight
}
}
// MARK: - UITableViewDataSource
extension MyContainerViewController {
func tableView(_ tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let id = String(describing: MyContainerTVCell.self)
guard let cell = tableView
.dequeueReusableCell(withIdentifier: id, for: indexPath)
as? MyContainerTVCell else {
return UITableViewCell()
}
cell.policyDetails = dataSource
// my cheat/trick doesn't work on large data.
DispatchQueue.main.asyncAfter(deadline: .now()+0.4) {
tableView.beginUpdates()
cell.tableView.layoutIfNeeded()
cell.tableView.reloadData() // the overridden one
tableView.endUpdates()
}
return cell
}
}
extension MyContainerViewController {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return estimateDataHeight()
}
}
My cell class which has the self size tableView and containerView:
class MyContainerTVCell: UITableViewCell, UITableViewDataSource, UITableViewDelegate {
// MARK: - IBOutlets
#IBOutlet weak var containerView: UIView!
#IBOutlet weak var shadowView: UIView!
#IBOutlet weak var tableView: SelfSizedTableView!
// MARK: - Properties
let titles = ["Email ID:", "Mobile Number:", "Address:", "ID: "] // first section data array
let moreData: [String] = [] // remaining reusable sections array
// no of subsequent sections for moreData array type
var numberOfSections: Int {
return 4
}
// MARK: -
var dataSource: MyDataSource!
// MARK: - Life Cycle
override func awakeFromNib() {
super.awakeFromNib()
setupView()
}
override func layoutSubviews() {
super.layoutSubviews()
}
// MARK: - Setup
func setupView() {
containerView.rounded(with: 10)
shadowView.layer.applyShadow()
tableView.dataSource = self
tableView.delegate = self
}
}
// MARK: - UITableViewDataSource
extension MyContainerTVCell {
func numberOfSections(in tableView: UITableView) -> Int {
return numberOfSections + 1
}
func tableView(_ tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
if section == 0 { return titles.count + 1 }
else if section == 1 { return moreData.count + 1 }
else { return moreData.count }
}
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let headerID = String(describing: MyHeaderTVCell.self)
let itemID = String(describing: MyItemTVCell.self)
switch indexPath.section {
case 0:
if indexPath.row == 0 {
guard let cell = tableView
.dequeueReusableCell(withIdentifier: headerID, for: indexPath)
as? MyHeaderTVCell else {
return UITableViewCell()
}
cell.titleLabel.text = dataSource.title
return cell
} else {
guard let cell = tableView
.dequeueReusableCell(withIdentifier: itemID, for: indexPath)
as? MyItemTVCell else {
return UITableViewCell()
}
let item = titles[indexPath.row-1]
cell.titleLabel.text = item
cell.separatorView.isHidden = true
let data: String
switch indexPath.row {
case 1:
data = dataSource.emailID
case 2:
data = dataSource.mobileNo
case 3:
data = dataSource.address
case 4:
data = dataSource.name
case 5:
data = dataSource.age
case 6:
data = dataSource.id
case 7:
data = dataSource.office
case 8:
data = dataSource.academic
default: data = String()
}
cell.detailLabel.text = data
return cell
}
case 1:
if indexPath.row == 0 {
guard let cell = tableView
.dequeueReusableCell(withIdentifier: headerID, for: indexPath)
as? MyHeaderTVCell else {
return UITableViewCell()
}
cell.titleLabel.text = "More Data"
return cell
} else {
guard let cell = tableView
.dequeueReusableCell(withIdentifier: itemID, for: indexPath)
as? MyItemTVCell else {
return UITableViewCell()
}
let sectionIndex = indexPath.section-1
guard sectionIndex <= numberOfSections-1,
let section = sectionsArray?[indexPath.section-1] else {
return UITableViewCell()
}
cell.titleLabel.text = moreData[indexPath.row-1]
cell.separatorView.isHidden = true
switch indexPath.row {
case 1:
cell.detailLabel.text = section.a
case 2:
cell.detailLabel.text = section.b
case 3:
cell.detailLabel.text = "\(section.c ?? 0)"
case 4:
cell.detailLabel.text = section.d
case 5:
cell.detailLabel.text = section.e
case 6:
cell.detailLabel.text = section.f
if indexPath.section < numberOfSections {
cell.separatorView.isHidden = false
}
default: break
}
return cell
}
default:
guard let cell = tableView
.dequeueReusableCell(withIdentifier: itemID, for: indexPath)
as? MyItemTVCell else {
return UITableViewCell()
}
let sectionIndex = indexPath.section-1
guard sectionIndex <= numberOfSections-1,
let section = sectionsArray?[indexPath.section-1] else {
return UITableViewCell()
}
cell.titleLabel.text = moreData[indexPath.row]
cell.separatorView.isHidden = true
switch indexPath.row {
case 0:
cell.detailLabel.text = section.a
case 1:
cell.detailLabel.text = section.b
case 2:
cell.detailLabel.text = "\(section.c ?? 0)"
case 3:
cell.detailLabel.text = section.d
case 4:
cell.detailLabel.text = section.e
case 5:
cell.detailLabel.text = section.f
if indexPath.section < numberOfSections {
cell.separatorView.isHidden = false
}
default: break
}
return cell
}
}
}
// MARK: - UITableViewDelegate
extension MyContainerTVCell {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 0 && indexPath.row == 0 { return 43 }
if indexPath.section == 1 && indexPath.row == 0 { return 43 }
return 32
}
}
Why would you want to expand tableView as much as its content size to make it scrollable, when tableView is already scrollable?
However, if you have some other content, aside from table, on the screen and you want them to scroll together, then you need to embed all your content into UIScrollView.
Then, make a height constraint for you tableView in xib/storyboard with any value.
Then you might do something like this:
// in your view controller
private var heightObservation: NSKeyValueObservation?
// called once, for example, in viewDidLoad()
private func setupTableView() {
...
observation = tableView.constraintFrameHeightToContentSizeHeight()
}
extension UITableView {
func constraintFrameHeightToContentSizeHeight() -> NSKeyValueObservation {
return observe(\.contentSize, changeHandler: { (tableView, _) in
tableView.heightConstraint?.constant = tableView.contentSize.height
})
}
}
// find height constraint
extension UIView {
var heightConstraint: NSLayoutConstraint? {
return constraints.first(where: { $0.firstAttribute == .height })
}
}
Don't forget to uncheck "Scrolling Enabled" in xib/storyboard for that table view.

Pass value to next view when label in Table view cell is tapped

would love to pass the value postArray[indexpath.row].creatorId when the label inside a tableview cell is tapped so it can be passed onto the next view controller so i can load the profile of that particular creator/user. I used custom cells, so how do i get the creator id based on the location of the label(username) selected.
//custom cell
class PostCell : UITableViewCell
{
#IBOutlet weak var timeAgoLabel: UILabel!
#IBOutlet weak var usernameLabel: UILabel!
#IBOutlet weak var profileImageView: UIImageView!
#IBOutlet weak var postImageView: UIImageView!
#IBOutlet weak var captionLabel: UILabel!
#IBOutlet weak var postStatsLabel: UILabel!
}
//do something when label is tapped
#objc func tapFunction(sender:UITapGestureRecognizer) {
//userClicked = creatorData
print(userClicked)
appDelegate.profileView()
print("tap working")
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0{
return 1
}else{
return postsArray.count
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//var returnCell: UITableViewCell!
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "statusCell", for: indexPath) as! statusCell
profilePicture = UserDefaults.standard.object(forKey: "userPic") as? String
if profilePicture != nil {
//load profile picture from library
let urlString = "https://test.com/uploads/profile-picture/"+(profilePicture)!
let profileURL = URL(string: urlString)
cell.statusProfilePic?.downloadedFrom(url: profileURL!)
} else {
print("you have no profile picture set")
}
return cell
} else {
if postsArray[indexPath.row].photos != nil{
let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell", for: indexPath) as! PostCell
if postsArray[indexPath.row].comments != nil {
comments = postsArray[indexPath.row].comments?.count
} else {
comments = 0
}
if postsArray[indexPath.row].like_list != nil {
likes = postsArray[indexPath.row].like_list?.count
}else{
likes = 0
}
//assign post id to PostID
postID = postsArray[indexPath.row].post_id
//make username clickable!
let tap = UITapGestureRecognizer(target: self, action: #selector(NewsfeedTableViewController.tapFunction))
cell.usernameLabel.isUserInteractionEnabled = true
cell.usernameLabel.addGestureRecognizer(tap)
cell.usernameLabel.text = postsArray[indexPath.row].fullname
cell.timeAgoLabel.text = postsArray[indexPath.row].data_created
cell.captionLabel.text = postsArray[indexPath.row].content
cell.timeAgoLabel.text = postsArray[indexPath.row].modified
//15 Likes 30 Comments 500 Shares
cell.postStatsLabel.text = "\(likes!) Likes \(comments!) Comments"
//load profile picture from library
let urlString = "https://test.com/uploads/profile-picture/"+(postsArray[indexPath.row].profile_pic_filename)!
let profileURL = URL(string: urlString)
cell.profileImageView.downloadedFrom(url: profileURL!)
//iterate through posts images images array
//load post picture from server library
var postImageName : String?
if postsArray[indexPath.row].photos != nil{
let postImage = postsArray[indexPath.row].photos
for postsImage in postImage!{
postImageName = postsImage.filename!
}
let urlPostImageString = "https://test.com/uploads/post-picture/"+(postImageName)!
let postsImageUrl = URL(string: urlPostImageString)
cell.postImageView.downloadedFrom(url: postsImageUrl!)
} else {
print("Post has no picture")
}
//return cell
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "NoImageCell", for: indexPath) as! NoImageTableViewCell
if postsArray[indexPath.row].comments != nil {
comments = postsArray[indexPath.row].comments?.count
} else {
comments = 0
}
if postsArray[indexPath.row].like_list != nil {
likes = postsArray[indexPath.row].like_list?.count
} else {
likes = 0
}
//make username clickable!
let tap = UITapGestureRecognizer(target: self, action: #selector(NewsfeedTableViewController.tapFunction))
cell.noImageUsername.isUserInteractionEnabled = true
cell.noImageUsername.addGestureRecognizer(tap)
cell.noImageUsername.text = postsArray[indexPath.row].fullname
cell.noImageTime.text = postsArray[indexPath.row].data_created
cell.noImagePost.text = postsArray[indexPath.row].content
cell.noImageTime.text = postsArray[indexPath.row].modified
//15 Likes 30 Comments 500 Shares
cell.noImageLikeAndComment.text = "\(likes!) Likes \(comments!) Comments"
//load profile picture from library
let urlString = "https://test.com/uploads/profile-picture/"+(postsArray[indexPath.row].profile_pic_filename)!
let profileURL = URL(string: urlString)
cell.noImageProfilePic.downloadedFrom(url: profileURL!)
return cell
}
}
}
Use this for example.
Implement didSelectRow() method and in it write something like this:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// this method works, when you taped cell. write here code of you need. Next code only example, which set user info to some VC and push it:
let controller = UserController as? UserController
if let controller = controller {
controller.user = users[indexPath.row]
self.navigationController?.pushViewController(controller, animated: true)
}
}
add this to your Cell's class:
func setTap() {
let tap = UITapGestureRecognizer(target: self, action: #selector(tapRecognized))
self.label.addGestureRecognizer(tap)
tap.numberOfTapsRequired = 1
}
#objc func tapRecognized(sender: UITapGestureRecognizer) {
// here your code of tap on label
print("label tapped")
}
Check on storyBoard is your label isUserInteractionEnabled? - set it to true. Inside tapRecodnized() method do what are you need. And you need to call method setTap() in your cell's method, which you call in tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell.
Update
Simple example. this code know what are you tapped. if you tap cell, but not label, add code of push some controller, else code of push another controller.
Cell's Class:
class MyTableViewCell: UITableViewCell {
#IBOutlet weak var label: UILabel!
var mainController: ViewController?
func setText(text: String) {
setTap()
label.text = text
}
func setTap() {
let tap = UITapGestureRecognizer(target: self, action: #selector(tapRecognized))
self.label.addGestureRecognizer(tap)
tap.numberOfTapsRequired = 1
}
#objc func tapRecognized(sender: UITapGestureRecognizer) {
if let mainController = mainController {
print("label tapped")
mainController.pushSomeVc(cell: self)
}
}
}
Code of main Class:
class ViewController: UIViewController {
#IBOutlet weak var myTableView: UITableView!
var array = ["1", "2", "3", "4", "5", "6"]
override func viewDidLoad() {
super.viewDidLoad()
}
func pushSomeVc(cell: MyTableViewCell) {
let row = myTableView.indexPath(for: cell)?.row
if let row = row {
// write here code of push controller, when label tapped. row property for get some user from array
print("push some vc with \(row)")
}
}
}
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = myTableView.dequeueReusableCell(withIdentifier: "cell") as? MyTableViewCell
if let cell = cell {
cell.setText(text: array[indexPath.row])
cell.mainController = self
}
return cell ?? UITableViewCell()
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
// write here code of push controller with comments
print("cell tapped: \(indexPath.row)")
}
}
I tested this code and it's work perfect

How do I increment/decrement a label value with two buttons pressed in tableview Swift [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I need swift code in my ViewController one table view, label, AddButton. In tableview 8 customcells are there, in each cell one label,(-, +) buttons are there. If I press '+' label value must increase while if I press '-' label value decrease, same way happen to each and every cell. Finally, if I press AddButton the total must be added and it displays in a label in viewcontroller Thanks, InAdvance. image
in viewController tableview methods
#IBOutlet var tableviewObj: UITableView!
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return 8
}
public func numberOfSections(in tableView: UITableView) -> Int // Default is 1 if not implemented
{
return 1
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
if indexPath.row == 0 {
let cell:firstTableViewCell = tableView.dequeueReusableCell(withIdentifier: "first") as! firstTableViewCell
return cell
}
else if indexPath.row == 1 {
let cell:secondTableViewCell = tableView.dequeueReusableCell(withIdentifier: "second") as! secondTableViewCell
return cell
}
else if indexPath.row == 2 {
let cell:thirdTableViewCell = tableView.dequeueReusableCell(withIdentifier: "third") as! thirdTableViewCell
return cell
}
else if indexPath.row == 3 {
let cell:fourthTableViewCell = tableView.dequeueReusableCell(withIdentifier: "fourth") as! fourthTableViewCell
return cell
}
else if indexPath.row == 4 {
let cell:fifthTableViewCell = tableView.dequeueReusableCell(withIdentifier: "fifth") as! fifthTableViewCell
return cell
}
else if indexPath.row == 5 {
let cell:sixthTableViewCell = tableView.dequeueReusableCell(withIdentifier: "sixth") as! sixthTableViewCell
return cell
}
else if indexPath.row == 6 {
let cell:seventhTableViewCell = tableView.dequeueReusableCell(withIdentifier: "seven") as! seventhTableViewCell
return cell
}else {
let cell:eighthTableViewCell = tableView.dequeueReusableCell(withIdentifier: "eight") as! eighthTableViewCell
return cell
}
}
#IBOutlet var labelObj: UILabel!
#IBAction func Total(_ sender: Any) {
// i need code here
}
class firstTableViewCell: UITableViewCell {
#IBOutlet var labelObj: UILabel!
var cur = 0
var str = ""
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
#IBAction func Minus(_ sender: Any) {
if (self.labelObj.text == "1") {
self.labelObj.text = String( 1)
}else
{
cur = Int(labelObj.text!)!
self.labelObj.text = String(cur - 1)
str = self.labelObj.text!
print(str)
}
}
#IBAction func Add(_ sender: Any) {
cur = Int(labelObj.text!)!
self.labelObj.text = String(cur + 1)
str = self.labelObj.text!
print(str)
}
Create a model to hold the value of the label in a cell-like below
struct Product {
var price = 0
}
We need to communicate from cell to viewcontroller so we need a protocol like a below
protocol CartSelection {
func addProductToCart(product : Product, atindex : Int)
}
I have created array to show in tableview. And I will pass the product to cell. So ViewController code is :
class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate,CartSelection {
#IBOutlet weak var totalLabel: UILabel!
var productArray = [Product]()
#IBOutlet weak var testTableview: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
for _ in 0...10{
productArray.append(Product(price: 1))
}
testTableview.allowsSelection = false
calculateTotal()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return productArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : TestTableViewCell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! TestTableViewCell
cell.product = productArray[indexPath.row]
cell.valueLabel.text = "\(cell.product.price)"
cell.productIndex = indexPath.row
cell.cartSelectionDelegate = self
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 75
}
#IBAction func addBtnPressed(_ sender: UIButton) {
}
func addProductToCart(product: Product, atindex: Int) {
productArray[atindex] = product
calculateTotal()
}
func calculateTotal()
{
var totalValue = 0
for objProduct in productArray {
totalValue += objProduct.price
}
self.totalLabel.text = "Total \(totalValue)"
}
}
and TableViewCell code like below :
class TestTableViewCell: UITableViewCell {
var product : Product!
private var counterValue = 1
var productIndex = 0
var cartSelectionDelegate: CartSelection?
#IBOutlet weak var valueLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
#IBAction func minusButton(_ sender: UIButton) {
if(counterValue != 1){
counterValue -= 1;
}
self.valueLabel.text = "\(counterValue)"
product.price = counterValue
cartSelectionDelegate?.addProductToCart(product: product, atindex: productIndex)
}
#IBAction func plusButton(_ sender: UIButton){
counterValue += 1;
self.valueLabel.text = "\(counterValue)"
product.price = counterValue
cartSelectionDelegate?.addProductToCart(product: product, atindex: productIndex)
}
}
Output will look like the screenshot below
Initial Stage
After changing value in cell

Increase/Decrease a value and display results in a Label inside a TableViewCell Swift Xcode

I have a ViewController with a TableView and a TableViewCell containing multiple sections and rows.
I have 2 button "plus" and "minus" and a label "totalLabel" in each row.
How can I get the value displayed in the label for each specific row when the user presses the + or - button?
for now when I run the app and press the + or - buttons only the totalLabel of the section 0/row 0 is working while random values just appear and disappear in the other sections/rows
my tableViewCell code :
import UIKit
protocol CommandeCellDelegate: class {
}
class CommandeCell: UITableViewCell {
weak var delegate : CommandeCellDelegate!
#IBOutlet weak var drinksLabel: UILabel!
#IBOutlet weak var priceLabel: UILabel!
#IBOutlet weak var totalLabel: UILabel!
#IBOutlet weak var plusButton: UIButton!
#IBOutlet weak var minusButton: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
here is my code for cellForRowAt :
class MenuViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, CommandeCellDelegate {
var count : Int = 0
var countValue : String!
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CommandeCell", for: indexPath) as! CommandeCell
cell.plusButton.tag = indexPath.section
cell.plusButton.tag = indexPath.row
cell.plusButton.addTarget(self, action: #selector(self.increaseValue), for: .touchUpInside)
cell.minusButton.tag = indexPath.section
cell.minusButton.tag = indexPath.row
cell.minusButton.addTarget(self, action: #selector(self.decreaseValue), for: .touchUpInside)
if indexPath.section == 0 {
let softInfo = softs[indexPath.row]
cell.drinksLabel?.text = softInfo.drinkName
cell.totalLabel?.text = // how to display countValue here?
let HappyHourStatus = partner!.barHHStatus
if case "0" = HappyHourStatus {
cell.priceLabel?.text = softInfo.drinkHHPrice
} else
if case "1" = HappyHourStatus {
cell.priceLabel?.text = softInfo.drinkPrice
}
}
else if indexPath.section == 1 {
let cocktailInfo = cocktails[indexPath.row]
cell.drinksLabel?.text = cocktailInfo.drinkName
cell.totalLabel?.text = // how to display countValue here?
let HappyHourStatus = partner!.barHHStatus
if case "0" = HappyHourStatus {
cell.priceLabel?.text = cocktailInfo.drinkHHPrice
} else
if case "1" = HappyHourStatus {
cell.priceLabel?.text = cocktailInfo.drinkPrice
}
}
return cell
}
and my funcs to increase or decrease the value :
func increaseValue(_ sender: UIButton) -> Int {
count = 1 + count
print(count)
countValue = "\(count)"
let rowToReload = IndexPath(row: sender.tag, section: sender.tag)
let rowsToReload: [Any] = [rowToReload]
tableView.reloadRows(at: rowsToReload as! [IndexPath], with: .automatic)
return count
}
func decreaseValue(_ sender: UIButton) -> Int {
if count == 0 {
print("Count zero")
} else {
count = count - 1
}
countValue = "\(count)"
let rowToReload = IndexPath(row: sender.tag, section: sender.tag)
let rowsToReload: [Any] = [rowToReload]
tableView.reloadRows(at: rowsToReload as! [IndexPath], with: .automatic)
return count
}
I have tried countless solutions but so far none is working - thank you for your help!
So your problem is this code
cell.plusButton.tag = indexPath.section
cell.plusButton.tag = indexPath.row
A tag can only store one value. So you are overriding the section with the row. So it is going to cause all sorts of weirdness. The better solution is to determine what cell you are targeting based on the button itself. Since you know what button was clicked you can convert the location of this button to a point on the table view. And then that point to a a particular index path.
So using your example code you can do something like below:
var softsCount: [Int] = []
var cocktailsCount: [Int] = []
override func viewDidLoad() {
super.viewDidLoad()
softsCount = Array(repeating: 0, count: softs.count) // Fill an array with 0
cocktailsCount = Array(repeating: 0, count: cocktails.count) // Fill an array with 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...
if indexPath.section == 0 {
...
cell.totalLabel?.text = "\(softsCount[indexPath.row])"
...
} else if indexPath.section == 1 {
...
cell.totalLabel?.text = "\(cocktailsCount[indexPath.row])"
...
}
...
}
func increaseValue(_ sender: UIButton) {
let pointInTable = sender.convert(sender.bounds.origin, to: tableView)
if let indexPath = self.tableView.indexPathForRow(at: pointInTable), let cell = tableView.cellForRow(at: indexPath) {
if indexPath.section == 0 {
softsCount[indexPath.row] += 1
cell.totalLabel?.text = "\(softsCount[indexPath.row])"
} else if indexPath.section == 1 {
cocktailsCount[indexPath.row] += 1
cell.totalLabel?.text = "\(cocktailsCount[indexPath.row])"
}
}
}
No sure why you are returning count. I am sure this is just a partial implementation. But the button should take care of the entire action including updating the label with the new count. You don't normally return values from button presses.
So updated the example to update the label with the current count. Since I am unable to see what your drinks object I made an assumption that the drinks class has a count parameter that starts at 0. This way each individual drink has a count assigned to it.

Resources