Setting check boxes on CustomTableViewCells - ios

I set a UIButton on CustomTableViewCells.
I would like to switch the image of UIButton when selected, but the default image does not change after I select again.
class CustomCell: UITableViewCell {
#IBOutlet weak var myButton: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
self.setup()
}
private func setup() {
self.myButton.setImage(UIImage(named: "checked"), for:.normal)
self.myButton.setImage(UIImage(named: "unchecked"), for:.highlighted)
}

You can use the property highlight and you can change this property when called didSelectItemAtIndexPath in the TableView
For Example:
func tableView(tableView: UITableView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
print("This is your Answer... \(indexPath.row)")
let newSelectedView = tableView.cellForItemAtIndexPath(indexPath) as! ChoiceCell
//important
newSelectedView.highlight.hidden = false
if self.selectedIndex != -1 && self.selectedIndex != indexPath.row {
let indexPathSelected = NSIndexPath(forRow: self.selectedIndex, inSection: 0)
let prevSelected = tableView.cellForItemAtIndexPath(indexPathSelected) as! ChoiceCell
//important
prevSelected.highlight.hidden = true
}
self.selectedIndex = indexPath.row
}

Related

In swift, how to manage two buttons in same custom tableview cell?

I am trying to manage two buttons in same custom tableview cell.
Added two buttons named Yes and No. If yes button is selected the No button will be inactive and Yes button became active.
Here is the image what I need
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell") as! TableViewCell
cell.yesButton.tag = 101
cell.noButton.tag = 102
cell.yesButton.addTarget(self, action: #selector(buttonClicked(sender:)), for: UIControl.Event.touchUpInside)
cell.noButton.addTarget(self, action: #selector(buttonClicked(sender:)), for: UIControl.Event.touchUpInside)
return cell
}
#objc func buttonClicked(sender: AnyObject) {
let buttonPosition = (sender as AnyObject).convert(CGPoint.zero, to: tableList)
let indexPath = tableList.indexPathForRow(at: buttonPosition)
if sender.tag == 101 {
if indexPath != nil {
print("Cell indexpath = \(String(describing: indexPath?.row))")
}
}
if sender.tag == 102 {
if indexPath != nil {
print("Cell indexpath = \(String(describing: indexPath?.row))")
}
}
}
Create a model to main the state of yesButton and noButton for each tableViewCell, i.e.
class Model {
var isYesSelected = false
var isNoSelected = false
}
Create a custom UITableViewCell with Outlets of yesButton and noButton.
Create a single #IBAction for both the buttons and handle their UI based on which button is tapped.
Also, use a buttonTapHandler to identify the row in which the button is tapped. It will be called everytime a button is tapped. We'll be setting this when creating the instance of TableViewCell in tableView(_:cellForRowAt:).
class TableViewCell: UITableViewCell {
#IBOutlet weak var yesButton: UIButton!
#IBOutlet weak var noButton: UIButton!
var buttonTapHandler: (()->())?
var model: Model?
override func prepareForReuse() {
super.prepareForReuse()
yesButton.backgroundColor = .gray
noButton.backgroundColor = .gray
}
func configure(with model: Model) {
self.model = model
self.updateUI()
}
#IBAction func onTapButton(_ sender: UIButton) {
model?.isYesSelected = (sender == yesButton)
model?.isNoSelected = !(sender == yesButton)
self.updateUI()
}
func updateUI() {
yesButton.backgroundColor = (model?.isYesSelected ?? false) ? .green : .gray
noButton.backgroundColor = (model?.isNoSelected ?? false) ? .green : .gray
}
}
UITableViewDataSource's tableView(_:cellForRowAt:) method goes like,
let numberOfCells = 10
var models = [Model]()
override func viewDidLoad() {
super.viewDidLoad()
(0..<numberOfCells).forEach { _ in
self.models.append(Model())
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return numberOfCells
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath) as! TableViewCell
cell.configure(with: models[indexPath.row])
cell.buttonTapHandler = {
print(indexPath.row)
}
return cell
}
To get the totalPoints, count the models with isYesSelected = true, i.e.
let totalPoints = models.reduce(0) { (result, model) -> Int in
if model.isYesSelected {
return result + 1
}
return 0
}
print(totalPoints)
Get that Button using your Tag like below and after that, you can change the value as per you want.
var tmpButton = self.view.viewWithTag(tmpTag) as? UIButton
Simple 3 step process...!!
Define Model Class
Prepare tableView Cell & handle actions
Set up tableView in view controller
Let's start implementation:
1) Define Model Class
In UI, we have a information like question & it's answer (Yes/No). So design model respectively.
//MARK:- Class Declaration -
class Question {
let questionText: String
var answerState: Bool?
init(question: String) {
self.questionText = question
}
}
2. Prepare tableView Cell & handle actions
Create a custom tableView cell with Question Label, Yes Button & No Button. Link that view with respected #IBOutlets & #IBActions.
import UIKit
class TableViewCell: UITableViewCell {
#IBOutlet weak var questionLabel: UILabel!
#IBOutlet weak var yesButton: UIButton!
#IBOutlet weak var noButton: UIButton!
var question: Question?
var toggle: Bool? {
didSet {
question?.answerState = toggle
//Do buttons operations like...
if let isToggle = toggle {
yesButton.backgroundColor = isToggle ? .green : .gray
noButton.backgroundColor = isToggle ? .gray : .green
} else {
yesButton.backgroundColor = .gray
noButton.backgroundColor = .gray
}
}
}
func prepareView(forQuestion question: Question) {
self.question = question
questionLabel.text = question.questionText
toggle = question.answerState
}
//Yes Button - IBAction Method
#IBAction func yesButtonTapped(_ sender: UIButton) {
toggle = true
}
//No Button - IBAction Method
#IBAction func noButtonTapped(_ sender: UIButton) {
toggle = false
}
}
3. Set up tableView in view controller
class ViewController: UIViewController {
//Prepare questions model array to design our tableView data source
let arrQuestions: [Question] = [Question(question: "Do you speak English?"), Question(question: "Do you live in Chicago?")]
}
//MARK:- UITableView Data Source & Delegate Methods -
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrQuestions.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let tableViewCell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell") as? TableViewCell else {
return UITableViewCell()
}
tableViewCell.prepareView(forQuestion: arrQuestions[indexPath.row])
return tableViewCell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80.0
}
}
Create basic tableView and configure dataSource functions
Create tableView cell with two buttons
Create cell class with buttons outlets and actions
Result of this code
Enjoy!

