5
votes

i am new to ios swift 2.2 . I tried to create one table view with custom cell xib. and i am populating some data in my table view. And also i added one custom check box button. And i am creating separate class for that check box button. Now when i click only on my button in my customcell.xib .But when i tap on my cell, my check box are not changing. i need to have both. When i click on my button it should change to check and uncheck image. When i tap on my cell also i need to change my button to check or uncheck image

And when i scroll down and again come back to top, my checked images are automatically chnaged to normalcheck box.

i need to do some action , so for that. When i tap on any cell my check box should check and uncheck.And alos i need to know which row cell has checked image . So that i can perform some action for my checked image row cell alone.

here is my custom check box class:

import UIKit

class CheckBoxButton: UIButton {

    // Images
    let checkedImage = UIImage(named: "CheckBoxChecked")! as UIImage
    let uncheckedImage = UIImage(named: "CheckBoxUnChecked")! as UIImage

    // Bool property
    var isChecked: Bool = false {
        didSet{
            if isChecked == true {
                self.setImage(checkedImage, forState: .Normal)
            } else {
                self.setImage(uncheckedImage, forState: .Normal)
            }
        }
    }

    override func awakeFromNib() {
        self.addTarget(self, action: #selector(CheckBoxButton.buttonClicked(_:)), forControlEvents: UIControlEvents.TouchUpInside)
        self.isChecked = false
    }

    func buttonClicked(sender: UIButton) {
        if sender == self {
            if isChecked == true {
                isChecked = false
            } else {
                isChecked = true
            }
        }
    }

}

Cutom cell.xib class:

import UIKit

class FavCell: UITableViewCell {

    @IBOutlet weak var FLabel1: UILabel!
    @IBOutlet weak var FLabel2: UILabel!

    @IBOutlet weak var checkbox: CheckBoxButton!
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }



    @IBAction func checkboxpress(sender: AnyObject) {
    }



}

my viewcontroller.swift

import UIKit

class FavVC: UIViewController {

    @IBOutlet weak var FavTableView: UITableView!

    //var FData = [FavouritesData]()

    var arrDict :NSMutableArray=[]

    let cellSpacingHeight: CGFloat = 5  // cell spacing from each cell in table view

    override func viewDidLoad() {

        super.viewDidLoad()

        self.jsonParsingFromURL()

        let nib = UINib(nibName:"FavCell", bundle: nil)

        FavTableView.registerNib(nib, forCellReuseIdentifier: "FCell")

    }
// web services method
    func jsonParsingFromURL ()
    {
//        let token = NSUserDefaults.standardUserDefaults().valueForKey("access_token") as? String

        let url = NSURL(string: "som url")

        let session = NSURLSession.sharedSession()

        let request = NSURLRequest(URL: url!)

        let dataTask = session.dataTaskWithRequest(request) { (data:NSData?, response:NSURLResponse?, error:NSError?) -> Void in
            // print("done, error: \(error)")

            if error == nil
            {

                dispatch_async(dispatch_get_main_queue())
                {
                    self.arrDict=(try! NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)) as! NSMutableArray
                    if (self.arrDict.count>0)
                    {
                        self.FavTableView.reloadData()
                    }
                }

            }


        }
        dataTask.resume()
}
 func numberOfSectionsInTableView(tableView: UITableView) -> Int
    {
//        return self.FData.count
        return self.arrDict.count
    }


    // number of rows
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    {
        return 1
    }

    // height for each cell
    func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
    {
        return cellSpacingHeight
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
    {

        let cell:FavCell = self.FavTableView.dequeueReusableCellWithIdentifier("FCell") as! FavCell
        cell.FLabel1.text=arrDict[indexPath.section] .valueForKey("favourite_name") as? String
        cell.FLabel2.text=arrDict[indexPath.section] .valueForKey("favourite_address") as? String
        return cell

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

please help me out.

Thanks in advance

3
use different state for selected and unselected checkbox images for make task easierEI Captain v2.0
then, if i tap my cell does it will change??user5513630
in didSelectRowatindexpath manage this selected and unselected state of checkboxEI Captain v2.0
Your issue solved by @EL Captain comment?Milan V.
Can user select multiple cell or at a time only one checkbox can be enabled?Arun Gupta

3 Answers

8
votes

In order to solve your issue, as @El Capitan mentioned, you will need to use the didSelectRowAtIndexPath method to change its states. Your codes should look something along the lines of this:

// Declare a variable which stores checked rows. UITableViewCell gets dequeued and restored as you scroll up and down, so it is best to store a reference of rows which has been checked
var rowsWhichAreChecked = [NSIndexPath]()

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
      let cell:FavCell = tableView.cellForRowAtIndexPath(indexPath) as! FavCell
      // cross checking for checked rows
      if(rowsWhichAreChecked.contains(indexPath) == false){
         cell.checkBox.isChecked = true
         rowsWhichAreChecked.append(indexPath) 
      }else{
         cell.checkBox.isChecked = false
         // remove the indexPath from rowsWhichAreCheckedArray
         if let checkedItemIndex = rowsWhichAreChecked.indexOf(indexPath){
            rowsWhichAreChecked.removeAtIndex(checkedItemIndex)
         }
      }
}

To redisplay cells which have been checked before after scrolling the rows out of view, at your cellForRowAtIndexPath, perform the same checking against rowsWhichAreChecked array and set its states accordingly.

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

let cell:FavCell = self.FavTableView.dequeueReusableCellWithIdentifier("FCell") as! FavCell
cell.FLabel1.text=arrDict[indexPath.section] .valueForKey("favourite_name") as? String
cell.FLabel2.text=arrDict[indexPath.section] .valueForKey("favourite_address") as? String


   if(rowsWhichAreChecked.contains(indexPath) == false){
         cell.checkBox.isChecked = true
    }else{
        cell.checkBox.isChecked = false
    }
  }
    return cell           
}

