Select deselect the radio in uitableview section with array in ios swift - swift

In tableview have different section.
Want to add the radio button for all the section.
Each section have individual select and deselect in tableview.
In first section choice1,[show in fig]
Selected cheese means cheese want to select, next if user click bacon means cheese automatically deselect.
[Here using radio button SSRadioButton class for click action. Create a radio button in tableview cell. how to write the button action for radio button. or suggest any new way].
Each radio button want individual select and deselect. The same process for all the section in tableview. how is possible help me. Thanks advance.
my code:
var radioControllerChoice : SSRadioButtonsController = SSRadioButtonsController()
var radioControllerDip : SSRadioButtonsController = SSRadioButtonsController()
func numberOfSections(in tableView: UITableView) -> Int {
return table_data.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of rows in the section.
return table_data[section].menu_id.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell:CustomiseTableViewCell = tableView.dequeueReusableCell(withIdentifier: "Customise") as! CustomiseTableViewCell
cell.name.text?=table_data[indexPath.section].menu_name[indexPath.row]
print(table_data[indexPath.section].customize[indexPath.row])
switch indexPath.section {
case 2:
radioControllerChoice.addButton(cell.radioBtn)
radioControllerChoice.shouldLetDeSelect = false
case 3:
radioControllerDip.addButton(cell.radioBtn)
radioControllerDip.shouldLetDeSelect = false
switch Int(table_data[indexPath.section].customize[indexPath.row]) {
case 1:
cell.radioBtn.isHidden = false
default:
print("Invalid choose")
cell.radioBtn.addTarget(self, action: #selector(ViewController.didSelectButton), for: .touchUpInside)
cell.radioBtn.tag = indexPath.row
}
}
}
func didSelectButton(selectedButton: UIButton?)
{
/// need solution for button action help me..
}

You can use UIButton instead of SSRadioButton, and then you can change the image of button for checked and unchecked radio button.
Swift3.2:
CustomiseTableViewCell
import UIKit
protocol CustomTableViewCellDelegate {
func didToggleRadioButton(_ indexPath: IndexPath)
}
class CustomiseTableViewCell: UITableViewCell {
#IBOutlet weak var itemLabel: UILabel!
#IBOutlet weak var radioButton: UIButton!
var delegate: CustomTableViewCellDelegate?
func initCellItem() {
let deselectedImage = UIImage(named: "ic_radio_button_unchecked_white")?.withRenderingMode(.alwaysTemplate)
let selectedImage = UIImage(named: "ic_radio_button_checked_white")?.withRenderingMode(.alwaysTemplate)
radioButton.setImage(deselectedImage, for: .normal)
radioButton.setImage(selectedImage, for: .selected)
radioButton.addTarget(self, action: #selector(self.radioButtonTapped), for: .touchUpInside)
}
func radioButtonTapped(_ radioButton: UIButton) {
print("radio button tapped")
let isSelected = !self.radioButton.isSelected
self.radioButton.isSelected = isSelected
if isSelected {
deselectOtherButton()
}
let tableView = self.superview as! UITableView
let tappedCellIndexPath = tableView.indexPath(for: self)!
delegate?.didToggleRadioButton(tappedCellIndexPath)
}
func deselectOtherButton() {
let tableView = self.superview?.superview as! UITableView
let tappedCellIndexPath = tableView.indexPath(for: self)!
let indexPaths = tableView.indexPathsForVisibleRows
for indexPath in indexPaths! {
if indexPath.row != tappedCellIndexPath.row && indexPath.section == tappedCellIndexPath.section {
let cell = tableView.cellForRow(at: IndexPath(row: indexPath.row, section: indexPath.section)) as! CustomiseTableViewCell
cell.radioButton.isSelected = false
}
}
}
}
Call initCellItem method from UITableViewDataSource's delegate method:
// Your ViewController
let menuList = [ ["Cheese", "Bacon", "Egg"],
["Fanta", "Lift", "Coke"] ] // Inside your ViewController
var selectedElement = [Int : String]()
func didToggleRadioButton(_ indexPath: IndexPath) {
let section = indexPath.section
let data = menuList[section][indexPath.row]
if let previousItem = selectedElement[section] {
if previousItem == data {
selectedElement.removeValue(forKey: section)
return
}
}
selectedElement.updateValue(data, forKey: section)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell:CustomiseTableViewCell =
tableView.dequeueReusableCell(withIdentifier: "Customise") as! CustomiseTableViewCell
let item = menuList[indexPath.section][indexPath.row]
cell.itemLabel.text = item
if item == selectedElement[indexPath.section] {
cell.radioButton.isSelected = true
} else {
cell.radioButton.isSelected = false
}
cell.initCellItem()
cell.delegate = self
// Your logic....
return cell
}

Alternate way:
You can use simple UIButton instead of any third party library (SSRadioButton) and use it like:
Set the UIButton's image in default state to - circle (as in the screenshot)
Set the UIButton's image in selected state to - filled circle
UIButton's action event can be captured in a normal way like you do in any other case.
Something like this:
Let me know if you want to follow this approach or need any kind of help regarding this.

Related

Show hidden label by button click inside tableView Cell (expand/collapse cell)

I have a stackView(vertical) which contains labels and bottom description label is hidden by default. And I implemented an arrow button at the right side of the cell. By clicking the button, I just want to show the hidden description label and stackView should expand automatically and make cell bigger. This was my basic idea to implement expandable cell.
So this is the code I used to get desired results:
#objc func downArrowButtonClicked(_ sender: UIButton){
let indexPath = IndexPath(row: sender.tag, section: 0)
selectedIndex = indexPath
selectedCellIndex = sender.tag
isDescHidden = !isDescHidden
tableView.reloadRows(at: [indexPath], with: .automatic)
}
Above is the code for the button inside clicked cell. I went with the idea to reload that particular index. I created a variable named selectedCellIndex of in which I use in cellForRowAt method to make some changes.
I also had the implement some code in viewDidLayoutSubviews() as when I first clicked the cell wasn't getting expanded fully. here's that just in case:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let indexPath = selectedIndex
tableView.reloadRows(at: [indexPath ?? IndexPath(row: 0, section: 0)], with: .automatic)
}
And calling it in willDisplay method which finally fixed the cell expansion issue:
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
viewDidLayoutSubviews()
}
And here is my cellForRowAt function:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell", for: indexPath) as! CustomTableViewCell
if indexPath.row == 0 {
cell.lblTitle.text = "Title 1"
cell.lblDesc.text = "Desc 1"
}
else if indexPath.row == 1 {
cell.lblTitle.text = "Title 2"
cell.lblDesc.text = "Desc 2"
}
else {
cell.lblTitle.text = "Title 3"
cell.lblDesc.text = "Desc 3"
}
if selectedCellIndex != nil {
if isDescHidden == false {
if cell.isDescHidden == true {
cell.lblDesc.isHidden = false
cell.btnArrow.setImage(UIImage(systemName: "chevron.up"), for: .normal)
}
else {
cell.lblDesc.isHidden = true
cell.btnArrow.setImage(UIImage(systemName: "chevron.down"), for: .normal)
}
}
else {
if cell.isDescHidden == true {
cell.lblDesc.isHidden = true
cell.btnArrow.setImage(UIImage(systemName: "chevron.down"), for: .normal)
}
else {
cell.lblDesc.isHidden = false
cell.btnArrow.setImage(UIImage(systemName: "chevron.up"), for: .normal)
}
}
cell.isDescHidden = !cell.isDescHidden
}
cell.btnArrow.tag = indexPath.row
cell.btnArrow.addTarget(self, action: #selector(downArrowButtonClicked(_:)), for: .touchUpInside)
return cell
}
This approach gets too confusing as you can see from the above code. The isDescHidden variable is defined in both Main view controller as well as table view cell class and I was trying to use both to expand or collapse a particular cell. However first time it works but if I have 3 cells expanded, collapsing button click doesn't work for 1-2 clicks then works.
Is there a better approach for this kind of problem? Or is there any way I can directly set cell.isDescHidden value from #objc func downArrowButtonClicked(_ sender: UIButton) function? So I can use that in cellForRowAt function?
I would be glad if I could directly make changes to cell variables from that.
Use the following function for automatic height for rows and provided top and bottom constraints to your stackView
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
Here is my CustomCell
class CustomCell: UITableViewCell {
#IBOutlet weak var titleCell: UILabel!
#IBOutlet weak var detail: UILabel!
#IBOutlet weak var arrowButton: UIButton!
let upArrow = UIImage(systemName: "chevron.up.circle.fill")
let downArrow = UIImage(systemName: "chevron.down.circle.fill")
var onArrowClick: ((UIButton)->())!
#IBAction func handleArrowButton(sender: UIButton){
onArrowClick(sender)
}
func updateArrowImage(expandStatus: Bool){
arrowButton.setImage(expandStatus ? downArrow : upArrow, for: .normal)
}
}
For sample Data
let data = [
["Nothing", "description is very long description is very long description is very long description is very "],
["Nothing", "description is very long "],
["Nothing", "description is very long "],
["Nothing", "description is very long "],
["Nothing", "description is very long "]
]
var eachCellStatus: [Bool] = []
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
for _ in data {
eachCellStatus.append(true)
}
}
TableView methods are like this
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! CustomCell
cell.titleCell.text = data[indexPath.row][0]
cell.detail.text = data[indexPath.row][1]
cell.detail.isHidden = eachCellStatus[indexPath.row]
cell.updateArrowImage(expandStatus: self.eachCellStatus[indexPath.row])
cell.onArrowClick = { button in
self.eachCellStatus[indexPath.row].toggle()
cell.updateArrowImage(expandStatus: self.eachCellStatus[indexPath.row])
tableView.reloadRows(at: [indexPath], with: .automatic)
}
return cell
}
First create a model to show data into cell. You have to preserve the state of cell.
struct CellData {
var title: String
var details: String
var isExpanded: Bool
}
In CustomTableViewCell add a property for cellData and assign Outlets data from it. Also create a protocol to reload row from UIViewController
protocol CustomTableViewCellDelegate {
func reloadRow(sender: CustomTableViewCell, flag: Bool)
}
class CustomTableViewCell: UITableViewCell {
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var detailsLabel: UILabel!
#IBOutlet weak var showButton: UIButton!
var indexPath: IndexPath?
var delegate: CustomTableViewCellDelegate?
var data: CellData? {
didSet {
if let data = data {
if data.isExpanded == false {
detailsLabel.isHidden = true
showButton.setImage(UIImage(systemName: "chevron.down"), for: .normal)
}else {
detailsLabel.isHidden = true
showButton.setImage(UIImage(systemName: "chevron.up"), for: .normal)
}
titleLabel.text = data.title
detailsLabel.text = data.details
}
}
}
override func awakeFromNib() {
super.awakeFromNib()
titleLabel.text = nil
detailsLabel.text = nil
}
#IBAction func showButtonAction(_ sender: UIButton) {
if var data = data {
data.isExpanded.toggle()
delegate?.reloadRow(cell: self, flag: data.isExpanded)
}
}
}
In UIViewController add an array of CellData type. You may assign it's data in viewDidLoad() method.
var tableData: [CellData]
Modify numberOfRowsInSection() and cellForRow() method like bleow.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell", for: indexPath) as! CustomTableViewCell
cell.data = tableData[indexPath.row]
cell.delegate = self
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
Then confirm CustomTableViewCellDelegate protocol to UIViewController
extension ViewController: CustomTableViewCellDelegate {
func reloadRow(sender: CustomTableViewCell, isExpanded: Bool) {
guard let tappedIndexPath = tableView.indexPath(for: sender) else { return }
tableData[tappedIndexPath.row].isExpanded = isExpanded
tableView.reloadRows(at: [indexPath], with: UITableView.RowAnimation.automatic)
}
}