get indexPath of UITableViewCell on click of Button from Cell

I have a button (red color cross) in the UITableViewCell and on click of that button I want to get indexPath of the UITableViewCell.
Right now I am assigning tag to each of the button like this
cell.closeButton.tag = indexPath.section
and the on click of the button I get the indexPath.section value like this:
#IBAction func closeImageButtonPressed(sender: AnyObject) {
data.removeAtIndex(sender.tag)
tableView.reloadData()
}
Is this the right way of implementation or is there any other clean way to do this?
Use Delegates:
MyCell.swift:
import UIKit
//1. delegate method
protocol MyCellDelegate: AnyObject {
func btnCloseTapped(cell: MyCell)
}
class MyCell: UICollectionViewCell {
#IBOutlet var btnClose: UIButton!
//2. create delegate variable
weak var delegate: MyCellDelegate?
//3. assign this action to close button
#IBAction func btnCloseTapped(sender: AnyObject) {
//4. call delegate method
//check delegate is not nil with `?`
delegate?.btnCloseTapped(cell: self)
}
}
MyViewController.swift:
//5. Conform to delegate method
class MyViewController: UIViewController, MyCellDelegate, UITableViewDataSource,UITableViewDelegate {
//6. Implement Delegate Method
func btnCloseTapped(cell: MyCell) {
//Get the indexpath of cell where button was tapped
let indexPath = self.collectionView.indexPathForCell(cell)
print(indexPath!.row)
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MyCell") as! MyCell
//7. delegate view controller instance to the cell
cell.delegate = self
return cell
}
}
How to get cell indexPath for tapping button in Swift 4 with button selector
#objc func buttonClicked(_sender:UIButton){
let buttonPosition = sender.convert(CGPoint.zero, to: self.tableView)
let indexPath = self.tableView.indexPathForRow(at:buttonPosition)
let cell = self.tableView.cellForRow(at: indexPath) as! UITableViewCell
print(cell.itemLabel.text)//print or get item
}
Try with the best use of swift closures : Simple, Quick & Easy.
In cellForRowAtIndexPath method:
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCellIdentifier", for: indexPath) as! CustomCell
cell.btnTick.mk_addTapHandler { (btn) in
print("You can use here also directly : \(indexPath.row)")
self.btnTapped(btn: btn, indexPath: indexPath)
}
Selector Method for external use out of cellForRowAtIndexPath method:
func btnTapped(btn:UIButton, indexPath:IndexPath) {
print("IndexPath : \(indexPath.row)")
}
Extension for UIButton :
extension UIButton {
private class Action {
var action: (UIButton) -> Void
init(action: #escaping (UIButton) -> Void) {
self.action = action
}
}
private struct AssociatedKeys {
static var ActionTapped = "actionTapped"
}
private var tapAction: Action? {
set { objc_setAssociatedObject(self, &AssociatedKeys.ActionTapped, newValue, .OBJC_ASSOCIATION_RETAIN) }
get { return objc_getAssociatedObject(self, &AssociatedKeys.ActionTapped) as? Action }
}
#objc dynamic private func handleAction(_ recognizer: UIButton) {
tapAction?.action(recognizer)
}
func mk_addTapHandler(action: #escaping (UIButton) -> Void) {
self.addTarget(self, action: #selector(handleAction(_:)), for: .touchUpInside)
tapAction = Action(action: action)
}
}
In Swift 4 , just use this:
func buttonTapped(_ sender: UIButton) {
let buttonPostion = sender.convert(sender.bounds.origin, to: tableView)
if let indexPath = tableView.indexPathForRow(at: buttonPostion) {
let rowIndex = indexPath.row
}
}
You can also get NSIndexPath from CGPoint this way:
#IBAction func closeImageButtonPressed(sender: AnyObject) {
var buttonPosition = sender.convertPoint(CGPointZero, to: self.tableView)
var indexPath = self.tableView.indexPathForRow(atPoint: buttonPosition)!
}
Create a custom class of UIButton and declare a stored property like this and use it to retrieve assigned indexPath from callFroRowAtIndexPath.
class VUIButton: UIButton {
var indexPath: NSIndexPath = NSIndexPath()
}
This is the full proof solution that your indexPath will never be wrong in any condition. Try once.
//
// ViewController.swift
// Table
//
// Created by Ngugi Nduung'u on 24/08/2017.
// Copyright © 2017 Ngugi Ndung'u. All rights reserved.
//
import UIKit
class ViewController: UITableViewController{
let identifier = "cellId"
var items = ["item1", "2", "3"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.title = "Table"
tableView.register(MyClass.self, forCellReuseIdentifier: "cellId")
}
//Return number of cells you need
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return items.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath) as! MyClass
cell.controller = self
cell.label.text = items[indexPath.row]
return cell
}
// Delete a cell when delete button on cell is clicked
func delete(cell: UITableViewCell){
print("delete")
if let deletePath = tableView.indexPath(for: cell){
items.remove(at: deletePath.row)
tableView.deleteRows(at: [deletePath], with: .automatic)
}
}
}
class MyClass : UITableViewCell{
var controller : ViewController?
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setUpViews()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fatalError("init(coder:) has not been implemented")
}
let label : UILabel = {
let label = UILabel()
label.text = "My very first cell"
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let btn : UIButton = {
let bt = UIButton(type: .system)
bt.translatesAutoresizingMaskIntoConstraints = false
bt.setTitle("Delete", for: .normal)
bt.setTitleColor(.red, for: .normal)
return bt
}()
func handleDelete(){
controller?.delete(cell: self)
}
func setUpViews(){
addSubview(label)
addSubview(btn)
btn.addTarget(self, action: #selector(MyClass.handleDelete), for: .touchUpInside)
btn.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
label.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 16).isActive = true
label.widthAnchor.constraint(equalTo: self.widthAnchor , multiplier: 0.8).isActive = true
label.rightAnchor.constraint(equalTo: btn.leftAnchor).isActive = true
}
}
Here is a full example that will answer your question.
In your cellForRow:
#import <objc/runtime.h>
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
setAssociatedObject(object: YOURBUTTON, key: KEYSTRING, value: indexPath)
}
#IBAction func closeImageButtonPressed(sender: AnyObject) {
let val = getAssociatedObject(object: sender, key: KEYSTROKING)
}
Here val is your indexPath object, your can pass any object like you can assign pass cell object and get it in button action.
try this:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = (tableView.dequeueReusableCell(withIdentifier: "MainViewCell", forIndexPath: indexPath) as! MainTableViewCell)
cell.myButton().addTarget(self, action: Selector("myClickEvent:event:"), forControlEvents: .touchUpInside)
return cell
}
this function get the position of row click
#IBAction func myClickEvent(_ sender: Any, event: Any) {
var touches = event.allTouches()!
var touch = touches.first!
var currentTouchPosition = touch.location(inView: feedsList)
var indexPath = feedsList.indexPathForRow(atPoint: currentTouchPosition)!
print("position:\(indexPath.row)")
}
class MyCell: UICollectionViewCell {
#IBOutlet weak var btnPlus: UIButton!
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) ->
UITableViewCell {
cell.btnPlus.addTarget(self, action: #selector(increment_Action(sender:)),
for: .touchUpInside)
cell.btnPlus.tag = indexPath.row
cell.btnPlus.superview?.tag = indexPath.section
}
#objc func increment_Action(sender: UIButton) {
let btn = sender as! UIButton
let section = btn.superview?.tag ?? 0
let row = sender.tag
}

