Select cell from a saved indexPath - ios

I am trying to create a tableview that selects the cell using an indexPath.
I have saved the indexPath of selected cell & save it to my data array for each question. However when I reload the tableView how do I get the indexPath to change that particular cell's background view to how it looked when I select the previous button.
var dataArray: [MultipleChoice] = [
MultipleChoice(
question: "Question 1",
options: ["Answer 1", "Answer 2", "Answer 3", "Answer 4"],
rightAnswer: "Answer 1",
subject: "General",
idxPath: [0,0]),
MultipleChoice(
question: "Question 2",
options: ["Answer 1", "Answer 2", "Answer 3", "Answer 4"],
rightAnswer: "Answer 2",
subject: "General",
idxPath: [0,0]),
#IBAction func nextButtonPressed(_ sender: Any) {
if var index = dataBrain.questionNumber {
if index + 1 < dataBrain.dataArray.count {
index += 1
dataBrain.questionNumber = index
scoreLabel.text = "\(dataBrain.questionNumber! + 1)/\(dataBrain.dataArray.count)"
answerHidden = true
table.reloadData()
}
}
#IBAction func previousButtonPressed(_ sender: Any) {
if var index = dataBrain.questionNumber {
if index - 1 >= 0 {
index -= 1
dataBrain.questionNumber = index
scoreLabel.text = "\(dataBrain.questionNumber! + 1)/\(dataBrain.dataArray.count)"
table.reloadData()
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: AnswerTableViewCell.identifier) as! AnswerTableViewCell
//Load Options:
if let index = dataBrain.questionNumber {
let data = dataBrain.dataArray[index]
cell.answerLabel.text = data.options![indexPath.row - 1]
cell.selectionStyle = .none
}
//Load Right/Wrong Options
let index = dataBrain.questionNumber
let data = dataBrain.dataArray[index!]
let rightAnswer = data.rightAnswer!
if cell.answerLabel.text == rightAnswer {
cell.confirmButton.setImage(UIImage(systemName: "checkmark.circle"), for: .normal)
cell.confirmButton.imageView?.tintColor = UIColor.green
} else {
cell.confirmButton.setImage(UIImage(systemName: "xmark.circle"), for: .normal)
cell.confirmButton.imageView?.tintColor = UIColor.red
}
//Load Background Color/Text
cell.delegate = self
cell.selectedBackgroundView = .none
cell.confirmButton.isHidden = answerHidden
let selectedCell = dataBrain.dataArray[index!].idxPath
if selectedCell == [0,0] {
cell.answerView.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
cell.answerLabel.textColor = #colorLiteral(red: 0.4228360057, green: 0.4478931427, blue: 0.4731111526, alpha: 1)
} else {
table.selectRow(at: selectedCell, animated: false, scrollPosition: .none)
}
return cell

When you implement tableView(_ tableView: UITableView, cellForRowAt ..., your job is to return a cell for the given indexPath -- do not change the table. Your source of truth is dataBrain.dataArray -- get the information, put it in a cell, and return it. That's it.
So, in this code:
let selectedCell = dataBrain.dataArray[index!].idxPath
if selectedCell == [0,0] {
cell.answerView.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
cell.answerLabel.textColor = #colorLiteral(red: 0.4228360057, green: 0.478931427, blue: 0.4731111526, alpha: 1)
} else {
table.selectRow(at: selectedCell, animated: false, scrollPosition: .none)
}
The if should be more like this:
if selectedCell[0] == indexPath.section, selectedCell[1] == indexPath.row {
// The cell I am making is selected -- set it up
} else {
// The cell I am making is not selected, set it up also
// (it could be a reused cell that is colored for selection, so ALWAYS set the properties.
}
Do not call table.selectRow
Now, when you want a cell to change, just reload it. Either reloadData (not ideal, but you can do it to make sure things work), or the other reload methods that target specific changes.

Related

TableView expand and collapse cells in Swift

Hi I've watched a tutorial about this issue and I can open and close tapped sections in my table view, but if a section is open and I am going to open another section, I want the previous one to be closed, but I can't.
TableViewCodes
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let section = sections[section]
if section.isOpened {
return section.options.count + 1
} else {
return 1
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "headerCell", for: indexPath) as? HeaderView else {return UITableViewCell()}
cell.backgroundColor = #colorLiteral(red: 0.9607108235, green: 0.9608257413, blue: 0.9606716037, alpha: 1)
cell.titleLabel?.text = sections[indexPath.section].title
return cell
} else {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath) as? CustomTableViewCell else {return UITableViewCell()}
cell.backgroundColor = #colorLiteral(red: 0.9607108235, green: 0.9608257413, blue: 0.9606716037, alpha: 1)
cell.titleLabel?.text = sections[indexPath.section].options[indexPath.row - 1]
return cell
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
sections[indexPath.section].isOpened = !sections[indexPath.section].isOpened
tableView.reloadSections([indexPath.section], with: .none)
}
Section Model
class Section {
let title: String
let options: [String]
var isOpened: Bool = false
init(title: String, options: [String], isOpened: Bool = false) {
self.title = title
self.options = options
self.isOpened = isOpened
}
}
ViewDidLoad
sections = [
Section(title: "Spor Giyim 1", options: [1,2,3].compactMap({ return "Cell \($0)" }), isOpened: true),
Section(title: "Spor Giyim 2", options: [1,2,3].compactMap({ return "Cell \($0)" }), isOpened: false),
Section(title: "Spor Giyim 3", options: [1,2,3].compactMap({ return "Cell \($0)" }), isOpened: false),
Section(title: "Spor Giyim 4", options: [1,2,3].compactMap({ return "Cell \($0)" }), isOpened: false)
]
You need to reset them all to false then toggle the current state of the clicked section
let toSet = !sections[indexPath.section].isOpened
sections.forEach {
$0.isOpened = false
}
sections[indexPath.section].isOpened = toSet
tableView.reloadData()
Store a reference to any open section in the viewController, use this to reset it to closed, and then reload both that section and the one you want to open:
class myVC: UIViewController {
var openSection: Int?
// rest of the VC...
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if let openSection = openSection, openSection != indexpath.section {
section[openSection].isOpened = false
section[indexPath.section].isOpened = true
tableView.reloadSections([ openSection, indexPath.section], with: .automatic)
openSection = indexPath.section
} else {
sections[indexPath.section].isOpened.toggle()
tableView.reloadSections([indexPath.section], with: .automatic)
openSection = sections[indexPath.section].isOpened ? indexPath.section : nil
}
}

FloatingPanel not appearing - Swift Xcode

I have a view controller which contains a table view. In this view controller, I've also set up a floating panel. The floating panel is not appearing for some reason, however. I know the ContentViewController is working, so I didn't include that code. The error is somewhere in this code and I can't find it. It's like the FloatingPanel is just not being added to the view.
import Foundation
import UIKit
import FloatingPanel
class Section {
let title: String
let options: [String]
var isOpened: Bool = false
init(title: String,
options: [String],
isOpened: Bool
) {
self.title = title
self.options = options
self.isOpened = isOpened
}
}
class PicsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UINavigationControllerDelegate, FloatingPanelControllerDelegate {
#IBOutlet weak var addButton: UIButton!
private let picsTableView: UITableView = {
let picsTableView = UITableView()
picsTableView.register(UITableViewCell.self,
forCellReuseIdentifier: "cell")
return picsTableView
}()
private var sections = [Section]()
let backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
/*------------START FLOATING PANEL-------------*/
var fpc: FloatingPanelController!
override func viewDidLoad() {
super.viewDidLoad()
print("PicsViewController LAUNCHED!!")
fpc = FloatingPanelController()
fpc.delegate = self
// guard let contentVC = storyboard?.instantiateViewController(identifier: "fpc_content") as? ContentViewController else {
// print("Failed to instantiate storyboard")
// return
// }
let contentVC = ContentViewController()
fpc.set(contentViewController: contentVC)
// fpc.track(scrollView: contentVC.collectionView)
fpc.addPanel(toParent: self)
/*------------END FLOATING PANEL-------------*/
// Set up models
picsTableView.delegate = self
picsTableView.dataSource = self
picsTableView.frame = view.bounds
picsTableView.backgroundColor = backgroundColor
view.addSubview(picsTableView)
sections = [
Section(title: "Section 1", options: ["Test 1", "Test 2", "Test 3"], isOpened: false),
Section(title: "Section 2", options: ["Test 1", "Test 2", "Test 3"], isOpened: false),
Section(title: "Section 3", options: ["Test 1", "Test 2", "Test 3"], isOpened: false),
Section(title: "Section 4", options: ["Test 1", "Test 2", "Test 3"], isOpened: false)
]
// get rid of extra table view cells
picsTableView.tableFooterView = UIView()
// customize button
addButton.layer.cornerRadius = 0.5 * addButton.bounds.size.width
addButton.clipsToBounds = true
addButton.backgroundColor = .red
addButton.tintColor = .white
addButton.setImage(#imageLiteral(resourceName: "plus-5-512"), for: .normal)
view.bringSubviewToFront(addButton)
}
#IBAction func addButtonTapped(_ sender: Any) {
print("Add button tapped")
}
func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let section = sections[section]
if section.isOpened {
return section.options.count + 1
} else {
return 1
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = picsTableView.dequeueReusableCell(
withIdentifier: "cell",
for: indexPath
)
cell.backgroundColor = .clear
cell.textLabel?.textColor = .black
if indexPath.row == 0 {
cell.textLabel?.text = sections[indexPath.section].title
} else {
cell.textLabel?.text = sections[indexPath.section].options[indexPath.row - 1]
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
picsTableView.deselectRow(at: indexPath, animated: true)
if indexPath.row == 0 {
sections[indexPath.section].isOpened = !sections[indexPath.section].isOpened
picsTableView.reloadSections([indexPath.section], with: .none)
} else {
print("Tapped sub cell \(indexPath.row)")
}
}
}
Typically, 3 or 4 statements to add any view controller as subview to any view controllers are
let viewController = SomeViewController()
self.addChild(viewController)
self.view.addSubview(viewController.view)
viewController.didMove(toParent: self)
Because you havent provided the implementation for addPanel where you are calling fpc.addPanel(toParent: self), I assume it does something similar to what I have written above, if I were to write it, I might write something like
func addPanel(toParent: UIViewController) {
toParent.addChild(self)
toParent.view.addSubview(self.view)
//add constraints or set frames for your subview
self.didMove(toParent: toParent)
}
Finally, you are adding multiple view's to your view controller's view namely a floating panel, tableView, and a button. Because you add panel before you add all other views it might be hidden under other subviews like tableView, you can obviously check this hypothesis using view debugger, and simplest way to fix it would be to use bringSubviewToFront, but issue is you are not holding the reference of FloatingPanelController's view so you can try adding self.view.bringSubviewToFront(fpc.view) as last statement of ViewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
// all other codes of yours
self.view.bringSubviewToFront(fpc.view)
}
and for some reason if that doesnt work call fpc.addPanel(toParent: self) as last statement of ViewDidLoad instead of adding in between and add bringSubviewToFront as last statement of addPanel(toParent method
override func viewDidLoad() {
super.viewDidLoad()
print("PicsViewController LAUNCHED!!")
fpc = FloatingPanelController()
fpc.delegate = self
let contentVC = ContentViewController()
fpc.set(contentViewController: contentVC)
picsTableView.delegate = self
picsTableView.dataSource = self
picsTableView.frame = view.bounds
picsTableView.backgroundColor = backgroundColor
view.addSubview(picsTableView)
sections = [
Section(title: "Section 1", options: ["Test 1", "Test 2", "Test 3"], isOpened: false),
Section(title: "Section 2", options: ["Test 1", "Test 2", "Test 3"], isOpened: false),
Section(title: "Section 3", options: ["Test 1", "Test 2", "Test 3"], isOpened: false),
Section(title: "Section 4", options: ["Test 1", "Test 2", "Test 3"], isOpened: false)
]
// get rid of extra table view cells
picsTableView.tableFooterView = UIView()
// customize button
addButton.layer.cornerRadius = 0.5 * addButton.bounds.size.width
addButton.clipsToBounds = true
addButton.backgroundColor = .red
addButton.tintColor = .white
addButton.setImage(#imageLiteral(resourceName: "plus-5-512"), for: .normal)
view.bringSubviewToFront(addButton)
fpc.addPanel(toParent: self) //added as last statement
}
and
func addPanel(toParent: UIViewController) {
toParent.addChild(self)
toParent.view.addSubview(self.view)
self.didMove(toParent: toParent)
toParent.view.bringSubviewToFront(self.view)
}

How to fix UITableView cell repeat in swift 4

When I create a new cell it will automatically mark
or when I marked the first one, I was creating multiple
Cell, there will be duplicates marked
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let itemCellIdentifier = "itemCell"
guard let itemCell = itemCardTableView.dequeueReusableCell(withIdentifier: itemCellIdentifier, for: indexPath) as? ItemCardTableViewCell else {
return UITableViewCell()
}
let itemCard = dataManager.items[indexPath.row]
itemCell.itemTitle.text = itemCard.title
if itemCard.isFinish {
itemCell.itemCellView.backgroundColor = UIColor(red: 0, green: 123, blue: 0)
}
return itemCell
}
Add cell method
let confirm = UIAlertAction(title: "確認", style: .default) { (action: UIAlertAction) in
guard let title = addAlert.textFields?.first?.text else { return }
let newItem = ItemCard(title: title, isFinish: false)
self.dataManager.items.append(newItem)
let indexPath = IndexPath(row: self.itemCardTableView.numberOfRows(inSection: 0), section: 0)
self.itemCardTableView.insertRows(at: [indexPath], with: .left)
When I create new data isFinish = false
How can I fix data duplication?
You should provide else case to set default background color.
if itemCard.isFinish {
itemCell.itemCellView.backgroundColor = UIColor(red: 0, green: 123, blue: 0)
} else {
itemCell.itemCellView.backgroundColor = UIColor.white
}
If I understood your question right, You should hold the isFinish flag somewhere out of the cell, because it's being reused by tableView.
You can create the finished = [Bool]() is your UIViewController and every time check finished[indexPath.row] to see if it's marked or not and pass the boolean to your cell.

How to reload the collection view data in table view cell after clicking another table view cell's collection view data in swift 3?

Here I am loading collection view data dynamically in table view cell and table view cells also created on dynamic json array count and here after selecting any element in collection view which is in first table view cell then the collection view needs to be reloaded with new data which is in second table view cell can anyone help me how to reload the collection view in second table view cell swift 3 if this is not possible can anyone provide me any alternative layout to implement this ?
Here is my cell for row method
if indexPath.section == 0 {
let cell = addToCartTableView.dequeueReusableCell(withIdentifier: "addToCartCollectionCell") as! AddToCartCollectionTableViewCell
cell.configurableProduct = self.detailModel
print(self.detailModel)
cell.collectionView.tag = indexPath.row
self.addToCartTableView.setNeedsLayout()
self.addToCartTableView.layoutIfNeeded()
cell.collectionView.reloadData()
cell.cellLabel.text = detailModel?.extensionAttribute?.productOptions[indexPath.row].label
if detailModel?.extensionAttribute?.productOptions[indexPath.row].label == "Size"{
cell.sizeGuideBtn.isHidden = false
}else{
cell.sizeGuideBtn.isHidden = true
}
cell.getCurrentRow = indexPath.row
return cell
}else {
let cell = addToCartTableView.dequeueReusableCell(withIdentifier: "addToCartQtyCell") as! AddToCartQuantityTableViewCell
self.addToCartTableView.setNeedsLayout()
self.addToCartTableView.layoutIfNeeded()
cell.QtyLabel.text = "Qty"
return cell
}
Here is my table view cell code
override func awakeFromNib() {
super.awakeFromNib()
collectionView.delegate = self
collectionView.dataSource = self
print(getCurrentRow)
// Initialization code
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 50, height: 30)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
print(configurableProduct?.extensionAttribute?.productOptions[getCurrentRow].values.count)
return (configurableProduct?.extensionAttribute?.productOptions[getCurrentRow].values.count)!
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! AddToCartCollectionViewCell
if indexPath.item == 0 {
let items = configurableProduct?.extensionAttribute?.productOptions[getCurrentRow].values[indexPath.row]
cell.collectionLabel.text = "\(items?.valueIndex as! Int)"
if indexPath.item == self.selectedIndex{
cell.backgroundColor = #colorLiteral(red: 0.007509540026, green: 0.6581087804, blue: 0.01165772038, alpha: 1)
}else if self.selectedIndex == nil {
cell.backgroundColor = UIColor.white
}else{
cell.backgroundColor = UIColor.white
}
}
else {
if selectedValue != nil {
for item in (self.configurableProduct?.extensionAttribute?.productStock)! {
// let jsonStr = "{\"label\":\"57-175\",\"stock\":0}"
let dict = try! JSONSerialization.jsonObject(with: item.data(using: .utf8)!, options: []) as! [String:Any]
let labelValue = dict["label"] as! String
print(labelValue)
let values:[String] = labelValue.components(separatedBy: "-")
print(values)
self.colorNumber = Int(values[0])
self.sizeNumber = Int(values[1])
let stock = dict["stock"] as! Int
let value = selectedValue
if value == self.colorNumber {
if stock != 0 {
self.sizeArray.append(self.sizeNumber!)
print(self.sizeArray)
cell.collectionLabel.text = "\(self.sizeNumber)"
}
}
}
if indexPath.item == self.selectedIndex{
cell.backgroundColor = #colorLiteral(red: 0.007509540026, green: 0.6581087804, blue: 0.01165772038, alpha: 1)
}else if self.selectedIndex == nil {
cell.backgroundColor = UIColor.white
}else{
cell.backgroundColor = UIColor.white
}
}
else {
let items = configurableProduct?.extensionAttribute?.productOptions[getCurrentRow].values[indexPath.item]
print(items?.valueIndex)
for item in (self.configurableProduct?.extensionAttribute?.productStock)! {
// let jsonStr = "{\"label\":\"57-175\",\"stock\":0}"
let dict = try! JSONSerialization.jsonObject(with: item.data(using: .utf8)!, options: []) as! [String:Any]
let labelValue = dict["label"] as! String
print(labelValue)
let values:[String] = labelValue.components(separatedBy: "-")
print(values)
self.colorNumber = Int(values[0])
self.sizeNumber = Int(values[1])
let stock = dict["stock"] as! Int
let value = self.selectedIndex
if value == self.colorNumber {
if stock != 0 {
self.sizeArray.append(self.sizeNumber!)
print(self.sizeArray)
cell.collectionLabel.text = "\(items?.valueIndex as! Int)"
}
}else {
cell.collectionLabel.text = "\(items?.valueIndex as! Int)"
}
}
if indexPath.item == self.selectedIndex{
cell.backgroundColor = #colorLiteral(red: 0.007509540026, green: 0.6581087804, blue: 0.01165772038, alpha: 1)
}else if self.selectedIndex == nil {
cell.backgroundColor = UIColor.white
}else{
cell.backgroundColor = UIColor.white
}
}
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if collectionView.tag == 0 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! AddToCartCollectionViewCell
cell.backgroundColor = #colorLiteral(red: 0.007509540026, green: 0.6581087804, blue: 0.01165772038, alpha: 1)
cell.collectionLabel.layer.cornerRadius = 15
cell.collectionLabel.layer.borderColor = #colorLiteral(red: 0.007509540026, green: 0.6581087804, blue: 0.01165772038, alpha: 1)
self.dataSelected = true
self.selectedIndex = indexPath.item
print(self.selectedIndex)
self.collectionView.reloadData()
self.sizeArray.removeAll()
self.selectedValue = configurableProduct?.extensionAttribute?.productOptions[1].values[indexPath.item].valueIndex
self.getCurrentRow = 1
self.collectionView.reloadData()
print(self.selectedValue)
}
else {
print(collectionView.tag)
}
}
here is my layout image
in didSelectItemAt of collection view, reload the table cell which contains size by doing
let indexpath = IndexPath(item: value, section: 0)
tableview.reloadRows(at: [indexpath], with: .none)
here value is position of row which you want to upate
Create a new variable "cellObj" which data type is same as you custom cell where you added collection view.
var cellObj:AddToCartCollectionTableViewCell!
After add assign cellObj value after this line.
let cell = addToCartTableView.dequeueReusableCell(withIdentifier: "addToCartCollectionCell") as! AddToCartCollectionTableViewCell
cellObj = cell
*** After doing you are able to reload collection view any where.
cellObj.collectionView.reloadData()
DispatchQueue.main.async {
// cell!.tableView.reloadData()
collectionView.reloadItems(at: [indexPath])
cell!.tableView.reloadData()
}
})

