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
}
}
}
Related
I have a Scene in storyboard that contains HistoryTable with historyCell and own UserHistoryViewCell view. This cell and also table is set to User interaction Enabled in Traits and Interaction sections. Scrolling is disabled and Delay Touch Down is also disabled. This cell is not responding at didSelectRowAt func at short click (only when pressing longer than 5? secs). I have a Tap Gesture Recognizer in my Scene and also another table with same problem. I tried to disable Tap Gesture Recognizer, but it seems that it doesn't do anything special. I'm not sure where is problem, I have my tables delegated and using the code bellow. I also provide screenshots of Attributes inspector for the table and cell. Btw. My second table has sections, so its little bit messy.
Second Btw. I have delay touch down enabled at the screenshot, because it has no effect at all. Third Btw. I have historyButton in my historyTable which is for removing old records. It has no impact at the cell itself (I think) because same stuff happens to my second table without this button. Also it worked before I added sections to my second table.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var counter = 0
if tableView.tag == 1 {
counter = (UserDefaults.standard.stringArray(forKey: "HistoryArray") ?? [String]()).count
let base = 60
self.historyTableHeightConstraint.constant = CGFloat(base) + CGFloat(counter) * 40
} else {
switch section {
case 0:
counter = presenter.storelist?.count ?? 0
case 1:
counter = presenter.storelist?.count ?? 0
default:
counter = 0
notFoundLabel.isHidden = false
}
}
return counter
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView.tag == 1 {
let defaults = UserDefaults.standard
let userSearchHistory = defaults.stringArray(forKey: "HistoryArray") ?? [String]()
let cell = tableView.dequeueReusableCell(withIdentifier: "historyCell", for: indexPath) as! UserHistoryTableViewCell
cell.titleLabel.text = userSearchHistory.reversed()[indexPath.row]
cell.historyButton.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
cell.historyButton.tag = indexPath.row
if self.editable == true {
let newImage = UIImage(named: "RemoveIcon")
cell.historyButton.setImage(newImage, for: .normal)
cell.historyButton.isEnabled = true
} else {
let newImage = UIImage(named: "searchHistoryIcon")
cell.historyButton.setImage(newImage, for: .normal)
cell.historyButton.isEnabled = false
}
return cell
} else {
switch indexPath.section {
case 0:
let cell = tableView.dequeueReusableCell(withIdentifier: "shopSearchCell", for: indexPath) as! ShopSearchTableViewCell
cell.shopLabel.text = presenter.storelist?[indexPath.row].storename
return cell
case 1:
let cell = tableView.dequeueReusableCell(withIdentifier: "SearchResultCell", for: indexPath) as! SearchResultCell
cell.SearchResultLabel.text = presenter.storelist?[indexPath.row].storename
return cell
default:
return UITableViewCell()
}
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print(#function + "\(indexPath.row)")
}
func tableView(_ tableView: UITableView, titleForHeaderInSection
section: Int) -> String? {
if tableView.tag == 2 {
if section == 0 {
if self.tableView(tableView, numberOfRowsInSection: section) > 0 {
return "Search shop"
} else {
return nil
}
} else {
if self.tableView(tableView, numberOfRowsInSection: section) > 0 {
return "Search"
} else {
return nil
}
}
} else {
return nil
}
}
// Sectionæ•°
func numberOfSections(in tableView: UITableView) -> Int {
if tableView.tag == 2 {
return 2
}
return 1
}
I have implemented the following code to add expand/collapse feature to UITableView sections. When user click each section1, it expands and when we click the same section1 it collapses. But, I want the section1 to collapse, if I am expanding section2. How can I implement this feature to my code added below.
struct FaqData{
var faqHead = String()
var faqImage = String()
var questionArray : [(question : String, answer : String, answerurl : String)] = [(String,String,String)]()
var openSection = Bool()
}
var supportArray = [FaqData]()
func numberOfSections(in tableView: UITableView) -> Int {
return supportArray.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0{
return 1
}
else{
if supportArray[section].openSection == true{
return supportArray[section].questionArray.count + 1
}else{
return 1
}
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
tableView.separatorStyle = UITableViewCell.SeparatorStyle.none
if indexPath.section == 0{
let cell = tableView.dequeueReusableCell(withIdentifier: "SupportCenterID", for: indexPath) as! SupportCenterTableViewCell
cell.selectionStyle = UITableViewCell.SelectionStyle.none
cell.faqCollection.reloadData()
return cell
}
else{
if indexPath.row == 0{
let cell = tableView.dequeueReusableCell(withIdentifier: "SupportFaqID") as! SupportCenterFaqTableViewCell
cell.selectionStyle = UITableViewCell.SelectionStyle.none
let faqHead = supportArray[indexPath.section].faqHead
cell.imageText.text = faqHead.capitalized
cell.imageButton.setImage(UIImage(named: supportArray[indexPath.section].faqImage), for: .normal)
return cell
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: "QuestionID") as! SupportQuestionTableViewCell
cell.selectionStyle = UITableViewCell.SelectionStyle.none
cell.isSelected = true
cell.questionLabel.text = "Q.\(indexPath.row) " + supportArray[indexPath.section].questionArray[indexPath.row - 1].question
cell.answerLabel.text = supportArray[indexPath.section].questionArray[indexPath.row - 1].answer
print(supportArray[indexPath.section].questionArray[indexPath.row - 1].answerurl)
if supportArray[indexPath.section].questionArray[indexPath.row - 1].answerurl == ""{
cell.urlButton.isHidden = true
}
else{
cell.urlButton.isHidden = false
}
cell.urlButton.isHidden = true
cell.urlButton.tag = indexPath.row
UserDefaults.standard.set(indexPath.section, forKey: "SectionValue")
cell.urlButton.addTarget(self, action: #selector(urlButtonClicked(_:)), for: .touchUpInside)
cell.layoutMargins = UIEdgeInsets.zero
return cell
}
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if supportArray[indexPath.section].openSection == true{
if indexPath.section != 0{
if indexPath.row == 0{
let cell = tableView.cellForRow(at: indexPath) as! SupportCenterFaqTableViewCell
cell.faqView.backgroundColor = .white
cell.imageButton.tintColor = UIColor(hexString: "#D71B61")
cell.imageText.textColor = UIColor(hexString: "#D71B61")
}
}
supportArray[indexPath.section].openSection = false
let sections = IndexSet.init(integer: indexPath.section)
tableView.reloadSections(sections, with: .fade)
}
else{
supportArray[indexPath.section].openSection = true
let sections = IndexSet.init(integer: indexPath.section)
tableView.reloadSections(sections, with: .fade)
if indexPath.section != 0{
if indexPath.row == 0{
let cell = tableView.cellForRow(at: indexPath) as! SupportCenterFaqTableViewCell
cell.faqView.backgroundColor = UIColor(hexString: "#D71B61")
cell.imageButton.tintColor = .white
cell.imageText.textColor = .white
}
}
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
Can anyone provide a solution for this?
do this in didselecterow method. This is the else case of your condition
// You will need to reload multiple sections. So make an array.
var reloadSections = [Int]()
// find already opened array
if let alreadyOpenSection = supportArray.firstIndex(where: { (faq) -> Bool in
return faq.openSection
}) {
// if found, toggle the openSections bit
supportArray[alreadyOpenSection].openSection = false
// add it to reload sections array
reloadSections.append(alreadyOpenSection)
}
supportArray[indexPath.section].openSection = true
reloadSections.append(indexPath.section)
// create index set with reload sections array
let sections = IndexSet.init(reloadSections)
tableView.reloadSections(sections, with: .fade)
// below code is same
if indexPath.section != 0{
if indexPath.row == 0{
let cell = tableView.cellForRow(at: indexPath) as! SupportCenterFaqTableViewCell
cell.faqView.backgroundColor = UIColor(hexString: "#D71B61")
cell.imageButton.tintColor = .white
cell.imageText.textColor = .white
}
}
I have two arrays like
names = ["Gopal", "Harish", "Kartik","Raj", "Vishal", "Manoj", "James"]
StoredNames = ["kartik", "Vishal", "James"]
I am displaying names Array into tableview. But My Task is if names array contains StoredNames array elements, I need to change that particular cell colour.Could anyone guide me to do this task.I am using is code. but unable to compare with StoredNames array.
override func tableView(_ tableView: UITableView, willDisplay cell:UITableViewCell, forRowAt indexPath: IndexPath) {
cell.backgroundColor = .yellow
if let index = names.index(of: "kartik") {
cell.backgroundColor = indexPath.row == index ? .green : .white
}
return cell
}
After edit:
func filterRowsForSearchedText(_ searchText: String) {
filteredModels = models.filter({( model : Contact) -> Bool in
return model.name.lowercased().contains(searchText.lowercased())||model.number.lowercased().contains(searchText.lowercased())
})
contactsTableView.reloadData()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = contactsTableView.dequeueReusableCell(withIdentifier: "ContactsTableViewCell", for: indexPath) as! ContactsTableViewCell
let model: Contact
if searchController.isActive && searchController.searchBar.text != "" {
model = filteredModels[indexPath.row]
} else {
model = models[indexPath.row]
}
cell.nameLabel.text = model.name
cell.numberLabel.text = model.number
return cell
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if storedNumberArr.contains(numberArr[indexPath.row]) {
//Name is there, color it
cell.backgroundColor = .green
} else {
// Color for non existance.
cell.backgroundColor = .white
}
}
You can use contains(element). Keep in mind that else statement is necessary because of reusable functionality. Also variable names should be camelCase.
let names = ["Gopal","Harish","Kartik","Raj","Vishal","Manoj","James"]
let storedNames = ["kartik","Vishal","James"]
if storedNames.contains(names[indexPath.row]) {
//Name is there, color it
cell.backgroundColor = .green
} else {
// Color for non existance.
cell.backgroundColor = .white
}
As suggested by dahiya_boy, if you want to compare string discarding their cases you can replace above if-condition by this :
if storedNames.map({ $0.lowercased()}).contains(names[indexPath.row].lowercased()) {
Please use this in cellforrow at indepath
if(indexPath.row % 2 == 0) {
cell.backgroundColor = UIColor.init(rgb: 0xebebeb)
} else{
cell.backgroundColor = UIColor.init(rgb: 0xdcdcdc)
}
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
}
}
}
I have a tableview which is filled with fruit, vegetable ,Meat. I am having problem at this point when I change category using UIPickerView my previous data which is saved in array gets deleted.
I don't know how to handle this problem. How will I save my previous category data and also when user change category?
Below is some of my code which I am working on.
CellForRowAt
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "adddiseasefoodcell", for: indexPath) as! AddDiseaseTableViewCell
print(indexPath.row)
cell.foodname.text = foodname[indexPath.row]
cell.foodimg.image = imagereturn(urrl: foodimage[indexPath.row])
cell.unitlbl.text = foodunit[indexPath.row]
cell.callbl.text = foodcal[indexPath.row]
cell.switchFood.tag = indexPath.row
cell.switchFood.isUserInteractionEnabled = false
print(check[indexPath.row]!)
// check[indexPath.row] = false
if check[indexPath.row]!
{
cell.switchFood.isOn = true
}
else
{
cell.switchFood.isOn = false
}
cell.switchFood.addTarget(self, action: #selector(buttonClicked(Sender:)), for: UIControlEvents.touchUpInside)
return cell
}
SaveButtonCode
func buttonClicked(Sender:UIButton)
{
print(Sender.tag)
let index = NSIndexPath(row: Sender.tag,section:0)
let cell = foodnametableview.cellForRow(at:index as IndexPath) as! AddDiseaseTableViewCell
if check[Sender.tag]!
{
// cell.switchFood.isUserInteractionEnabled = true
cell.switchFood.isOn = false
check[Sender.tag] = false
}
else
{
// cell.switchFood.isUserInteractionEnabled = true
cell.switchFood.isOn = true
check[Sender.tag] = true
}
}
You need to create different Arrays for each of your Category. And than you have to do it like that:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if selectedCategory == .meat {
return meatArray.count
}
// same for other Catgories
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//Create cell and other configurations
if selectedCategory == .meat {
let selectedFood = meatArray(indexPath.row)
//use selectedFood object to get values and use it in the cell
}
return cell!
}
I think better way to implement this is to add element in array with categories and retrieve array data with its index accordingly. For this you have to save data in dictionary with category as key and elements as value.