Multiple checkmark in Tableview in swift3 - ios

How to do the multiple checkmark in tableview. I need to select the multiple checkmark in tableview and what are the checkmarks I need to select to place the multiple values in label.
Example player1,player2,player3 in label
here is my code
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return TypeOfAccountArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// let cell = tableView.dequeueReusableCellWithIdentifier("reuseIdentifier", forIndexPath: indexPath) as! UITableViewCell
let cell:TypeofAccountCell=tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TypeofAccountCell
cell.Uertype_lbl.text=TypeOfAccountArray[indexPath.row]
cell.selectionStyle = UITableViewCellSelectionStyle.none;
cell.Uertype_lbl.font = UIFont(name:"Roboto-Regular", size:13)
cell.Uertype_lbl.adjustsFontSizeToFitWidth = true
if (selectedIndex == indexPath as NSIndexPath?) {
cell.checkmarkbtn.setImage(UIImage(named: "checkmark.png"),for:UIControlState.normal)
} else {
cell.checkmarkbtn.setImage(UIImage(named: "uncheckmark.png"),for:UIControlState.normal)
}
// Configure the cell...
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath as IndexPath, animated: true)
let row = indexPath.row
print(TypeOfAccountArray[row])
selectedIndex = indexPath as NSIndexPath?
self.Type_of_account_txt.text = (TypeOfAccountArray[row])
self.Type_account_view.isHidden = true
tableView.reloadData()
}

Change your selectedindex to hold array of index path var selectedIndexes = [IndexPath](), on your cell xib, set your checkmark image on button selected stated and uncheckmark image on normal status and use the below code.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return TypeOfAccountArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:TypeofAccountCell=tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TypeofAccountCell
cell.Uertype_lbl.text=TypeOfAccountArray[indexPath.row]
cell.selectionStyle = UITableViewCellSelectionStyle.none;
cell.Uertype_lbl.font = UIFont(name:"Roboto-Regular", size:13)
cell.Uertype_lbl.adjustsFontSizeToFitWidth = true
// Configure the cell...
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath as IndexPath, animated: true)
let cell:TypeofAccountCell=tableView.cellForRow(at: indexPath) as! TypeofAccountCell
if selectedIndexes.contains(indexPath)
{
cell.checkmarkbtn.isSelected = false
if let index = selectedIndexes.index(of: indexPath) {
selectedIndexes.remove(at: index)
}
}
else
{
cell.checkmarkbtn.isSelected = true
selectedIndexes.append(indexPath)
}
}
self.Type_of_account_txt.text = ""
for element in selectedIndexes
{
self.Type_of_account_txt.text = (self.Type_of_account_txt.text ?? "") + "\(TypeOfAccountArray[element.row]) ,"
}
if (selectedIndexes.count > 0)
{
self.Type_of_account_txt.text = self.Type_of_account_txt.text?.substring(to: (self.Type_of_account_txt.text?.index(before: (self.Type_of_account_txt.text?.endIndex)!))!)
}
}

you need to follow this step :
In didSelectRowAt, you need to add and remove indexpath in array for multiple checkmark.
Now , in cellForRowAtIndexPath you need to check that current
indexPath consist in array .
if (![arrIndexPath containsObject: indexPath]) {
// do something
cell.checkmarkbtn.setImage(UIImage(named: "checkmark.png"),for:UIControlState.normal)
}

Related

Tableview header cell expand with same cardView in swift?