EDITED ANSWER

I have got your code to work but I had to make some modifications to your Checkbox class and ViewController

Checkbox.swift

class CheckBoxButton: UIButton {

    // Images
    let checkedImage = UIImage(named: "CheckBoxChecked")! as UIImage
    let uncheckedImage = UIImage(named: "CheckBoxUnChecked")! as UIImage

    // Bool property
    var isChecked: Bool = false {
        didSet{
            if isChecked == true {
                self.setImage(uncheckedImage, forState: .Normal)
            } else {
                self.setImage(checkedImage, forState: .Normal)
            }
        }
    }

    override func awakeFromNib() {
        self.userInteractionEnabled = false
//        self.addTarget(self, action: #selector(CheckBoxButton.buttonClicked(_:)), forControlEvents: UIControlEvents.TouchUpInside)
//        self.isChecked = false
    }

    func buttonClicked(sender: UIButton) {
        if sender == self {
            if isChecked == true {
                isChecked = false
            } else {
                isChecked = true
            }
        }
    }

}

ViewController.swift

class FavVC: UIViewController, UITableViewDelegate, UITableViewDataSource {


    @IBOutlet weak var FavTableView: UITableView!


    var rowsWhichAreChecked = [NSIndexPath]()

    //var FData = [FavouritesData]()

    var arrDict :NSMutableArray=[]

    let cellSpacingHeight: CGFloat = 5  // cell spacing from each cell in table view

    override func viewDidLoad() {

        self.FavTableView.delegate = self
        self.FavTableView.dataSource = self

        super.viewDidLoad()

        self.jsonParsingFromURL()

        let nib = UINib(nibName:"FavCell", bundle: nil)

        FavTableView.registerNib(nib, forCellReuseIdentifier: "FCell")

    }