Pass variable to custom UITableViewCell from UIViewController

Here is how I use my custom UITableViewCell RunningTableViewCell inside UIViewController:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("myCell", forIndexPath: indexPath) as! RunningTableViewCell
//.......
cell.isTop = false
if(indexPath.row == 0){
cell.isTop = true
}
cell.isBottom = false
if(indexPath.row == myArray.count-1){
cell.isBottom = true
}
return cell
}
And here is my RunningTableViewCell class: (Cell's GUI is made inside storyboard)
class RunningTableViewCell: UITableViewCell {
//#IBOutlet ...
#IBOutlet weak var myButton: SomeButton!
var isTop: Bool?
var isBottom: Bool?
override func awakeFromNib() {
super.awakeFromNib()
print("result: \(self.isTop) \(self.isBottom)")
myButton.isTop = self.isTop
myButton.isBottom = self.isBottom
}
}
It returns result: nil nil
The usage of the result is: (SomeButton is a subview inside RunningTableViewCell)
class SomeButton: UIButton {
var isTop = false
var isBottom = false
override func drawRect(rect: CGRect) {
if(isTop){
// DO SOMETHING...
}
if(isBottom){
// DO SOMETHING...
}
}
}
So how can I pass data to RunningTableViewCell?
awakeFromNib is called right after the view and its subviews were allocated and initialized.
So your code from awakeFromNib in RunningTableViewCell for each cell is called before delegate method func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell. That is why isTop and isBottom are nil in awakeFromNib.
You can define method in RunningTableViewCell, which will load cell with this variables.
func load(isTop: Bool, isBottom: Bool) {
self.isTop = isTop
self.isBottom = isBottom
// Update cell UI as you wish
}
And finally rewrite delegate method func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell in your view controller.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("myCell", forIndexPath: indexPath) as! RunningTableViewCell
let isTop = indexPath.row == 0
let isBottom = indexPath.row == myArray.count-1
cell.load(isTop, isBottom: isBottom)
return cell
}
You need to override prepareForReuse in the cell. And remove it from tableView:indexPath:. So when you scroll the cell is going to be reused but the isBotton and isTop vars will be reseted.
override func prepareForReuse() {
self.isBottom = false
self.isTop = false
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("myCell", forIndexPath: indexPath) as! RunningTableViewCell
//.......
cell.isTop = false
if(indexPath.row == 0){
cell.isTop = true
cell.tag=100
}
cell.isBottom = false
if(indexPath.row == myArray.count-1){
cell.isBottom = true
cell.tag=200
}
return cell
}
and also get this like ...
class RunningTableViewCell: UITableViewCell {
//#IBOutlet ...
var isTop: Bool?
var isBottom: Bool?
override func awakeFromNib() {
super.awakeFromNib()
if (self.tag==100)
{
isTop=true
}
else if (self.tag==200) {
isBottom=true
}
else{
isTop=false
isBottom=false
}
print("result: \(self.isTop) \(self.isBottom)")
}
}
And also do using singleton methods...
You can resolve this issue by call custom method in your cell like,
inside UIViewController:
//.......
cell.isTop = false
if(indexPath.row == 0){
cell.isTop = true
}
cell.isBottom = false
if(indexPath.row == myArray.count-1){
cell.isBottom = true
}
cell.UpdateViews()
return cell
}
inside TableViewCell:
//#IBOutlet ...
var isTop: Bool?
var isBottom: Bool?
func updateViews() {
print("result: \(self.isTop) \(self.isBottom)")
}
Good luck!