I have attached the image click the card view expands the same card inside the table cell dynamically its passible to achieve this?
I have searched a lot but not working
Hear my code added header cell with CardView
added arrow button to click the button expand the cell
its able expand but not in parent card it was showing diff card
I have adde my source code
var hiddenSections = Set<Int>()
let tableViewData = [
["1","2","3","4","5"],
["1","2","3","4","5"],
["1","2","3","4","5"],
]
override func viewDidLoad() {
super.viewDidLoad()
let CustomeHeaderNib = UINib(nibName: "CustomSectionHeader", bundle: Bundle.main)
historyTableView.register(CustomeHeaderNib, forHeaderFooterViewReuseIdentifier: "customSectionHeader")
}
func numberOfSections(in tableView: UITableView) -> Int {
return self.tableViewData.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if self.hiddenSections.contains(section) {
return 0
}
return self.tableViewData[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = self.tableViewData[indexPath.section][indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return view.frame.width/4
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = self.historyTableView.dequeueReusableHeaderFooterView(withIdentifier: "customSectionHeader") as! CustomSectionHeader
header.setupCornerRadious()
let sectionButton = header.expandBtn
sectionButton?.setTitle(String(section),
for: .normal)
sectionButton?.tag = section
sectionButton?.addTarget(self,action: #selector(self.hideSection(sender:)), for: .touchUpInside)
return header
}
#objc
private func hideSection(sender: UIButton) {
let section = sender.tag
func indexPathsForSection() -> [IndexPath] {
var indexPaths = [IndexPath]()
for row in 0..<self.tableViewData[section].count {
indexPaths.append(IndexPath(row: row,
section: section))
}
return indexPaths
}
if self.hiddenSections.contains(section) {
self.hiddenSections.remove(section)
self.historyTableView.insertRows(at: indexPathsForSection(),
with: .fade)
} else {
self.hiddenSections.insert(section)
self.historyTableView.deleteRows(at: indexPathsForSection(),
with: .fade)
}
}
With out sections also you can achieve this. To do this,
1.Return cell height as section height. If user clicks on the cell then return total content height to the particular cell.
2.You need to take an array, if user selects cell, add indexPath number in to array. If selects already expand cell remove it from array. In height for row at index check indexPath is in array or not.
This is one of the way. With sections also you can do that.
//MARK:- UITableView Related Methods
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrDict.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
// var cel = tblExpandedTest.dequeueReusableCellWithIdentifier("expCell", forIndexPath: indexPath) as! CDTableViewCell
var cel : CaseHearingTabTVC! = tableView.dequeueReusableCell(withIdentifier: "caseHearingTabCell") as! CaseHearingTabTVC
if(cel == nil)
{
cel = Bundle.main.loadNibNamed("caseHearingTabCell", owner: self, options: nil)?[0] as! CaseHearingTabTVC;
}
//cell?.backgroundColor = UIColor.white
cel.delegate = self
if indexPath != selctedIndexPath{
cel.subview_desc.isHidden = true
cel.subview_remarks.isHidden = true
cel.lblHearingTime.isHidden = true
}
else {
cel.subview_desc.isHidden = false
cel.subview_remarks.isHidden = false
cel.lblHearingTime.isHidden = false
}
return cel
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectIndex = true;
if(selectedInd == indexPath.row) {
selectedInd = -1
}
else{
let currentCell = tableView.cellForRow(at: indexPath)! as! CaseHearingTabTVC
cellUpdatedHeight = Float(currentCell.lblHearingTime.frame.origin.y + currentCell.lblHearingTime.frame.size.height) + 2;
selectedInd = -1
tblCaseHearing.reloadData()
selectedInd = indexPath.row
}
let previousPth = selctedIndexPath
if indexPath == selctedIndexPath{
selctedIndexPath = nil
}else{
selctedIndexPath = indexPath
}
var indexPaths : Array<IndexPath> = []
if let previous = previousPth{
indexPaths = [previous]
}
if let current = selctedIndexPath{
indexPaths = [current]
}
if indexPaths.count>0{
tblCaseHearing.reloadRows(at: indexPaths, with: UITableView.RowAnimation.automatic)
}
}
func tableView(_ tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowIndexPath indexPath:IndexPath) {
(cell as! CaseHearingTabTVC).watchFrameChanges()
}
func tableView(_ tableView: UITableView, didEndDisplayingCell cell: UITableViewCell, forRowIndexPath indexPath:IndexPath) {
(cell as! CaseHearingTabTVC).ignoreFrameChanges()
}
func tableView(_ TableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat{
if indexPath == selctedIndexPath{
return CGFloat(cellUpdatedHeight)
}else{
return CaseHearingTabTVC.defaultHeight
}
}
Best approach is to create two different cells for normal card and expanded card.
fileprivate var selectedIndex: Int?
func registerTableViewCells() {
tableView.register(UINib(nibName:Nib.CardCell , bundle: nil), forCellReuseIdentifier: "CardCell")
tableView.register(UINib(nibName:Nib.ExpandedCardCell , bundle: nil), forCellReuseIdentifier: "ExpandedCardCell")
}
override func viewDidLoad() {
super.viewDidLoad()
self.registerTableViewCells()
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
guard let index = selectedIndex else {
return 115
}
if index == indexPath.row{
return 200
}
return 115
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let selected = selectedIndex, selected == indexPath.row{
let cell = tableView.dequeueReusableCell(withIdentifier: "ExpandedCardCell", for: indexPath) as! ExpandedCardCell
return cell
}
let cell = tableView.dequeueReusableCell(withIdentifier: "CardCell", for: indexPath) as! CardCell
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if selectedIndex == indexPath.row{
selectedIndex = nil
}
else{
selectedIndex = indexPath.row
}
UIView.performWithoutAnimation {
tableView.reloadData()
}
}

I want to set tick in tableview cell for row at indexpath

i am adding multiple selection in tableview with sections in tableview, so how can i store that section index as well as indexpath of that cell for display when user click on cell inside that particular sections that will store in array as selected item and reflect in cellForRowAtindexpath the better solution is appreciated
func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return itemsInSections[section].count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return self.sections.count;
}
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
let header = view as! UITableViewHeaderFooterView
header.textLabel?.textColor = UIColor(red: 8/255, green: 38/255, blue: 76/255, alpha: 1.0)
header.backgroundColor = UIColor.clear
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tablheaders.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath)
let section = indexPath.section
if checkdarray.count > 0
{
if (self.checkdarray[section][indexPath.row] as Int == 1)
{
cell.accessoryType = .checkmark;
}
else
{
cell.accessoryType = .none;
}
}
cell.textLabel?.text = itemsInSections[indexPath.section][indexPath.row] as! String
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let section = indexPath.section as Int
let indepaths = indexPath.row as Int
tableView.cellForRow(at: indexPath as IndexPath)?.accessoryType = .checkmark
checkdarray.insert([1], at: [section][indepaths])
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
tableView.cellForRow(at: indexPath as IndexPath)?.accessoryType = .none
// checkdarray.remove(at: indexPath.row)
//checkdarray.insert(0, at: indexPath.row)
}
The most efficient and reliable solution is to keep the isSelected state in the data model.
Use a struct as data model and add a member isSelected along with the other information you need.
struct Model {
var isSelected = false
var someOtherMember : String
// other declarations
}
In cellForRow set the checkmark according to the isSelected member
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) // use always the passed tableView instance
let model = itemsInSections[indexPath.section][indexPath.row]
cell.accessoryType = model.isSelected ? .checkmark : .none
cell.textLabel?.text = model.someOtherMember
return cell
}
In didSelectRowAt and didDeselectRowAt update the model and reload the row
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
itemsInSections[indexPath.section][indexPath.row].isSelected = true
tableView.reloadRows(at: [indexPath], with: .none)
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
itemsInSections[indexPath.section][indexPath.row].isSelected = false
tableView.reloadRows(at: [indexPath], with: .none)
}
Never use an extra array to save index paths. Don't do that.
I have used button in table...
// declare var
var checkarrMenu = Set<IndexPath>()
// In tableView
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = mManageTableView.dequeueReusableCell(withIdentifier: "TableViewCellID")as! TableViewCell
cell.mRadioBtnAct.tag = indexPath.row
cell.mRadioBtnAct.addTarget(self, action: #selector(mRadioCheck(sender:)), for: .touchUpInside)
if checkarrMenu.contains(indexPath){
cell.mradioimage.image = UIImage(named: "Radiochecked")
}else{
cell.mradioimage.image = UIImage(named: "Radio checkedlightRadio3")
}
return cell
}
// on radio btn Action
#objc func mRadioCheck(sender:UIButton){
let touchPoint: CGPoint = sender.convert(CGPoint.zero, to: mManageTableView)
// maintable --> replace your tableview name
let clickedButtonIndexPath = mManageTableView.indexPathForRow(at: touchPoint)
if checkarrMenu.contains(clickedButtonIndexPath){
checkarrMenu.remove(clickedButtonIndexPath)
}else{
checkarrMenu.insert(clickedButtonIndexPath)
}
tableView.reloadData()
}
// hope its works for you!