    // web services method
    func jsonParsingFromURL ()
    {
//        let token = NSUserDefaults.standardUserDefaults().valueForKey("access_token") as? String

        let url = NSURL(string: "some url")

        let session = NSURLSession.sharedSession()

        let request = NSURLRequest(URL: url!)

        let dataTask = session.dataTaskWithRequest(request) { (data:NSData?, response:NSURLResponse?, error:NSError?) -> Void in
            // print("done, error: \(error)")

            if error == nil
            {

                dispatch_async(dispatch_get_main_queue())
                {
                    self.arrDict=(try! NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)) as! NSMutableArray
                    if (self.arrDict.count>0)
                    {
                        self.FavTableView.reloadData()
                    }
                }

            }


        }
        dataTask.resume()

//        
//        let StringUrl = "http"+token!

//        let url:NSURL = NSURL(string: StringUrl)!

//        if let JSONData = NSData(contentsOfURL: url)
//        {
//            if let json = (try? NSJSONSerialization.JSONObjectWithData(JSONData, options: [])) as? NSDictionary
//            {
//                for values in json
//                {
//                    self.FData.append()
//                }

//                if let reposArray = json["data"] as? [NSDictionary]
//                {
//                    
//                    for item in reposArray
//                    {
//                        let itemObj = item as? Dictionary<String,AnyObject>
//                        
//                        let b_type = itemObj!["business_type"]?.valueForKey("type")
//                        
//                        //self.Resultcount.text = "\(b_type?.count) Results"
//                        
//                        if (b_type as? String == "Taxis")
//                        {
//                            
//                            self.FData.append(FavouritesData(json:item))
//                            
//                        }
//                    }
//                }

//            }
//        }

    }

    func numberOfSectionsInTableView(tableView: UITableView) -> Int
    {
//        return self.FData.count
        return self.arrDict.count
    }


    // number of rows
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    {
        return 1
    }

    // height for each cell
    func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
    {
        return cellSpacingHeight
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
    {

        let cell:FavCell = self.FavTableView.dequeueReusableCellWithIdentifier("FCell") as! FavCell
        cell.FLabel1.text=arrDict[indexPath.section] .valueForKey("favourite_name") as? String
        cell.FLabel2.text=arrDict[indexPath.section] .valueForKey("favourite_address") as? String

        let isRowChecked = rowsWhichAreChecked.contains(indexPath)

        if(isRowChecked == true)
        {
            cell.checkbox.isChecked = true
            cell.checkbox.buttonClicked(cell.checkbox)
        }else{
            cell.checkbox.isChecked = false
            cell.checkbox.buttonClicked(cell.checkbox)
        }

    return cell
}

    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        let cell:FavCell = tableView.cellForRowAtIndexPath(indexPath) as! FavCell
        // cross checking for checked rows
        if(rowsWhichAreChecked.contains(indexPath) == false){
            cell.checkbox.isChecked = true
            cell.checkbox.buttonClicked(cell.checkbox)
            rowsWhichAreChecked.append(indexPath)
        }else{
            cell.checkbox.isChecked = false
            cell.checkbox.buttonClicked(cell.checkbox)
            // remove the indexPath from rowsWhichAreCheckedArray
            if let checkedItemIndex = rowsWhichAreChecked.indexOf(indexPath){
                rowsWhichAreChecked.removeAtIndex(checkedItemIndex)
            }
        }
    }


    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}