how to uncheck uitableview cells using accessory checkmark

i have two sections
1.MapViewController
2.TypesTableViewController
when i run my app and call TypesTableViewController and when it opens it shows all cells selected i want it to be unchecked
please help me and check my code
1.MapViewController
class MapViewController: UIViewController {
#IBOutlet weak var mapCenterPinImage: UIImageView!
#IBOutlet weak var pinImageVerticalConstraint: NSLayoutConstraint!
var searchedTypes = ["bakery", "bar", "cafe", "grocery_or_supermarket", "restaurant"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "Types Segue" {
let navigationController = segue.destinationViewController as! UINavigationController
let controller = navigationController.topViewController as! TypesTableViewController
controller.selectedTypes = searchedTypes
controller.delegate = self
}
}
}
// MARK: - TypesTableViewControllerDelegate
extension MapViewController: TypesTableViewControllerDelegate {
func typesController(controller: TypesTableViewController, didSelectTypes types: [String]) {
searchedTypes = controller.selectedTypes.sort()
dismissViewControllerAnimated(true, completion: nil)
}
}
2.TypesTableViewController
protocol TypesTableViewControllerDelegate: class {
func typesController(controller: TypesTableViewController, didSelectTypes types: [String])
}
class TypesTableViewController: UITableViewController {
let possibleTypesDictionary = ["bakery":"Bakery", "bar":"Bar", "cafe":"Cafe", "grocery_or_supermarket":"Supermarket", "restaurant":"Restaurant"]
var selectedTypes: [String]!
weak var delegate: TypesTableViewControllerDelegate!
var sortedKeys: [String] {
return possibleTypesDictionary.keys.sort()
}
// MARK: - Actions
#IBAction func donePressed(sender: AnyObject) {
delegate?.typesController(self, didSelectTypes: selectedTypes)
}
// MARK: - Table view data source
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return possibleTypesDictionary.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("TypeCell", forIndexPath: indexPath)
let key = sortedKeys[indexPath.row]
let type = possibleTypesDictionary[key]!
cell.textLabel?.text = type
cell.imageView?.image = UIImage(named: key)
cell.accessoryType = (selectedTypes!).contains(key) ? .Checkmark : .None
return cell
}
// MARK: - Table view delegate
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
let key = sortedKeys[indexPath.row]
if (selectedTypes!).contains(key) {
selectedTypes = selectedTypes.filter({$0 != key})
} else {
selectedTypes.append(key)
}
tableView.reloadData()
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//toggle checkmark on and off
if tableView.cellForRow(at: indexPath)?.accessoryType == .checkmark {
tableView.cellForRow(at: indexPath)?.accessoryType = .none
}
else {
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
//add animation so cell does not stay selected
tableView.deselectRow(at: indexPath, animated: true)
}
Not sure what you are doing in your code. If you want to uncheck then change below line to
cell.accessoryType = (selectedTypes!).contains(key) ? .Checkmark : .None
to
cell.accessoryType = (selectedTypes!).contains(key) ? . None : . Checkmark
Updated:- second part of the answer to get only checkmark cells,
change as below
#IBAction func donePressed(sender: AnyObject) {
let rowCount = tableView.numberOfRowsInSection(0)
selectedTypes.removeAll()
for var index = 0; index < rowCount; ++index {
let cell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: index, inSection: 0)) as! YourCell
if cell.accessoryType = .Checkmark{
let key = sortedKeys[index]
selectedTypes.append(key)
}
delegate?.typesController(self, didSelectTypes: selectedTypes)
}
}