UIButton state changing while scrolling the tableview with multiple sections - Swift

I have multiple sections in my tableview with multiple custom cells(cell with radio button, cell with check box and cell with textfield). Problem is under section with radio button, only one radio button should be selectable under radio button section. After selecting, I have tried scrolling, multiple radio buttons are selected. Help much appreciated.
class RedioButtonCell: UITableViewCell {
var radioButtonDelegate: RedioCellDelegate?
var cellindexPath : IndexPath?
#IBOutlet weak var btnRediouttion: UIButton?
#IBOutlet weak var lblTitle: UILabel?
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
}
Cell for row method:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if ((qaArray[indexPath.section]["Que"] as! [String:String])["type"]!) == CONTROL
{
let cell = tableView.dequeueReusableCell(withIdentifier: "RedioButtonCell", for: indexPath) as! RedioButtonCell
cell.btnRediouttion?.tag = Int("\(indexPath.section)" + "\(indexPath.row)")!
cell.lblTitle!.text = String(describing: ansDetailArray[indexPath.row]["survey_answer"]!)
let deselectedImage = UIImage(named: "Radio_Unselected")?.withRenderingMode(.alwaysTemplate)
let selectedImage = UIImage(named: "radio_Selected")?.withRenderingMode(.alwaysTemplate)
btnRediouttion?.setImage(deselectedImage, for: .normal)
btnRediouttion?.setImage(selectedImage, for: .selected)
btnRediouttion?.addTarget(self, action: #selector(self.radioButtonTapped), for: .touchUpInside)
cell.cellindexPath = indexPath;
return cell
}
}
func radioButtonTapped(_ radioButton: UIButton) {
print("radio button tapped")
let isSelected = !(radioButton?.isSelected)!
radioButton?.isSelected = isSelected
if isSelected {
}
}
The tableView cells are reused ( happens when scrolling ) , so you need to keep track of the selected one by saving it's IndexPath and assign it inside cellForRowAt
//
declare this in your VC
var currentIndex:IndexPath?
//
class RadioButton:UIButton {
var indexPath:IndexPath
}
//
func radioButtonTapped(_ radioButton: RadioButton) {
self.currentIndex = radioButton.indexPath
}
//
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath == currentIndex {
// this should be selected
}
else {
// Deselect this
}
cell.radioButton.indexPath = indexPath
}