0
votes
 {
        let cell:FilterTableViewCell = tableView.dequeueReusableCell(withIdentifier: "filtercell", for: indexPath) as! FilterTableViewCell

        // Configure the cell...
        cell.lblCategory?.attributedText = FontAttributes.sharedInstance.AttributesString(message: self.filterArray[indexPath.row], color: Textcolor)

        cell.BtnIndex?.addTarget(self, action: #selector(checkMarkTapped(_ :)), for: .touchUpInside)
        cell.BtnIndex?.tag = indexPath.row


        let rowid = indexPath.row
        let found = rowsWhichAreChecked.filter{$0.rowId == rowid}.count > 0
        if found
        {
             cell.BtnIndex?.setImage(checkedImage, for: .normal)
        }
        else
        {
             cell.BtnIndex?.setImage(uncheckedImage, for: .normal)

        }
        return cell
    }

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {


        let cell:FilterTableViewCell = tableView.cellForRow(at: indexPath) as! FilterTableViewCell



        let rowid = indexPath.row

       let found = rowsWhichAreChecked.filter{$0.rowId == rowid}.count > 0

        if found
        {
            tempArrayFordelete = rowsWhichAreChecked
            for obj in tempArrayFordelete
            {
                if let index = rowsWhichAreChecked.index(where: { $0.rowId == obj.rowId }) {
                    // removing item
                    rowsWhichAreChecked.remove(at: index)
                    cell.BtnIndex?.setImage(uncheckedImage, for: .normal)
                }
            }
        }
        else
        {

            cell.BtnIndex?.setImage(checkedImage, for: .normal)
            let objrowId = selectedIndex(rowId: indexPath.row)
            rowsWhichAreChecked.append(objrowId)
        }




    }
0
votes

It gives me a great pleasure to inform you all that solve above issue

Resolving Issue Is

  1. CheckBox Functionality
  2. RadioButton Functionality
  3. ReuseCell(tableView.dequeueReusableCell)//Also solve selected cell position issue.

Tested Code

  • Swift 5
  • iOS 12.2

Here is my code

import UIKit

class countrySelection:UITableViewCell{
     @IBOutlet weak var imgFlag: UIImageView!
     @IBOutlet weak var lblCountryName: UILabel!
     @IBOutlet weak var btnSelection: UIButton!
}

class ViewController: UIViewController {

    var listingDict=[[String:String]]()

    var radioOption:Int?// Only used :: if u are 2. RadioButton Functionality implement

    @IBOutlet weak var tableView: UITableView!
    override func viewDidLoad() {
        super.viewDidLoad()
    
        tableView.dataSource=self
        tableView.delegate=self
    
        fillCountryData()
        // Do any additional setup after loading the view.
    }

    func fillCountryData(){
        self.fillJsonData(imgName: "india_flag", countryName: "India")
        self.fillJsonData(imgName: "pakistan_flag", countryName: "Pakistan")
        self.fillJsonData(imgName: "israel_flag", countryName: "Israel")
        self.fillJsonData(imgName: "albania_flag", countryName: "Albania")
        self.fillJsonData(imgName: "america_flag", countryName: "America")
        self.fillJsonData(imgName: "belize_flag", countryName: "Belize")
        self.fillJsonData(imgName: "brunei_flag", countryName: "Brunei")
        self.fillJsonData(imgName: "comoros_flag", countryName: "Comoros")
        self.fillJsonData(imgName: "congo_flag", countryName: "Congo")
        self.fillJsonData(imgName: "ecuador_flag", countryName: "Ecuador")
        self.fillJsonData(imgName: "haiti_flag", countryName: "Haiti")
        self.fillJsonData(imgName: "jamaica_flag", countryName: "Jamaica")
        self.fillJsonData(imgName: "kenya_flag", countryName: "Kenya")
        self.fillJsonData(imgName: "mali_flag", countryName: "Mali")
    
        self.tableView.reloadData()
    }

    func fillJsonData(imgName:String,countryName:String){
        var dictData=[String:String]()
        dictData["img"]=imgName
        dictData["country"]=countryName
        dictData["check"]="false"
        listingDict.append(dictData)
    }

}

extension ViewController:UITableViewDataSource,UITableViewDelegate{

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return listingDict.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell=tableView.dequeueReusableCell(withIdentifier: "countrySelection") as! countrySelection
        let dictVal=listingDict[indexPath.row]
        cell.lblCountryName.text=dictVal["country"]
        cell.imgFlag.image=UIImage(named:dictVal["img"]!)
    
        /*//Check Box Functionality
        if dictVal["check"] == "false"{
            cell.btnSelection.setImage(UIImage(named: "checkbox_UnSelect"), for: .normal)
        } else{
            cell.btnSelection.setImage(UIImage(named: "checkbox_Select"), for: .normal)
        }*/
    
        //RadioButton Functionality
        if radioOption==indexPath.row{
            listingDict[indexPath.row]["check"]="true"
            cell.btnSelection.setImage(UIImage(named: "radioButton_Select"), for: .normal)
        } else{
            listingDict[indexPath.row]["check"]="false"
            cell.btnSelection.setImage(UIImage(named: "radioButton_UnSelect"), for: .normal)
        }
    
        return cell
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        /*//CheckBox Functionality
        if listingDict[indexPath.row]["check"]=="true"{
            listingDict[indexPath.row]["check"]="false"
        } else{
            listingDict[indexPath.row]["check"]="true"
        }*/
        //RadioButton Functionality
        print("RadioButton",listingDict)
        if listingDict[indexPath.row]["check"]=="true"{
            radioOption=nil
        } else{
            radioOption=indexPath.row
        }
    
        self.tableView.reloadData()
    }
}