Im trying to save and load choice from TableView Multiple checkmarks.
I have a code ready, but I don't know how to save the selection. And how to load the selection at the opening of the list.
MY CODE:
var selectedCells = [IndexPath]()
var selectedAreas = [String]()
var Areas = [] //my text for the cells..
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return Areas.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")!
cell.textLabel?.text = Areas[indexPath.row]
cell.accessoryType = selectedCells.contains(indexPath) ? .checkmark : .none
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedCell = tableView.cellForRow(at: indexPath)
selectedCells.append(indexPath)
if selectedCell?.accessoryType == .checkmark {
if let indexremove = selectedAreas.firstIndex(of: (Areas[indexPath.row])) {
selectedAreas.remove(at: indexremove)
}
selectedCell?.accessoryType = .none
print(selectedCells)
print(selectedAreas)
print("remove ")
selectedCells = selectedCells.filter {$0 != indexPath}
} else {
print(selectedCells)
print(selectedAreas)
print("add")
selectedAreas.append(Areas[indexPath.row])
selectedCell?.accessoryType = .checkmark
}
}
Don't use multiple arrays as data source. That's pretty bad practice and inefficient.
Delete them
var selectedCells = [IndexPath]()
var selectedAreas = [String]()
Declare Area as struct and add an isSelected member
struct Area {
let name : String
var isSelected : Bool
init(name : String, isSelected : Bool = false) {
self.name = name
self.isSelected = isSelected
}
}
var areas = [Area(name: "Foo"), Area(name: "Bar")]
In cellForRowAt assign the checkmark depending on isSelected
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let area = areas[indexPath.row]
cell.textLabel?.text = area.name
cell.accessoryType = area.isSelected ? .checkmark : .none
return cell
}
In didSelectRow toggle isSelected and reload the row (yes, only two lines of code)
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
areas[indexPath.row].isSelected.toggle()
tableView.reloadRows(at: [indexPath], with: .none)
}
You get the selected areas with
let selectedAreas = areas.filter{$0.isSelected}
and an array of the names
let selectedAreaNames = areas.filter{$0.isSelected}.map{$0.name}
To load and save the names to UserDefaults add these two methods
func saveSelection()
{
let selectedAreaNames = areas.filter{$0.isSelected}.map{$0.name}
UserDefaults.standard.set(selectedAreaNames, forKey: "selectedNames")
}
func loadSelection()
{
guard let selectedAreaNames = UserDefaults.standard.array(forKey: "selectedNames") as? [String] else { return }
for (index, area) in areas.enumerated() {
areas[index].isSelected = selectedAreaNames.contains(area.name)
}
tableView.reloadData()
}
Related
I have a tableView that allows users to make multiple selections from an array of data,
When the user clicks done, I would like the selected text to be then transferred over to another tableViews textView
Is there a way to transfer over the selected text and have the text separated by a , ?
I am coding programmatically.
var checked = [Int]()
var items = [String]()
var selectedItems = [String]()
#objc func done() {
let hud = JGProgressHUD(style: .dark)
hud.textLabel.text = "Saving!"
hud.show(in: view)
dismiss(animated: true, completion: nil)
hud.dismiss()
let aCell = aboutCell(style: .default, reuseIdentifier: nil)
aCell.textField3.text = selectedItems.joined(separator: ",")
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableView.cellForRow(at: indexPath)?.accessoryType == UITableViewCell.AccessoryType.checkmark {
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCell.AccessoryType.none
} else {
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCell.AccessoryType.checkmark
if selectedItems.contains(items[indexPath.row]) {
selectedItems.remove(at: selectedItems.firstIndex(of: items[indexPath.row])!)
} else {
selectedItems.append(items[indexPath.row])
}
checked.append(indexPath.row)
}
}
According to my understanding to the question, these are my thoughts:
1. First setup necessary variables
var items = [String]() // data to display in tableview
var selectedItems = [String]() // here all the selected datas are stored
2. Store the selected items data from the didSelectRowAt delegate method
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if selectedItems.contains(items[indexPath.row]) { //check if the selected already contains the items and if contains remove it
selectedItems.remove(at: selectedItems.firstIndex(of: items[indexPath.row])!)
} else { // append the required items
selectedItems.append(items[indexPath.row])
}
// ..... other codes here
}
3. on done button
let requiredText = selectedItems.joined(separator: ",")
// pass this data through delegate method
There is no need to create an array for the selected items. You can simply call tableview method selectRow(at:animated:scrollPosition:) when selecting a row and when you need to get the selected rows just call tableview instance property indexPathsForSelectedRows. Then you just need to join the selected rows with a comma and use the resulting string in your textview or textfield. Don't forget to implement didDeselectRowAt item method as well to deselectRow.
import UIKit
class TableViewController: UITableViewController {
var items: [String] = ["1st", "2nd", "3rd", "4th", "5th"]
override func viewDidLoad() {
super.viewDidLoad()
tableView.allowsMultipleSelection = true
}
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if let cell = tableView.cellForRow(at: indexPath) {
cell.accessoryType = .none
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.selectRow(at: indexPath, animated: true, scrollPosition: .none)
if let cell = tableView.cellForRow(at: indexPath) {
cell.accessoryType = .checkmark
}
}
func done() {
if let indexPaths = tableView.indexPathsForSelectedRows {
// note that this will preserve the order that the rows where selected. Just sort the indexPaths if you need it sorted.
let string = indexPaths.map { items[$0.row] }.joined(separator: ",")
print(string)
// your code
}
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCellID", for: indexPath) as! TableViewCell
cell.textLabel?.text = items[indexPath.row]
cell.accessoryType = cell.isSelected ? .checkmark : .none
return cell
}
}
I have made a table view in a view controller and populating it programmatically. I am able to checkmark on cell at a time as i wanted but when i come back to that screen, it is not there.
These are my arrays:
let devCourses = [("Sound"),("Vibrate"),("Both"),("None")]
let devCousesImages = [UIImage(named: "speaker"), UIImage(named: "Group 1094"), UIImage(named: "Group 1093"), UIImage(named: "speaker-1")]
Here is my code for didSelectRowAt:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
Here is the code for didDeselectRowAt:
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
tableView.cellForRow(at: indexPath)?.accessoryType = .none
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell=tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath as IndexPath) as! VibTableViewCell
let courseTitle = devCourses[indexPath .row]
let Images = devCousesImages[indexPath .row]
cell.label.text=courseTitle
cell.label.textColor = UIColor.darkGray
cell.photo.image=Images
return cell
}
I want the checkmark to be there when i get back to the screen
You can use my solution.
Save state of your cells in plist file with NSCoder. Even you restart your app - you don't lose your data.
import UIKit
class TableViewController: UITableViewController {
var itemsArray : [Item] = [Item(name: "mom", done: true), Item(name: "pap", done: false), Item(name: "Lena", done: false), Item(name: "Gleb", done: false), Item(name: "Sasha", done: false), Item(name: "Max", done: false)]
/* path to custom plist file */
let dataFilePath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("Items.plist")
override func viewDidLoad() {
super.viewDidLoad()
if let filePath = dataFilePath {
print(filePath)
}
loadData()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return itemsArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let item = itemsArray[indexPath.row]
cell.accessoryType = item.done ? .checkmark : .none
cell.textLabel?.text = item.name
// Configure the cell...
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
itemsArray[indexPath.row].done = !itemsArray[indexPath.row].done
/* when state is changed - save it to plist file */
saveDate()
tableView.deselectRow(at: indexPath, animated: true)
}
/* save array to plist file (you can see it inside folder from consol) */
func saveDate() {
let encoder = PropertyListEncoder()
do {
let data = try encoder.encode(itemsArray)
try data.write(to: dataFilePath!)
} catch {
print(error.localizedDescription)
}
self.tableView.reloadData()
}
/* load data from plist file */
func loadData() {
if let data = try? Data(contentsOf: dataFilePath!) {
let decoder = PropertyListDecoder()
do {
itemsArray = try decoder.decode([Item].self, from: data)
} catch {
print(error.localizedDescription)
}
}
}
}
dataModel:
import Foundation
struct Item : Encodable, Decodable {
var name : String = ""
var done : Bool = false
}
Make a dictionary [IndexPath:Bool] to keep track of the state of which rows are selected.
var dict: [IndexPath:Bool] = [:]
in tableView(_:, didSelectRowAt:) add the following line:
dict[indexPath] = true
in tableView(_:, didDeselectRowAt:) add the following line:
dict[indexPath] = false
in tableView(_:, cellForRowAt:) add the following lines:
let selected = dict[indexPath] ?? false
cell.accessoryType = selected ? .checkmark : .none
As you want to come back to view controller to show selected cell. then you are to maintain selected cell array and after that in viewDidLoad/ viewWillappear to set selected cell as below code
for index in selectedArray {
self.tableView.selectRow(at: IndexPath(row: index, section: 0), animated: false, scrollPosition: .none)
}
First of all rather than multiple arrays use a struct for the data source.
And don't use extra arrays or dictionaries to maintain the selection either, this is error-prone and unnecessarily expensive.
Add a boolean member to the struct for the selected state.
struct Course : Codable {
let name : String
let image : String
var isSelected : Bool
}
Declare the data source array
var courses = [Course(name: "Sound", image: "speaker", isSelected: false),
Course(name: "Vibrate", image: "Group 1094", isSelected: false),
Course(name: "Both", image: "Group 1093", isSelected: false),
Course(name: "None", image: "speaker-1", isSelected: false)]
In cellForRowAt set the checkmark depending on isSelected
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! VibTableViewCell
let course = courses[indexPath.row]
cell.label.text = course.name
// define the text color in Interface Builder
// cell.label.textColor = UIColor.darkGray
cell.photo.image = UIImage(named: course.image)
cell.accessoryType = course.isSelected ? .checkmark : .none
return cell
}
In didSelectRowAt toggle the isSelected value in the data source and reload the row
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
courses[indexPath.row].isSelected.toggle()
tableView.reloadRows(at: indexPath, with: .none)
}
Finally delete the method didDeselectRowAt
To save the array you could write
do {
let data = try JSONEncoder().encode(courses)
UserDefaults.standard.set(data, forKey: "Courses")
} catch { print(error) }
It is posible to add a select all option in TableView Multiple checkmarks...?
I have a code ready, and I try to do this function. please help me !
CODE:
struct Area {
let name : String
var isSelected : Bool
init(name : String, isSelected : Bool = false) {
self.name = name
self.isSelected = isSelected
}
}
var areas = [Area(name: "Select all"),Area(name: "a"),Area(name: "b"),Area(name: "c"),Area(name: "d"]
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return areas.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let area = areas[indexPath.row]
cell.textLabel?.text = area.name
cell.accessoryType = area.isSelected ? .checkmark : .none
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
areas[indexPath.row].isSelected.toggle()
tableView.reloadRows(at: [indexPath], with: .none)
let selectedAreas = areas.filter{$0.isSelected}.map{$0.name}
print(selectedAreas)
}
Thanks.
You have to check if the user selected the first row ("Select all") and update the other rows accordingly:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// toggle the selected area
areas[indexPath.row].isSelected.toggle()
// save the new state for later use
let isSelected = areas[indexPath.row].isSelected
if indexPath.row == 0 {
// "Select all" was selected – update all areas
for i in 1..<areas.count {
areas[i].isSelected = isSelected
}
// update UI
tableView.visibleCells.forEach { $0.accessoryType = isSelected ? .checkmark : .none }
} else {
// update UI
tableView.cellForRow(at: indexPath)?.accessoryType = isSelected ? .checkmark : .none
}
tableView.deselectRow(at: indexPath, animated: true)
}
Recommendation
To separate concerns visually you could also use an own table view section for the "Select all" row. In that case some more changes are necessary:
var areas = [
// you do not need an area for "Select all" any longer
Area(name: "a"),
Area(name: "b"),
Area(name: "c"),
Area(name: "d")
]
var allSelected: Bool {
// helper var to see if all areas are currently selected
return areas.filter({!$0.isSelected}).isEmpty
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
switch section {
case 1: return "Areas"
default: return nil
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section {
case 0: return 1 // select all
case 1: return areas.count
default:
// we should never get here
fatalError()
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.selectionStyle = .none
if indexPath.section == 0 {
cell.textLabel?.text = "Select all"
cell.accessoryType = allSelected ? .checkmark : .none
} else {
let area = areas[indexPath.row]
cell.textLabel?.text = area.name
cell.accessoryType = area.isSelected ? .checkmark : .none
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == 0 {
// (de-)select all
let shouldSelect = !allSelected
for i in 0..<areas.count {
areas[i].isSelected = shouldSelect
}
} else {
areas[indexPath.row].isSelected.toggle()
}
tableView.reloadRows(at: tableView.indexPathsForVisibleRows ?? [], with: .automatic)
}
First you need to enable multiple selection for the table view
tableView.allowsMultipleSelection = true
tableView.allowsMultipleSelectionDuringEditing = true
Select all rows
for section in 0..<tableView.numberOfSections {
for row in 0..<tableView.numberOfRows(inSection: section) {
let indexPath = IndexPath(row: row, section: section)
tableView.selectRow(at: indexPath, animated: false, scrollPosition: .none)
}
}
To enable checkmark whenever a row is selected:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) {
let area = areas[indexPath.row]
area.isSelected = true
cell.accessoryType = .checkmark
}
}
Also remove checkmark when it is deselected:
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) {
let area = areas[indexPath.row]
area.isSelected = false
cell.accessoryType = .none
}
}
Please vote this answer if it helps. Thanks.
First change your Area to class so it will be reference type
class Area {
let name : String
var isSelected : Bool
init(name : String, isSelected : Bool = false) {
self.name = name
self.isSelected = isSelected
}
}
Now change your didselect logic
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let area = areas[indexPath.row]
area.isSelected.toggle()
if area.name == "Select all"{
areas = areas.map{$0.isSelected = true}
}
tableView.reloadRows(at: [indexPath], with: .none)
let selectedAreas = areas.filter{$0.isSelected}.map{$0.name}
print(selectedAreas)
}
In didSelectRow:
if indexPath.row == 0 { // the first item is the select all button
// find out which areas should be selected
let indicesThatShouldBeSelected = (1..<areas.count).filter { !areas[$0].isSelected }
// update model
indicesThatShouldBeSelected.forEach { areas[$0].isSelected = true }
// update view
tableView.reloadRows(at: indicesThatShouldBeSelected.map { IndexPath(section: 0, row: $0) }, with: .none)
}
You could also just do tableView.reloadData(), which reloads the whole table view instead of just the rows that needs reloading.
If the selectAll row is at index 0 check the row, then set all isSelected members to true and reload the entire table
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0 {
areas.indices.forEach{areas[$0].isSelected = true}
tableView.reloadData()
} else {
areas[indexPath.row].isSelected.toggle()
tableView.reloadRows(at: [indexPath], with: .none)
}
let selectedAreas = areas.filter{$0.isSelected}.map{$0.name}
print(selectedAreas)
}
And if you want to exclude the first item to be selected drop the first index
areas.indices.dropFirst().forEach{areas[$0].isSelected = true}
I'm having an issue where when I'm selecting the cell for e.g at index 3 , it selecting cells below also at random indexes. Check and Uncheck cell is working but for some reasons when selecting a cell it is selecting other cells as well. My array is returning 120 rows in total. I have selected multiple touch. Thank you for the help.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return arrayVerbCount.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = self.tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MesTalentsChoixCell
cell.verb!.text = arrayVerbCount[indexPath.row].verb
if cell.isSelected
{
cell.isSelected = false
if cell.accessoryType == UITableViewCellAccessoryType.none
{
cell.accessoryType = UITableViewCellAccessoryType.checkmark
}
else
{
cell.accessoryType = UITableViewCellAccessoryType.none
}
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
let cell = tableView.cellForRow(at: indexPath)
if cell!.isSelected
{
cell!.isSelected = false
if cell!.accessoryType == UITableViewCellAccessoryType.none
{
cell!.accessoryType = UITableViewCellAccessoryType.checkmark
}
else
{
cell!.accessoryType = UITableViewCellAccessoryType.none
}
}
}
My custom cell class:
class MesTalentsChoixCell: UITableViewCell {
#IBOutlet weak var verb: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
You should do like this way, this is very much easy solution if there is only one section.
Initialize selectedItems array like this,
var selectedItems: [Int] = []
Find UITableViewDataSource method below
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell") as! CustomCell
cell.tmpValue.text = data[indexPath.row]
if selectedItems.contains(indexPath.row) {
cell.accessoryType = .checkmark
} else {
cell.accessoryType = .none
}
return cell
}
Find UITableViewDelegate Method below.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if selectedItems.contains(indexPath.row) {
let index = selectedItems.index(of: indexPath.row)
selectedItems.remove(at: index!)
} else {
selectedItems.append(indexPath.row)
}
tableView.reloadRows(at: [indexPath], with: .none)
}
Code will be changed depending on your requirement and custom cell. Hope you can do it your way. Thank you.
UPDATE
You can even use Set also like this way,
var setSelectedItems: Set<Int> = []
UITableViewDataSource method,
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell") as! CustomCell
cell.tmpValue.text = data[indexPath.row]
if setSelectedItems.contains(indexPath.row) {
cell.accessoryType = .checkmark
} else {
cell.accessoryType = .none
}
return cell
}
UITableViewDelegate method,
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if setSelectedItems.contains(indexPath.row) {
setSelectedItems.remove(indexPath.row)
} else {
setSelectedItems.insert(indexPath.row)
}
tableView.reloadRows(at: [indexPath], with: .none)
}
Make bool array for stability while scrolling i.e.
var arrStatusBool = [Bool]()
Now set value at indexPath.row in didSelectRowAt
public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
if self.arrStatusBool[indexPath.row]
{
self.arrStatusBool[indexPath.row] = false
}
else
{
self.arrStatusBool[indexPath.row] = true
}
}
And also put this in cellForRowAt to avoid scrolling issue.
if self.arrStatusBool[indexPath.row]
{
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
else
{
tableView.cellForRow(at: indexPath)?.accessoryType = .none
}
hope this help!
For multiple selection you should track selected cells in a Dictionary for convenience faster access to selected and unselected indexPaths allowing you use multiple sections because the key value of our Dictionary is a string formed by (IndexPath.section)+(IndexPath.row) which is always unique combination
var selectedIndexPaths : [String:Bool] = [:]
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let currentIndexPathStr = "\(indexPath.section)\(indexPath.row)"
if(self.selectedIndexPaths[currentIndexPathStr] == nil || !self.selectedIndexPaths[currentIndexPathStr]!) {
self.selectedIndexPaths[currentIndexPathStr] = true
}else{
self.selectedIndexPaths[currentIndexPathStr] = false
}
self.tableView.reloadRows(at: [indexPath], with: .automatic)
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "npCell", for: indexPath) as! NewPlaylistTableViewCell
cell.mTitle.text = musics[indexPath.row]["title"] as! String?
cell.mArtist.text = musics[indexPath.row]["artist"] as! String?
cell.accessoryType = .checkmark
let currentIndexPathStr = "\(indexPath.section)\(indexPath.row)"
if(self.selectedIndexPaths[currentIndexPathStr] == nil || !self.selectedIndexPaths[currentIndexPathStr]!) {
cell.accessoryType = .none
}
return cell
}
Results
Just a minor change
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = self.tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MesTalentsChoixCell
cell.verb!.text = arrayVerbCount[indexPath.row].verb
if cell.isSelected
{
cell.accessoryType = UITableViewCellAccessoryType.checkmark
}
else
{
cell.accessoryType = UITableViewCellAccessoryType.none
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
let cell = tableView.cellForRow(at: indexPath)
//toggle the state
cell!.isSelected = !cell!.isSelected
if cell!.isSelected
{
cell!.accessoryType = UITableViewCellAccessoryType.checkmark
}
else
{
cell!.accessoryType = UITableViewCellAccessoryType.none
}
}
Note: you should also create method for common code :-)
I'm having trouble presenting the data. I have copied the code from https://stackoverflow.com/a/39307841/7118403 because i want to test his method on saving the checkmark. But unfortunately I can't present the data on tableView. When i try to print the "myItems" it shows [tableViewCheckmark.Item]. I can't seem to find the solution. PS. I'm a new to programming. Thank you in advance.
class Item {
let name : String
var selected = false
init(name: String) {
self.name = name
}
}
class TableViewController: UITableViewController {
#IBOutlet var uiTableView: UITableView!
var myItems = [Item]()
override func viewDidLoad() {
uiTableView.reloadData()
}
override func viewWillAppear(_ animated: Bool) {
let item = Item(name:"Foo")
myItems.append(item)
print(myItems)
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath)
let item = myItems[indexPath.row]
cell.textLabel!.text = item.name
cell.accessoryType = item.selected ? .checkmark : .none
cell.selectionStyle = .none
cell.tintColor = UIColor.green
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
saveDefaults()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return myItems.count
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let item = myItems[indexPath.row]
item.selected = true
tableView.reloadRows(at: [indexPath as IndexPath], with: .none)
}
func saveDefaults() {
let selectedCells = myItems.filter { $0.selected }.map { $0.name }
let defaults = UserDefaults.standard
defaults.set(selectedCells, forKey:"selectedCells")
}
func readDefaults()
{
let defaults = UserDefaults.standard
let selectedItems = defaults.stringArray(forKey: "selectedCells")!
for item in myItems {
item.selected = selectedItems.contains(item.name)
}
tableView.reloadData()
}
}
Signature of UITableViewDataSource methods is changed in Swift 3 also you are currently passing array count in numberOfSections(in:) remove it and add below methods.
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myItems.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath)
let item = myItems[indexPath.row]
cell.textLabel!.text = item.name
cell.accessoryType = item.selected ? .checkmark : .none
cell.selectionStyle = .none
cell.tintColor = UIColor.green
return cell
}
override func tableView(tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let item = myItems[indexPath.row]
item.selected = true
tableView.reloadRows(at: [indexPath], with: .none)
}