UITableViewCell has incorrect change on indexPath

I try to use UITableViewCell's accessoryType property to checkmark cell when clicked ,but when cell selected , the checkmark set several time for different cells for example when I select row [0] , row [0] and row [8] and row [17] AccessoryType set to checkmark !
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "npCell", for: indexPath) as! NewPlaylistTableViewCell
cell.mTitle.text = musics[indexPath.row]["title"] as! String?
cell.mArtist.text = musics[indexPath.row]["artist"] as! String?
cell.selectionStyle = .none
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
cell?.accessoryType = .checkmark
tableView.reloadData()
}
For single selection, you need to track your selected indexPath in a viewController variable,
var selectedIndexPath : IndexPath?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.selectedIndexPath = indexPath
tableView.reloadData()
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "npCell", for: indexPath) as! NewPlaylistTableViewCell
cell.mTitle.text = musics[indexPath.row]["title"] as! String?
cell.mArtist.text = musics[indexPath.row]["artist"] as! String?
cell.accessoryType = .none
cell.selectionStyle = .none
if(indexPath == selectedIndexPath) {
cell.accessoryType = .checkmark
}
return cell
}
Even better (avoiding reload the entire UITableView)
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let previousSelectedIndexPath = self.selectedIndexPath
self.selectedIndexPath = indexPath
if(previousSelectedIndexPath != nil) {
self.tableView.reloadRows(at: [previousSelectedIndexPath!,self.selectedIndexPath!], with: .automatic)
}else{
self.tableView.reloadRows(at: [self.selectedIndexPath!], with: .automatic)
}
self.tableView.reloadData()
}
UPDATE, Allowing multiple selection
For multiple selection you should track selected cells in a Dictionary for convenience faster access to selected and unselected indexPaths allowing you use multiple sections because the key value of our Dictionary is a string formed by (IndexPath.section)+(IndexPath.row) which is always unique combination
var selectedIndexPaths : [String:Bool] = [:]
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let currentIndexPathStr = "\(indexPath.section)\(indexPath.row)"
if(self.selectedIndexPaths[currentIndexPathStr] == nil || !self.selectedIndexPaths[currentIndexPathStr]!) {
self.selectedIndexPaths[currentIndexPathStr] = true
}else{
self.selectedIndexPaths[currentIndexPathStr] = false
}
self.tableView.reloadRows(at: [indexPath], with: .automatic)
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "npCell", for: indexPath) as! NewPlaylistTableViewCell
cell.mTitle.text = musics[indexPath.row]["title"] as! String?
cell.mArtist.text = musics[indexPath.row]["artist"] as! String?
cell.accessoryType = .checkmark
let currentIndexPathStr = "\(indexPath.section)\(indexPath.row)"
if(self.selectedIndexPaths[currentIndexPathStr] == nil || !self.selectedIndexPaths[currentIndexPathStr]!) {
cell.accessoryType = .none
}
return cell
}
Results