Swift Show Overlapping Button on TableViewCell

I have a button in a TableViewCell the overlaps the welcome TableViewCell. It looks fine when the view loads, however when I scroll down the tableview and scroll back up the button is cut off by the next tableviewcell.
I found a hack to make the background clear for the message TableViewCell, however, the bottom of the button is still not clickable.
Is there a way to set the priority of the button to be on top of the next?
HomeTableViewController.swift
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch indexPath.section {
case 0:
let cell = tableView.dequeueReusableCell(withIdentifier: "heroCell", for: indexPath) as! HeroTableViewCell
heroCell = cell
cell.separatorInset = UIEdgeInsets(top: 0, left: 10000, bottom: 0, right: 0)
return cell
case 1:
let cell = tableView.dequeueReusableCell(withIdentifier: "welcomeCell", for: indexPath) as! WelcomeTableViewCell
// Set Intro Name
if let user = Auth.auth().currentUser {
// User is signed in
// References to firebase
let userFS = Firestore.firestore().collection("users")
// Set the navigation title to users name
userFS.document(user.uid).getDocument { (document, error) in
if let userInfo = document {
let firstName = userInfo["firstName"] as! String
cell.introLabel.text = "Hey, \(firstName)"
} else {
print("User name does not exist")
}
}
}
return cell
case 2:
let cell = tableView.dequeueReusableCell(withIdentifier: "tripsCell", for: indexPath) as! TripTableViewCell
return cell
case 3:
let cell = tableView.dequeueReusableCell(withIdentifier: "suggestionsCell", for: indexPath) as! SuggestionTableViewCell
return cell
default:
let cell = tableView.dequeueReusableCell(withIdentifier: "popularsCell", for: indexPath) as! PopularTableViewCell
return cell
}
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
switch indexPath.section {
case 0: return 425
case 1: return 200
case 2: return 400
case 3: return 400
default: return 400
}
}
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 425
}
HeroTableViewCell.swift
class HeroTableViewCell: UITableViewCell {
// MARK: - Outlets
#IBOutlet weak var heroImage: UIImageView!
#IBOutlet weak var heroImageViewTopConstraint: NSLayoutConstraint!
#IBOutlet weak var planTripButton: SpringButton!
// MARK: - Variables
let notification = UINotificationFeedbackGenerator()
override func awakeFromNib() {
}
// MARK: - Actions
#IBAction func addTripButtonPressed(_ sender: UIButton) {
planTripButton.animation = "pop"
planTripButton.animate()
notification.notificationOccurred(.success)
}
}
If I understand your question correctly, you want + button to hover over the UITableView, so that it is clickable regardless of which cell the user has scrolled to?
In the image below, I have place my action button (the pencil in the top right of the view) at the same level in the view hierarchy as my tableView. So as the user scrolls, that button is always visible and the user can click at any time.
Please note where the Action Button sits relative to the tableView in the Document outline. It is at the same level. It is not a subview of the tableView.

