I have used tableview(grouped).
So i need to select one row from the each section of UITableviewSection.
So for that i have tableview and one submit button .So i need to check when i click on the submit button i need to check whether i have selected one row from the each section ,if not then show alert as not selected the section number.How to check?
This is my data.
{
"data":[
{
"question": "Gender",
"options": ["Male","Female"]
},
{
"question": "How old are you",
"options": ["Under 18","Age 18 to 24","Age 25 to 40","Age 41 to 60","Above 60"]
},
{
"question": "I am filling the Questionnaire for?",
"options": ["Myself","Mychild","Partner","Others"]
}
]
}
QuestionModel:-
class QuestionListModel: NSObject {
var selected = false
var dataListArray33:[NH_OptionsModel] = []
var id:Int!
var question:String!
var buttontype:String!
var options:[String]?
var v:String?
var optionsModelArray:[OptionsModel] = []
init(dictionary :JSONDictionary) {
guard let question = dictionary["question"] as? String,
let typebutton = dictionary["button_type"] as? String,
let id = dictionary["id"] as? Int
else {
return
}
if let options = dictionary["options"] as? [String]{
print(options)
print(options)
for values in options{
print(values)
let optionmodel = OptionsModel(values: values)
self.optionsModelArray.append(optionmodel)
}
}
self.buttontype = typebutton
self.question = question
self.id = id
// print(self.dataListArray33)
}
}
optionModel:-
class OptionsModel: NSObject {
var isSelected:Bool? = false
var v:String?
var values:String?
init(values:String) {
self.values = values
print( self.values)
}
ViewModel:-
func numberOfSections(tableView: UITableView) -> Int{
print((datasourceModel.dataListArray?.count)!)
return (datasourceModel.dataListArray?.count)!
}
func titleForHeaderInSection(atsection section: Int) -> NH_QuestionListModel {
return datasourceModel.dataListArray![section]
}
func numberOfRowsIn(section:Int) -> Int {
print( datasourceModel.dataListArray?[section].optionsModelArray.count ?? 0)
return datasourceModel.dataListArray?[section].optionsModelArray.count ?? 0
// return self.questionsModelArray?[section].optionsModelArray.count ?? 0
}
func datafordisplay(atindex indexPath: IndexPath) -> NH_OptionsModel{
print(datasourceModel.dataListArray![indexPath.section].optionsModelArray[indexPath.row])
return datasourceModel.dataListArray![indexPath.section].optionsModelArray[indexPath.row]
}
func question(answer:String) {
print(questions)
questions.append(answer)
print(questions )
}
func questionlist(answer:String) {
print( questionlist )
questionlist.append(answer)
print( questionlist )
}
func answer(answer:String) {
answers.append(answer)
print(answers)
}
and finally viewController:-
func numberOfSections(in tableView: UITableView) -> Int {
return questionViewModel.numberOfSections(tableView: tableView)
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let identifier = "HeaderCell"
var headercell: questionheader! = tableView.dequeueReusableCell(withIdentifier: identifier) as? questionheader
if headercell == nil {
tableView.register(UINib(nibName: "questionheader", bundle: nil), forCellReuseIdentifier: identifier)
headercell = tableView.dequeueReusableCell(withIdentifier: identifier) as? NH_questionheader
}
headercell.setReviewData(reviews:questionViewModel.titleForHeaderInSection(atsection:section))
return headercell
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 150
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return questionViewModel.numberOfRowsIn(section: section)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let identifier = "Cell"
var cell: QuestionListCell! = tableView.dequeueReusableCell(withIdentifier: identifier) as? QuestionListCell
if cell == nil {
tableView.register(UINib(nibName: "QuestionListCell", bundle: nil), forCellReuseIdentifier: identifier)
cell = tableView.dequeueReusableCell(withIdentifier: identifier) as? NH_QuestionListCell
}
cell.contentView.backgroundColor = UIColor.clear
let questionsModel = questionViewModel.titleForHeaderInSection(atsection:indexPath.section)
print(questionsModel.buttontype)
questionViewModel.button = questionsModel.buttontype
cell.setOptions(Options1: questionViewModel.datafordisplay(atindex: indexPath))
print("Section \(indexPath.section), Row : \(indexPath.row)")
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
print("Section \(indexPath.section), Row : \(indexPath.row)")
let cell = tableview.cellForRow(at: indexPath) as? NH_QuestionListCell
let model = questionViewModel.datafordisplay(atindex: indexPath)
print(model.isSelected)
cell?.setOptions(OptionsSelected:questionViewModel.datafordisplay(atindex: indexPath))
print(model.isSelected)
questionViewModel.isselected = model.isSelected!
let section = indexPath.section
let index = indexPath.row
print(section)
print(index)
if !questionViewModel.selectedIndexPaths.contains(indexPath) {
questionViewModel.selectedIndexPaths.append(indexPath)
print(questionViewModel.selectedIndexPaths.append(indexPath))
let questionModel = questionViewModel.titleForHeaderInSection(atsection: section)
print(questionModel.question)
questionViewModel.question = questionModel.question
questionViewModel.questionlist(answer: questionViewModel.question!)
let cell = tableview.cellForRow(at: indexPath) as? NH_QuestionListCell
let model = questionViewModel.datafordisplay(atindex: indexPath)
print(model.values)
questionViewModel.answer(answer: model.values!)
let value: Int = questionModel.id
let string = String(describing: value)
//let x: Int? = Int(model.id)
questionViewModel.question_id = string
questionViewModel.question(answer: questionViewModel.question_id!)
print(questionModel.id)
// append the selected index paths
} // if indexPath.section == section {
// questionViewModel.indexPath(indexPaths: index)
// }
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if let index = questionViewModel.selectedIndexPaths.index(of: indexPath) {
print(index)
questionViewModel.selectedIndexPaths.remove(at: index)
}
}
According to this i got the output .
But i have button action in viewcontroller.
#IBAction func forward(_ sender: AnyObject) {
}
In this button action i need to check whether from each section did i selected one row or not .if not show alert .How to do
my current didselect method :-
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
let cell = tableview.cellForRow(at: indexPath) as? NH_QuestionListCell
let model = questionViewModel.datafordisplay(atindex: indexPath)
print(model.isSelected)
cell?.setOptions(OptionsSelected:questionViewModel.datafordisplay(atindex: indexPath))
print(model.isSelected)
questionViewModel.isselected = model.isSelected!
let section = indexPath.section
let index = indexPath.row
print(section)
print(index)
if !questionViewModel.selectedIndexPaths.contains(indexPath) {
questionViewModel.selectedIndexPaths.append(indexPath)
print(questionViewModel.selectedIndexPaths.append(indexPath))
let questionModel = questionViewModel.titleForHeaderInSection(atsection: section)
print(questionModel.question)
questionViewModel.question = questionModel.question
questionViewModel.questionlist(answer: questionViewModel.question!)
let cell = tableview.cellForRow(at: indexPath) as? NH_QuestionListCell
let model = questionViewModel.datafordisplay(atindex: indexPath)
print(model.values)
questionViewModel.answer(answer: model.values!)
let value: Int = questionModel.id
let string = String(describing: value)
//let x: Int? = Int(model.id)
questionViewModel.question_id = string
questionViewModel.question(answer: questionViewModel.question_id!)
print(questionModel.id)
}
I have 3 array
According to this didselect method:-
ex:-for section 1 :-i selected 1st row so the data append as below.
questionlist:["How r u?"]
answelist:["fine"]
But suppose i think that i need 2nd indexpath ,so i need to remove the previous appended data from arrays and append the current data .As below:
questionlist:["How r u?"]
answelist:["not well"]
And next for section 2 : i selected 1st indexpath.row data .then that data is append.So i need to get as below:-
questionlist:["How r u?","Gender"]
answelist:["not well","Male"]
Here selecting i think that i need the 2nd option then remove the added indexpath.row data from array and show as:-
questionlist:["How r u?","Gender"]
answelist:["not well","Female"]
Such way how to set?
you can update your model based on the selection like
"data":[
{
"question": "Gender",
"options": ["Male","Female"],
"optionSelected": "Male"
}
]
and on Submit , check data for selections
The table view has a property to get selected index paths. You can use all native components for that. What you need is to deselect an item at index path where one is already selected in a certain section. You also just need to then check that the number of selected index paths is the same as number of arrays in your data source.
Check something like this:
var dataSource: [[Any]]!
var tableView: UITableView!
func didSelectRowAt(_ indexPath: IndexPath) {
guard let selectedPaths = tableView.indexPathsForSelectedRows else { return } // We need to have selected paths
guard selectedPaths.contains(indexPath) == false else { return } // The same cell being selected
let previouslySelectedCellIndexPaths: [IndexPath] = selectedPaths.filter { $0.section == indexPath.section && $0 != indexPath } // Getting all selected index paths within this section
previouslySelectedCellIndexPaths.forEach { tableView.deselectRow(at: $0, animated: true) } // Deselect waht was previously selected
}
/// Will return array of selected objects only if all sections have a selected index
///
/// - Returns: A result array
func getSelectionData() -> [Any]? {
guard let selectedPaths = tableView.indexPathsForSelectedRows else { return nil } // We need to have selected paths
guard selectedPaths.count == dataSource.count else { return nil } // This should prevent missing selections assuming all index paths are unique in sections
return selectedPaths.map { dataSource[$0.section][$0.row] } // Map selected index paths back to objects
}
I tried to use kind of minimum code to show all of this. It is all commented so you can see row by row what goes on.
You might want to check is all sections are unique the second method but it is not needed if the first one is always used.
You can store selected indexPath in an array. OnClick of submit just loop through array and check either at least one element is from each section.
FYI : indexPath contains section info also.
Declare an mutable array and allocate in viewDidLoad.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[anArray addObject:indexPath];
}
on Submit action follow this, you can improvise based on your requirement
-(void)onSubmitAction{
[anArray addObject:indexPath];
NSMutableArray *countOfSection=[[NSMutableArray alloc]init];
for (NSIndexPath*indexPath in anArray ) {
if(![anArray containsObject:indexPath.section])
[countOfSection addObject:indexPath.section];
}
if(countOfSection.count == self.tableview.numberOfSections){
//write your code
}else{
// show alert
}
}
Step 1 : Create Global Variable
var selectedIndexPaths = [IndexPath]()
Step 2: Add UITableView Property
tableView.allowsMultipleSelection = true
Step 3 : Implement the delegate methods
//On Selection
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedIndexPathAtCurrentSection = selectedIndexPaths.filter({ $0.section == indexPath.section})
for indexPath in selectedIndexPathAtCurrentSection {
tableView.deselectRow(at: indexPath, animated: true)
if let indexOf = selectedIndexPaths.index(of: indexPath) {
selectedIndexPaths.remove(at: indexOf)
}
}
selectedIndexPaths.append(indexPath)
}
// On DeSelection
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if let index = selectedIndexPaths.index(of: indexPath) {
selectedIndexPaths.remove(at: index)
}
}
Step 4: Getting Selected IndexPaths with sections
#IBAction func forward(sender:Any){
let totalSections = questionViewModel.numberOfSections(tableView: tableView)
for section in 0..<totalSections {
if (selectedIndexPaths.filter({ $0.section == section}).count >= 1) {
continue
} else {
// Show alert
print("Please select item at",(section))
return
}
}
}
Related
Before duplicating this question, please be known that I've spent days on this issue, working hours, and looking for all same sort of questions on SO, but there is something I am missing or doing wrong.
I have a tableView in which the data is being populated via API response. Below is the model I have.
struct Model : Codable {
let bugClassification : [Bug]?
}
struct Bug : Codable {
let selectable : String? //Telling wether cell is single/Multi selected
var options : [Options]?
}
struct Options : Codable, Equatable {
let title : String?
let id: Int
var isCellSelected: Bool = false
}
Scenario
I want to create multiple sections, each having different cell depending upon the type of selectable, either single or multi. I have achieved that, but the problem I am getting is that whenever I scroll, random cells are also selected. Now, I know this behaviour is because of tableView reusing the cells. But I am confused as how to handle all this. Also, I want to put the validation on the sections, that is, every section should have atleast one cell selected. Kindly guide me in the right direction, and any small help would be appreciated. Below is my code.
CellForRowAt
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if bugClassification[indexPath.section].selectable?.lowercased() == "multi-select" {
//Multi-Selection
let cell = tableView.dequeueReusableCell(withIdentifier: multiSelectionCellID) as! MultiSelectionCell
let item = bugClassification[indexPath.section].options![indexPath.row]
cell.label.text = item.title
if item.isCellSelected {
cell.checkMarkImageView.alpha = 1
cell.checkMarkView.layer.borderColor = UIColor.white.cgColor
cell.checkMarkView.backgroundColor = .emerald
} else if item.isCellSelected {
cell.checkMarkImageView.alpha = 0
cell.checkMarkView.layer.borderColor = UIColor.veryLightBlue.cgColor
cell.checkMarkView.backgroundColor = .white
}
return cell
} else {
//Single-Selection
let cell = tableView.dequeueReusableCell(withIdentifier: singleSelectionCellID) as! SingleSelectionCell
let item = bugClassification[indexPath.section].options![indexPath.row]
cell.label.text = item.title
if item.isCellSelected {
cell.checkMarkImageView.alpha = 1
cell.checkMarkView.layer.borderColor = UIColor.emerald.cgColor
} else {
cell.checkMarkImageView.alpha = 0
cell.checkMarkView.layer.borderColor = UIColor.veryLightBlue.cgColor
}
return cell
}
}
DidSelectRow Method
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if bugClassification[indexPath.section].selectable?.lowercased() == "multi-select" {
var item = bugClassification[indexPath.section].options![indexPath.row]
item.isCellSelected = !item.isCellSelected
bugClassification[indexPath.section].options![indexPath.row] = item
self.tableView.reloadRows(at: [indexPath], with: .automatic)
} else {
let items = bugClassification[indexPath.section].options
if let selectedItemIndex = items!.indices.first(where: { items![$0].isCellSelected }) {
bugClassification[indexPath.section].options![selectedItemIndex].isCellSelected = false
if selectedItemIndex != indexPath.row {
bugClassification[indexPath.section].options![indexPath.row].isCellSelected = true
}
} else {
bugClassification[indexPath.section].options![indexPath.row].isCellSelected = true
}
self.tableView.reloadSections([indexPath.section], with: .automatic)
}
}
In cellForRowAt
if item.isCellSelected == true{
cell.accessoryType = .checkmark
} else {
cell.accessoryType = .none
}
and update the model by every selection
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let item = bugClassification[indexPath.section].options![indexPath.row]
if let cell = tableView.cellForRow(at: indexPath) {
cell.accessoryType = .none
if indexPath.section == 0{
item.isCellSelected.isSelected = false
}else{
item.isCellSelected.isSelected = false
}
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let item = bugClassification[indexPath.section].options![indexPath.row]
if let cell = tableView.cellForRow(at: indexPath) {
cell.accessoryType = .checkmark
if indexPath.section == 0{
item.isCellSelected.isSelected = true
}else{
item.isCellSelected.isSelected = true
}
}
}
I am new in swift and I am not able to get main tableview index on nested tableview button click
my code is like this
extension Section2QuestionsViewController: UITableViewDataSource, UITableViewDelegate
{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrFinancialYears.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let strCellID = "Section2QuestionCell"
var cell = tableView.dequeueReusableCell(withIdentifier: strCellID) as? Section2QuestionCell
if cell == nil
{
tableSection2.register(Section2QuestionCell.self, forCellReuseIdentifier: strCellID)
cell = tableSection2.dequeueReusableCell(withIdentifier: strCellID) as? Section2QuestionCell
}
let dictAppStats = arrFinancialYears[indexPath.row] as? [String:Any]
cell?.lblQuestionTitle.text = "\(indexPath.row + 1). \(dictAppStats?["question"] as? String ?? "")"
cell?.arrCourses = [Any]()
cell?.arrCourses = dictAppStats?["options"] as? [Any] ?? []
cell?.tableInsideHeightConstraints.constant = CGFloat(28 * (cell?.arrCourses.count ?? 0))
cell?.tableInside.reloadData()
return cell!
}
}
Inside tableview
extension Section2QuestionCell: UITableViewDataSource, UITableViewDelegate
{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrCourses.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "InsideSection2QuestionCell", for: indexPath) as! InsideSection2QuestionCell
cell.selectionStyle = .none
let dictFeeStats = arrCourses[indexPath.row] as? [String:Any]
cell.lblOption.text = dictFeeStats?["option_value"] as? String
cell.btnOption.tag = indexPath.item
cell.btnOption.addTarget(self, action: #selector(btnOptionClick), for: .touchUpInside)
cell.lblAnswerKey.text = dictFeeStats?["answer_key"] as? String
cell.lblQuestionId.text = dictFeeStats?["question_id"] as? String
cell.lblAnswerId.text = dictFeeStats?["option_id"] as? String
return cell
}
}
Button Click
#objc func btnOptionClick(_ sender: UIButton)
{
let index = IndexPath(row: sender.tag, section: 0)
let cell: InsideSection2QuestionCell = tableInside.cellForRow(at: index) as! InsideSection2QuestionCell
let QuestionId = cell.lblQuestionId.text
let AnswwerId = cell.lblAnswerId.text
print(QuestionId as Any)
print(AnswwerId as Any)
Globalnewdict = ["option":AnswwerId as Any,"question":QuestionId as Any]
Globalindexvalue = sender.tag
NotificationCenter.default.post(name: Notification.Name(rawValue: "disconnectPaxiSockets"), object: nil)
tableInside.reloadData()
}
I am not able to get main tableview index path value on button. Is there is any way to get main tableview index path value on button click.
Please help
Thanks in Advance!
You could add an index path object in your Section2QuestionCell
var parentTableIndexPath : IndexPath!
Then set the value in cellForRowAt tableview delegate method
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let strCellID = "Section2QuestionCell"
var cell = tableView.dequeueReusableCell(withIdentifier: strCellID) as? Section2QuestionCell
if cell == nil {
tableSection2.register(Section2QuestionCell.self, forCellReuseIdentifier: strCellID)
cell = tableSection2.dequeueReusableCell(withIdentifier: strCellID) as? Section2QuestionCell
}
cell.parentTableIndexPath = indexPath
let dictAppStats = arrFinancialYears[indexPath.row] as? [String:Any]
cell?.lblQuestionTitle.text = "\(indexPath.row + 1). \(dictAppStats?["question"] as? String ?? "")"
cell?.arrCourses = [Any]()
cell?.arrCourses = dictAppStats?["options"] as? [Any] ?? []
cell?.tableInsideHeightConstraints.constant = CGFloat(28 * (cell?.arrCourses.count ?? 0))
cell?.tableInside.reloadData()
return cell!
}
Since btnOptionClick() is in same class, you can directly access the parent table Index path in your button action.
In
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let strCellID = "Section2QuestionCell"
var cell = tableView.dequeueReusableCell(withIdentifier: strCellID) as? Section2QuestionCell
if cell == nil
{
tableSection2.register(Section2QuestionCell.self, forCellReuseIdentifier: strCellID)
cell = tableSection2.dequeueReusableCell(withIdentifier: strCellID) as? Section2QuestionCell
}
let dictAppStats = arrFinancialYears[indexPath.row] as? [String:Any]
cell?.lblQuestionTitle.text = "\(indexPath.row + 1). \(dictAppStats?["question"] as? String ?? "")"
cell?.arrCourses = [Any]()
cell?.arrCourses = dictAppStats?["options"] as? [Any] ?? []
cell?.tableInsideHeightConstraints.constant = CGFloat(28 * (cell?.arrCourses.count ?? 0))
cell?.tableInside.tag = indexPath.row
cell?.tableInside.reloadData()
return cell!
}
In ButtonClick
#objc func btnOptionClick(_ sender: UIButton)
{
let index = IndexPath(row: sender.tag, section: 0)
let cell: InsideSection2QuestionCell = tableInside.cellForRow(at: index) as! InsideSection2QuestionCell
let QuestionId = cell.lblQuestionId.text
let AnswwerId = cell.lblAnswerId.text
print(QuestionId as Any)
print(AnswwerId as Any)
Globalnewdict = ["option":AnswwerId as Any,"question":QuestionId as Any]
Globalindexvalue = tableInside.tag
NotificationCenter.default.post(name: Notification.Name(rawValue: "disconnectPaxiSockets"), object: nil)
tableInside.reloadData()
}
In cellForRowAt I set indexpath.row to tableview.tag.
Then on button click I set tableview.tag to global indexpath.
I have a simple app that populates a UITableView based on data inputed in a different ViewController. I am trying to implement the "swipe left to delete"
My problem is that this UITableView is a dropdown table view. That is when I click on one cell of the UITableView the cells open up and show me the internal cells associated with that one cells.
I think I am missing something simple as my code to delete the row does not work, it just throws a SIGBRT error. I think because maybe I trying to remove the wrong array maybe? I think it is messed up because it is a dropdown UITableView, so I am left with a bunch of extra UITableview rows?
Code to added delete button and remove selected row.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
// remove the item from the data model
tableViewData.remove(at: indexPath.row)
// delete the table view row
tableView.deleteRows(at: [indexPath], with: .fade)
}
}
Whole code in the UITableViewController is as follows:
import Foundation
import UIKit
private let reuseidentifier = "Cell"
struct cellData {
var opened = Bool()
var title = String()
var exerciseData = [String]()
var repsSetsData = [String]()
}
//here
struct Contact {
var fullname: String
var exercises : [Exercise]
}
class Exercise : NSObject , NSSecureCoding{
static var supportsSecureCoding: Bool = true
var excerciseName: String
var excerciseReps: String
var excerciseSets: String
init(Name : String, Reps : String, Sets : String) {
excerciseName = Name
excerciseReps = Reps
excerciseSets = Sets
}
func encode(with aCoder: NSCoder) {
aCoder.encode(excerciseName, forKey: "excerciseName")
aCoder.encode(excerciseReps, forKey: "excerciseReps")
aCoder.encode(excerciseSets, forKey: "excerciseSets")
}
required convenience init?(coder aDecoder: NSCoder) {
let excerciseName = aDecoder.decodeObject(forKey: "excerciseName") as! String
let excerciseReps = aDecoder.decodeObject(forKey: "excerciseReps") as! String
let excerciseSets = aDecoder.decodeObject(forKey: "excerciseSets") as! String
self.init(Name: excerciseName, Reps: excerciseReps, Sets: excerciseSets)
}
}
class ContactController: UITableViewController {
//new
var tableViewData = [cellData]()
var contacts = [Contact]()
override func viewDidLoad() {
super.viewDidLoad()
//getting data from CoreData
self.contacts = CoreDataManager.sharedInstance.retrieveDataFromCoreData()
tableView.register(UINib(nibName: "ExerciseCell", bundle: nil), forCellReuseIdentifier: "ExerciseCell")
for contact in contacts{
var exerciseData = [String]()
var repsSetsData = [String]()
for exercise in contact.exercises{
let name = exercise.excerciseName
let sets = exercise.excerciseSets
let reps = exercise.excerciseReps
exerciseData.append(name)
repsSetsData.append("Reps: " + reps + " Sets: " + sets)
}
self.tableViewData.append(cellData.init(opened: false, title: contact.fullname, exerciseData:exerciseData, repsSetsData: repsSetsData))
}
self.tableView.reloadData()
self.navigationController?.navigationBar.prefersLargeTitles = true
self.navigationItem.title = "Workouts"
view.backgroundColor = .white
tableView.register(UITableViewCell.self, forCellReuseIdentifier: reuseidentifier)
}
#IBAction func handleAddContact(_ sender: Any) {
let controller = AddContactController()
controller.delegate = self
self.present(UINavigationController(rootViewController: controller), animated: true, completion: nil)
}
//UITABLEVIEW
//all new
override func numberOfSections(in tableView: UITableView) -> Int {
//new
return tableViewData.count
}
override func tableView(_ tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
//new
if tableViewData[section].opened == true {
return tableViewData[section].exerciseData.count + 1
}else {
return 1
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: reuseidentifier, for: indexPath)
cell.textLabel?.text = tableViewData[indexPath.section].title
return cell
}else {
//use a different cell identifier if needed
let cell = tableView.dequeueReusableCell(withIdentifier: "ExerciseCell", for: indexPath) as! ExerciseCell
cell.exerciseLabel.text = tableViewData[indexPath.section].exerciseData[indexPath.row - 1]
cell.repsSetsLabel.text = tableViewData[indexPath.section].repsSetsData[indexPath.row - 1]
cell.repsSetsLabel.sizeToFit()
return cell
}
}
//did select row new
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableViewData[indexPath.section].opened == true {
tableViewData[indexPath.section].opened = false
let sections = IndexSet.init(integer: indexPath.section)
tableView.reloadSections(sections, with: .none) //play around with animation
}else {
tableViewData[indexPath.section].opened = true
let sections = IndexSet.init(integer: indexPath.section)
tableView.reloadSections(sections, with: .none) //play around with animation
}
}
//being able to delete a row
// this method handles row deletion
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
// remove the item from the data model
tableViewData.remove(at: indexPath.row)
// delete the table view row
tableView.deleteRows(at: [indexPath], with: .fade)
}
}
}
//this is an extention to addContactController. this is what happens whent he done button is clicked in addcontactcontroller
extension ContactController: AddContactDelegate {
func addContact(contact: Contact) {
self.dismiss(animated: true) {
//Saving Data to CoreData
CoreDataManager.sharedInstance.addContactsToCoreData(contact: contact)
self.contacts.append(contact)
//Settings values in table view
var exerciseData = [String]()
var repsSetsData = [String]()
for exercise in contact.exercises{
let name = exercise.excerciseName
let sets = exercise.excerciseSets
let reps = exercise.excerciseReps
exerciseData.append(name)
repsSetsData.append("Reps: " + reps + " Sets: " + sets)
}
self.tableViewData.append(cellData.init(opened: false, title: contact.fullname, exerciseData:exerciseData, repsSetsData: repsSetsData))
self.tableView.reloadData()
}
}
}
After deleting the rows can you try to reload the tableview cells like this: self.tableView.reloadData()
It's supposed that you delete a row not an entire section , so replace
tableViewData.remove(at: indexPath.row)
with
tableViewData[indexPath.section].exerciseData.remove(at: indexPath.row)
also make sure exerciseData is mutable ( declared as var )
How to get row index from UITableView which the array list made by append to a Object Class.
And I want to get the row index based on the value from the object, I needed that for scroll to a row which I only know a value from object, but don't know which the row index.
Below is the code for create a array and show to the UITableView.
let paging: Int
let obj: Any
var currentAyaPlaying: Int?
var listArr = [] as [Any]
override func viewDidLoad() {
super.viewDidLoad()
tableView.estimatedRowHeight = 700
tableView.rowHeight = UITableView.automaticDimension
tableView.allowsSelection = true
if paging == Paging.SURA {
let sura = obj as! Sura
listArr.append(Sura(sura.index, sura.start, sura.ayas, sura.type, sura.img, sura.name, sura.translate))
for aya in 1...sura.ayas {
listArr.append(Mark(sura.index, aya))
}
} else if (paging == Paging.JUZ){
let juz = obj as! Juz
for suras in juz.sura_start...juz.sura_end {
let sura = MetaData().mSuras[suras - 1]
if juz.sura_start == suras {
for aya in juz.aya_start...(juz.sura_end == suras ? juz.aya_end : sura.ayas) {
listArr.append(Mark(suras, aya))
}
} else if juz.sura_end == suras {
listArr.append(Sura(sura.index, sura.start, sura.ayas, sura.type, sura.img, sura.name, sura.translate))
for aya in 1...juz.aya_end {
listArr.append(Mark(suras, aya))
}
} else {
listArr.append(Sura(sura.index, sura.start, sura.ayas, sura.type, sura.img, sura.name, sura.translate))
for aya in 1...sura.ayas {
listArr.append(Mark(suras, aya))
}
}
}
}
NotificationCenter.default.addObserver(self, selector: #selector(appearNotifAudioReload(_:)), name: NSNotification.Name(rawValue: NotifKey.actAudioReloadFromParentToChild), object: nil)
}
#objc func appearNotifAudioReload(_ notification: Notification) {
guard let sura = notification.userInfo?["sura"] as? Int else { return }
guard let aya = notification.userInfo?["aya"] as? Int else { return }
print("sura: \(sura)")
print("aya: \(aya)")
self.currentAyaPlaying = aya
if paging == Paging.SURA {
let indexPath = NSIndexPath(row: self.currentAyaPlaying!, section: 0)
tableView.scrollToRow(at: indexPath as IndexPath, at: .top, animated: true)
} else if paging == Paging.JUZ {
let IStackInHere = Mark(sura, aya) // how to get the row index from this data?
let indexPath = NSIndexPath(row: IStackInHere, section: 0)
tableView.scrollToRow(at: indexPath as IndexPath, at: .top, animated: true)
}
tableView.reloadData()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listArr.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if (listArr[indexPath.row] as? Sura) != nil {
tableView.register(UINib(nibName: identifierAyaHeader, bundle: Bundle.main), forCellReuseIdentifier: identifierAyaHeader)
let cell = tableView.dequeueReusableCell(withIdentifier: identifierAyaHeader, for: indexPath) as! AyaCellHeader
let data = listArr[indexPath.row] as! Sura
cell.configureWithData(data)
return cell
}
tableView.register(UINib(nibName: identifierAya, bundle: Bundle.main), forCellReuseIdentifier: identifierAya)
let cell = tableView.dequeueReusableCell(withIdentifier: identifierAya, for: indexPath) as! AyaCell
let data = listArr[indexPath.row] as! Mark
cell.configureWithData(data)
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if (listArr[indexPath.row] as? Mark) != nil {
tableView.deselectRow(at: indexPath, animated: false)
let mark = listArr[indexPath.row] as! Mark
showActionBottom(mark: mark)
}
}
I want to get it in the condition if paging == Paging.JUZ in the func appearNotifAudioReload, I just try to get it with:
let index = listArr.firstIndex{$0 === Mark(sura, aya)}
But no lucky and error
"Binary operator '===' cannot be applied to operands of type 'Any' and
'Mark'"
I know this forum is not to solve my coding problems, but right now I'm really troubled.
Thanks in advance.
You need to use == (to equal signs) to compare equality. Assuming the Mark struct conforms to Equatable, you can use the following:
let index = listArr.firstIndex { $0 as! Mark == Mark(sura, aya) }
I want tableviewcell index on dropdown item selection. But the index is nil when I am clicking on dropdown item. Is there any way to get index on dropdown item selection? If anyone have any better solution give me some idea.
let EditDropDown = DropDown()
lazy var dropDowns: [DropDown] = {
return [
self.EditDropDown
]
}()
This is my function which I am using for DropDown List.
func setupGenderDropDown() {
let cellHeader = tableview.dequeueReusableCell(withIdentifier: "CellRIDHeader") as! SPOccupationCell
EditDropDown.anchorView = cellHeader.btnDots
EditDropDown.bottomOffset = CGPoint(x: 0, y: 40)
// You can also use localizationKeysDataSource instead. Check the docs.
EditDropDown.dataSource = [
"Edit",
"Make Default",
"Delete"
]
// Action triggered on selection
EditDropDown.selectionAction = { [weak self] (index, item) in
cellHeader.btnDots.setTitle(item, for: .normal)
if item == "Edit"
{
// I am Getting Cell Index but index is nil
let cell = self!.tableview.dequeueReusableCell(withIdentifier: "CellRIDHeader") as! SPOccupationCell
let indexPath = self!.tableview.indexPath(for: cell)
print(indexPath as Any)
let occupation_id = self!.arrayOccupation[(indexPath?.row)!].occupation_Main_id
print(occupation_id)
let next = self!.storyboard?.instantiateViewController(withIdentifier: "EditOccupationVCSID") as! EditOccupationVC
self!.navigationController?.pushViewController(next, animated: false)
next.occupationId = occupation_id
}
else if item == "Make Default"
{
print("B")
}
else if item == "Delete"
{
print("c")
}
}
}
I am assuming you are using DropDown library to show dropdown. There is a problem where you are getting cell when it is tapped so I have created a demo project (simple tableView and not with custom UITableViewCell) for you and I have added comment to explain the changes. Consider below code:
import UIKit
import DropDown
class ViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var items: [String] = ["We", "Heart", "Swift"]
let editDropDown = DropDown() //Object name should start with small letter
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
func setupGenderDropDown(cell: UITableViewCell) { //Pass your cell with argument and change type to your custom cell
//By changing cell argument with your custom cell you will get your button for anchor
editDropDown.anchorView = cell.textLabel
editDropDown.bottomOffset = CGPoint(x: 0, y: 40)
editDropDown.dataSource = [
"Edit",
"Make Default",
"Delete"
]
//Here you need to update selectionAction from their library page
editDropDown.selectionAction = { [unowned self] (index: Int, item: String) in
//Here you will get selected item and index
print("Selected item: \(item) at index: \(index)")
if item == "Edit"
{
print(item)
print(index)
}
else if item == "Make Default"
{
print("B")
}
else if item == "Delete"
{
print("c")
}
}
//This was missing in your code
editDropDown.show()
}
}
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "cell") as! UITableViewCell
cell.textLabel?.text = self.items[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//Get the selected cell this way
guard let indexPath = tableView.indexPathForSelectedRow else { return }
guard let currentCell = tableView.cellForRow(at: indexPath) else { return }
//Pass your selected cell to setupGenderDropDown method
setupGenderDropDown(cell: currentCell)
}
}
HERE you can check demo project. And it's created into Xcode 10.1