Stepper on tableview cell (swift)

I put stepper both outlets and action into tableview cell and using protocol delegate to connect it to tableview. When i tapped stepper in first row, stepper value appear normaly in first row but its also appear in some random row. how to fix this?
TableViewCell
protocol ReviewCellDelegate{
func stepperButton(sender: ReviewTableViewCell)
}
class ReviewTableViewCell: UITableViewCell {
#IBOutlet weak var countStepper: UIStepper!
#IBOutlet weak var stepperLabel: 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 stepperButtonTapped(sender: UIStepper) {
if delegate != nil {
delegate?.stepperButton(self)
stepperLabel.text = "x \(Int(countStepper.value))"
}
}
ViewController
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "reviewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! ReviewTableViewCell
var imageView: UIImageView?
let photoG = self.photos[indexPath.row]
imageView = cell.contentView.viewWithTag(1) as? UIImageView
//let layout = cell.goodiesImage
let tag = indexPath.row // +1
cell.tag = tag
photoG.fetchImageWithSize(CGSize(width: 1000, height: 1000), completeBlock: { image, info in
if cell.tag == tag {
imageView?.image = image
cell.goodiesImage.image = image
}
})
func stepperButton(sender: ReviewTableViewCell) {
if let indexPath = tableView.indexPathForCell(sender){
print(indexPath)
}
}
Reset the value of stepper while loading your cell. you can reset the cell property values in cell's prepareForReuse method. add the following method in your ReviewTableViewCell class.
override func prepareForReuse()
{
super.prepareForReuse()
countStepper.value = 0.0
}
In tableViewCell VC:
1 - add these field
var cellDelegate: cellProtocol?
var index: IndexPath?
2 - then add this in the delegate:
func onStepperClick(index: Int, sender: UIStepper)
3 - when you have dragged your stepper over as an action use this:
#IBAction func cellStepper(_ sender: UIStepper) {
cellDelegate?.onStepperClick(index: (index?.row)!, sender: sender)
sender.maximumValue = 1 //for incrementing
sender.minimumValue = -1 //for decrementing
//this will make sense later
}
In ViewController
1 - add these to the tableView function that has the cellAtRow variable.
cell.cellDelegate = self
cell.index = indexPath
2 - Use this instead of your stepperButton function
func onStepperClick(index: Int, sender: UIStepper) {
print(index)
if sender.value == 1.0{
//positive side of stepper was pressed
}else if sender.value == -1.0{
//negative side of stepper was pressed
}
sender.value = 0 //resetting to zero so sender.value produce different values on plus and minus
}
Hope this works for you
As mentioned by #A-Live, your component is being reused and so need to be updated.
So in your view controller:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "reviewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! ReviewTableViewCell
var imageView: UIImageView?
let photoG = self.photos[indexPath.row]
imageView = cell.contentView.viewWithTag(1) as? UIImageView
//let layout = cell.goodiesImage
let tag = indexPath.row // +1
cell.tag = tag
photoG.fetchImageWithSize(CGSize(width: 1000, height: 1000), completeBlock: { image, info in
if cell.tag == tag {
imageView?.image = image
cell.goodiesImage.image = image
}
})
cell.countStepper.value = XXX[indexPath.row].value; //Here you update your view
cell.stepperLabel.text = "x \(Int(cell.countStepper.value))" //And here
And
func stepperButton(sender: ReviewTableViewCell) {
if let indexPath = tableView.indexPathForCell(sender){
print(indexPath)
XXX[sender.tag].value = sender.counterStepper.value //Here you save your updated value
}
NOTE:
1.MY Cell class is just normal..All changes are in viewcontroller class
2.I have taken stepper and over it added ibAddButton with same constraint as ibStepper
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()
}

Resources