Button state activates on wrong cells

I added button into cell-s and added action so if user touches it then the state is "Dislike" and if user touches again the state is "Like". However, the state applies to other cell buttons also. And if I scroll fast it just randomly picks what cell button should have the state. What causes this?
I call button with function inside cellForRowAt indexPath: IndexPath function like this:
cell.likeButton.addTarget(self, action: #selector(like), for: .touchUpInside)
And this is the function that is assigned to the button:
func like(sender: UIButton){
let section = 0
let row = sender.tag
let indexPath = IndexPath(row: row, section: section)
let cell: FeedTableViewCell = tableView.dequeueReusableCell(withIdentifier: "feedCell", for: indexPath) as! FeedTableViewCell
FIRDatabase.database().reference().child("posts").child(postsArray[indexPath.row].key).runTransactionBlock({ (currentData: FIRMutableData) -> FIRTransactionResult in
if var post = currentData.value as? [String : AnyObject], let uid = FIRAuth.auth()?.currentUser?.uid {
var stars : Dictionary<String, Bool>
stars = post["stars"] as? [String : Bool] ?? [:]
var starCount = post["starCount"] as? Int ?? 0
if let _ = stars[uid] {
// Unstar the post and remove self from stars
starCount -= 1
stars.removeValue(forKey: uid)
cell.likeButton.tag = indexPath.row
cell.likeButton.setTitle("Like", for: .normal)
cell.likeLabel.text = "\(starCount)"
} else {
// Star the post and add self to stars
starCount += 1
stars[uid] = true
cell.likeButton.tag = indexPath.row
cell.likeButton.setTitle("Dislike", for: .normal)
cell.likeLabel.text = "\(starCount)"
}
post["starCount"] = starCount as AnyObject?
post["stars"] = stars as AnyObject?
// Set value and report transaction success
currentData.value = post
return FIRTransactionResult.success(withValue: currentData)
}
return FIRTransactionResult.success(withValue: currentData)
}) { (error, committed, snapshot) in
if let error = error {
print(error.localizedDescription)
}
}
}
And like this I created the tableview with cells:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: FeedTableViewCell = tableView.dequeueReusableCell(withIdentifier: "feedCell", for: indexPath) as! FeedTableViewCell
cell.likeButton.tag = indexPath.row
cell.likeButton.addTarget(self, action: #selector(self.tapped), for: .touchUpInside)
}
What causes the state to transfer to the other buttons also? I even added tags so it detects the selected button. Is there something to do with cell reuse?
It adds likes to Firebase to the right one..
This is caused by reusing previous cells when scrolling and is the base mechanism of a table view.
You need to reset the state of your button on every call to cellForRowAtIndexPath.
Between let cell = ... and cell.starButton.addTarget you need to perform something like cell.starButton.deselect(), or .select(), based on the index path you're working on.
var selectindex : Int?
var selectedindex : NSMutableArray = NSMutableArray()
#IBOutlet var tableview: UITableView!
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("LikeCell", forIndexPath: indexPath)
let like: UIButton = (cell.viewWithTag(2) as! UIButton)
let comment: UIButton = (cell.viewWithTag(3) as! UIButton)
if selectedindex.containsObject(indexPath.row) {
like.setBackgroundImage(UIImage.init(named: "like.png"), forState: .Normal)
}else{
like.setBackgroundImage(UIImage.init(named: "like (1).png"), forState: .Normal)
}
comment.setBackgroundImage(UIImage(named: "chat.png"), forState: UIControlState.Normal)
like.addTarget(self, action: #selector(self.CloseMethod(_:event:)), forControlEvents: .TouchDown)
comment.addTarget(self, action: #selector(self.CloseMethod1(_:event:)), forControlEvents: .TouchDown)
return cell
}
#IBAction func CloseMethod(sender: UIButton, event: AnyObject) {
let touches = event.allTouches()!
let touch = touches.first!
let currentTouchPosition = touch.locationInView(self.tableview)
let indexPath = self.tableview.indexPathForRowAtPoint(currentTouchPosition)!
selectindex = indexPath.row
if selectedindex.containsObject(selectindex!) {
selectedindex.removeObject(selectindex!)
// call your firebase method for update database
}else{
selectedindex.addObject(selectindex!)
// call your firebase method for update database
}
self.tableview.reloadData()
}
Output :
https://www.dropbox.com/s/ub7wln5y6hdw0sz/like%20button.mov?dl=0
I think this issue is because of dequeuing your cell twice. you should try;
func like(sender: UIButton){
//your code ...
let cell: FeedTableViewCell = self.tableViewAddress.cellForRowAtIndexPath(indexPath) as! FeedTableViewCell
//Your code ...

Why my checkbox in custom cell shows different behaviour while selecting and scrolling in swift?

I have a xib view in which I took a tableView with a customcell xib. In this custom cell I have a checkbox button which behaves like check and uncheck using custom cell. But when ever I click the first cell checkbox as tick the multiple of 9th cell like 9th row cell, 18th row cell, .....also became ticked. and while scrolling the checkbox tick option is changing between cells. I am not able to know why this is happening..??
I have registered cell xib view as:
override func viewDidLoad() {
super.viewDidLoad()
//Register custom cell
let nib = UINib(nibName: "CustomOneCell", bundle: nil)
AddOnTableView.registerNib(nib, forCellReuseIdentifier: "addoncell")
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return ADDONITEMS.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:CustomOneCell = AddOnTableView.dequeueReusableCellWithIdentifier("addoncell") as! CustomOneCell
let item: AddOnItems = ADDONITEMS[indexPath.row]
cell.addOnName.text = item.name
cell.addOnPrice.text = "£\(item.price!)"
return cell
}
For checkbox I have added a custom class as below:
var isCheckedAddOnGlobal = Bool()
class AddOnCheckBox: UIButton {
let checkedImage = UIImage(named: "checkboxredtick.png")! as UIImage
let unCheckedImage = UIImage(named:"checkbox untick.png")!as UIImage
//bool property
var ischecked:Bool = false{
didSet{
//print(ischecked)
if ischecked == true{
self.setImage(checkedImage, forState: .Normal)
}else{
self.setImage(unCheckedImage, forState: .Normal)
}
}
}
override func awakeFromNib() {
self.addTarget(self, action:#selector(CheckBox.buttonClicked(_:)), forControlEvents: UIControlEvents.TouchUpInside)
self.ischecked = false
}
func buttonClicked(sender: UIButton) {
if (sender == self) {
if ischecked == true{
ischecked = false
isCheckedAddOnGlobal = false
}else{
ischecked = true
isCheckedAddOnGlobal = true
}
}
}
}
This is happening because you are reusing the TableViewCell, To solve your problem you can try something like this, first create an array of Int that give you selected row and use that array inside cellForRowAtIndexPath method.
var selectedItems = [Int]()
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:CustomOneCell = AddO nTableView.dequeueReusableCellWithIdentifier("addoncell") as! CustomOneCell
let item: AddOnItems = ADDONITEMS[indexPath.row]
cell.addOnName.text = item.name
cell.addOnPrice.text = "£\(item.price!)"
cell.checkBoxBtn.tag = indexPath.row
if (selectedItems.contains(indexPath.row)) {
cell.checkBoxBtn.setImage(UIImage(named:"checkbox untick.png"), forState: .Normal)
}
else {
cell.checkBoxBtn.setImage(UIImage(named: "checkboxredtick.png"), forState: .Normal)
}
cell.checkBoxBtn.addTarget(self, action:#selector(self.buttonClicked(_:)), forControlEvents: UIControlEvents.TouchUpInside)
return cell
}
func buttonClicked(sender: UIButton) {
if (self.selectedItems.contains(sender.tag)) {
let index = self.selectedItems.indexOf(sender.tag)
self.selectedItems.removeAtIndex(index)
}
else {
self.selectedItems.append(sender.tag)
}
self.tableView.reloadData()
}
Best way is on selecting cell call
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath) as! CustomOneCell
cell.buttonClicked()
}
and change buttonClicked method to
func buttonClicked() {
...
}
I would make an object, which contains the product information and a boolean, to check if the product has been selected or not.
If you make it this way, the checkmarks will appear correct. When you are scrolling on a tableview, then it loads the data everytime it shows new cells.
Right now, it only knows that the index etc. 9 is selected, and when you scroll down and load new cells, then the index 9 will be selected automatic again.
Try something like this:
Example
class Product {
var productName = "Test"
var isSelected: Bool = false
}
Under your cellForRowAtIndexPath
if product.isSelected == true {
cell.checkBoxBtn.setImage(UIImage(named:"checkbox untick.png"), forState: .Normal)
} else {
cell.checkBoxBtn.setImage(UIImage(named: "checkboxredtick.png"), forState: .Normal)
}