Select ALL TableView Rows Programmatically Using selectRowAtIndexPath

I'm trying to programmatically select all rows in my tableview using the following code:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:myTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell") as! myTableViewCell
cell.accessoryType = .None
if allJobsSelected {
let bgColorView = UIView()
bgColorView.backgroundColor = UIColor(red: 250/255, green: 182/255, blue: 17/255, alpha: 1)
cell.contentView.backgroundColor = UIColor(red: 250/255, green: 182/255, blue: 17/255, alpha: 1)
cell.selectedBackgroundView = bgColorView
cell.accessoryType = .Checkmark
cell.highlighted = false
cell.selected = true
// cell.accessoryType = .Checkmark
self.tableView.selectRowAtIndexPath(indexPath, animated: true, scrollPosition: UITableViewScrollPosition.None)
self.tableView(self.tableView, didSelectRowAtIndexPath: indexPath)
}
var job: Jobs!
job = jobs[UInt(indexPath.row)] as! Jobs
cell.reports2JobTitle.text = job.jobTitle
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.tableView.allowsMultipleSelection = true
if let cell:myTableViewCell = tableView.cellForRowAtIndexPath(indexPath) as? myTableViewCell {
let bgColorView = UIView()
bgColorView.backgroundColor = UIColor(red: 250/255, green: 182/255, blue: 17/255, alpha: 1)
cell.contentView.backgroundColor = UIColor(red: 250/255, green: 182/255, blue: 17/255, alpha: 1)
cell.selectedBackgroundView = bgColorView
cell.accessoryType = .Checkmark
cell.highlighted = false
self.tableView.selectRowAtIndexPath(indexPath, animated: true, scrollPosition: UITableViewScrollPosition.Bottom)
}
}
My issue is that only the rows that have been dequeued are added to my table's data model when I segue to the next viewcontroller. In order to add all the rows to my table's data model I have to manually scroll through the whole table. How can I change this so all the selected rows are added to my table's data model without having to scroll through the whole table?
What I cannot understand is that after all my rows are selected I then loop through my indexPaths as follows but not all of the indexPaths are added unless I first scroll through the entire table.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "reportsDisplay") {
let controller = segue.destinationViewController as! ReportsDisplayViewController
var selectedJob : Jobs!
if let indexPaths = tableView.indexPathsForSelectedRows {
for i in 0 ..< indexPaths.count {
let thisPath = indexPaths[i]
selectedJob = jobs[UInt(thisPath.row)] as! Jobs
let jobTitle = selectedJob.jobTitle
let id = selectedJob.identifier
jobsToReport.append(jobTitle)
jobsID.append(id)
}
}
controller.reportedJobs = jobsToReport
controller.idOfJobs = jobsID
}
}
For Swift 3 and answering your question literally, regardless of your code.
func selectAllRows() {
for section in 0..<tableView.numberOfSections {
for row in 0..<tableView.numberOfRows(inSection: section) {
tableView.selectRow(at: IndexPath(row: row, section: section), animated: false, scrollPosition: .none)
}
}
}
If you want to inform the tableview delegate, use this method:
func selectAllRows() {
for section in 0..<tableView.numberOfSections {
for row in 0..<tableView.numberOfRows(inSection: section) {
let indexPath = IndexPath(row: row, section: section)
_ = tableView.delegate?.tableView?(tableView, willSelectRowAt: indexPath)
tableView.selectRow(at: indexPath, animated: false, scrollPosition: .none)
tableView.delegate?.tableView?(tableView, didSelectRowAt: indexPath)
}
}
}
At the time allJobsSelected becomes true, you need to call the UITableView method selectRowAtIndexPath(_:animated:scrollPosition:) for each row of your table. In my case, I attached this functionality to the right bar button item which I named Select All. Calling this from cellForRowAtIndexPath is surely not the right place.
#IBAction func doSelectAll(sender: UIBarButtonItem) {
let totalRows = tableView.numberOfRowsInSection(0)
for row in 0..<totalRows {
tableView.selectRowAtIndexPath(NSIndexPath(forRow: row, inSection: 0), animated: false, scrollPosition: UITableViewScrollPosition.None)
}
}
Functional solution (Swift 5.1)
extension UITableViewDataSource where Self: UITableView {
/**
* Returns all IndexPath's in a table
* ## Examples:
* table.indexPaths.forEach {
* selectRow(at: $0, animated: true, scrollPosition: .none) // selects all cells
* }
*/
public var indexPaths: [IndexPath] {
return (0..<self.numberOfSections).indices.map { (sectionIndex: Int) -> [IndexPath] in
(0..<self.numberOfRows(inSection: sectionIndex)).indices.compactMap { (rowIndex: Int) -> IndexPath? in
IndexPath(row: rowIndex, section: sectionIndex)
}
}.flatMap { $0 }
}
}
Solution for Swift 5.5
This method can be logically made an extension of UITableView and must be called from the main thread:
extension UITableView {
// Must be called from the main thread
func selectAllRows() {
let totalRows = self.numberOfRows(inSection: 0)
for row in 0..<totalRows {
self.selectRow(at: IndexPath(row: row, section: 0), animated: true, scrollPosition: .none)
}
}
}
Note: this code is only for the only section

Resources