UITableView cell on double click should go to previous state

If I select (click) row of TableView, it should add Image saying that I selected this particular Item. It's working fine!
My problem is: if user want to move back from that selected item.
If I click on the same row it should deselect that cell and hide that image.
What I tried is:
func tableView (_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath as IndexPath) as! leistungCell
// Configure the cell...
let tableData = self.tableData[indexPath.row]
cell.leistungLbl.text = tableData["leistung_info"] as? String
//space between Rows
cell.contentView.backgroundColor = colorLightGray
cell.contentView.layer.borderColor = UIColor.white.cgColor
//space between Rows
cell.contentView.layer.borderWidth = 3.0
cell.contentView.layer.cornerRadius = 8
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
cell?.imageView?.image = UIImage(named: "check.png")
let value = Info["leistung_info"] as! String
}
func tableView(_ tableView: UITableView, didDeSelectRowAt indexPath: IndexPath){
let cell = tableView.cellForRow(at: indexPath)
cell?.imageView?.image = nil
}
Forget and remove didDeSelectRowAt, just use didSelectRowAt, and an array to save selections:
var selectedIndexPaths = [IndexPath]()
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
if let index = selectedIndexPaths.index(of: indexPath) { //deselect it if the row is selected
tableView.deselectRow(at: indexPath, animated: true)
cell?.imageView?.image = nil
selectedIndexPaths.remove(at: index)
}
else{ //select it if the row is deselected
cell?.imageView?.image = UIImage(named: "check.png")
selectedIndexPaths.append(indexPath)
}
}
And be aware of that the cells are being REUSED ! Please do the same check in cellForRowAt method.

Link the UITableViewCell label to next ViewController programmatically

I have created 2 TableViewControllers in one ViewController programmatically as :
// contents for labels in cells for tableviewcontrollers
let contents1 : [String] = ["One:","Two:","Three:","Four:","Five:"]
let contents2 : [String] = ["Six:","Seven:","Eight:","Nine:","Ten:"]
override func viewDidLoad() {
super.viewDidLoad()
table1.delegate = self
table1.dataSource = self
table2.delegate = self
table2.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if(tableView.tag == 1)
{
return contents1.count
}
else if (tableView.tag == 2)
{
return contents2.count
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath as IndexPath )
if (tableView.tag == 1)
{
cell.textLabel?.text = contents1[indexPath.row]
}
else if (tableView.tag == 2)
{
cell.textLabel?.text = contents2[indexPath.row]
}
return cell
}
My question is that , how can I programmatically link "Four:" label of first TableViewController "table1" when selected to show up next new ViewController without using Segue?
You can UITableView's deSelectRowAt delegate method to identify the cell selection after that you can proceed to next view
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
if cell?.textLabel?.text == "Four" { // you can use you indexPath to compare as well
let secondViewController = self.storyboard.instantiateViewControllerWithIdentifier("SecondViewController") as SecondViewController
self.navigationController.pushViewController(secondViewController, animated: true)
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = pets[indexPath.row]
// Configure the cell...
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
myIndex = indexPath.row
performSegue(withIdentifier: "segue", sender: self)

Resources