How to change editing style for specific cell in tableview - swift

I have a tableview where the editingstyle is .delete for all the cells. But I want to have some specific cells that doesnt have editingstyle (so that you can't swipe them, .none). Anyone have any suggestions for how to implement this?
I tried to write something like UITableViewCell.EditingStyle.none for that specific row but that didnt work.
Thanks in advance, Pontus

Consider the following example:
class ViewController: UITableViewController {
private let arr = (1...10).map { "Item \($0)" }
override func viewDidLoad() {
super.viewDidLoad()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arr.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
cell?.textLabel?.text = arr[indexPath.row]
return cell ?? UITableViewCell()
}
override func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
if indexPath.row == 2 {//<- Your condition
return .none
} else {
return .delete
}
}
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
}
So the key is to use editingStyleForRowAt in order to change the style for a specific cell (or even multiple cells) (see the documentation for further reference: https://developer.apple.com/documentation/uikit/uitableviewdelegate/1614869-tableview).

Related

TableView action per item

I have a tableView like this:
class ViewController: UIViewController {
#IBOutlet var tableView: UITableView!
let names = ["TEXT1", "TEXT2", "TEXT3"]
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view.
tableView.delegate = self
tableView.dataSource = self
}
}
extension ViewControllerMeer: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let name = names[indexPath.row]
print("You clicked on \(name)")
}
}
extension ViewControllerMeer: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return names.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = names[indexPath.row]
let n = names[indexPath.item]
switch n {
case "TEXT1":
print("s1")
case "TEXT2":
print("s2")
case "TEXT3":
print("s3")
default:
break
}
return cell
}
}
It reads the items from the 'let names', So far so good :) I now want to add some actions because now every item will print 'You tapped me'. I figured something out like
override func tableView(_ tableView: UITableView,
didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if indexPath.row == 0 {
print("cell1")
} else if indexPath.row == 1 {
print("cell2")
} else if indexPath.row == 2 {
print("cell3")
}
}
The only problem is that it generates an error 'Method does not override any method from its superclass'. So I guess this won't work. What would be a good method to do it?
remove the override in front of func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
And you can either to a big if statement or switch statement to do something with the names or you can do something like:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let name = names[indexPath.row]
print("You clicked on \(name)")
switch indexPath.row {
case 0:
//do something
self.shareApp()
case 1:
//do something else
self.writeReview()
default:
break
}
}
I just copied your codes to show you basically if you really want to override tableview functions
class ViewController: UITableViewController {
#IBOutlet var tableView: UITableView!
let names = ["TEXT1", "TEXT2", "TEXT3"]
override func viewDidLoad() {
super.viewDidLoad()
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("You tapped me!")
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return names.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = names[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let name = names[indexPath.row]
print("You clicked on \(name)")
}
}

Weird display behaviour when selecting tableview row

I have this table view, that populates through Core Data. Everything looks fine, even when scrolling, until I press and hold any row - then that row distorts like in the second image below.
(source: staticflickr.com)
(source: staticflickr.com)
Here's the code to display the tableview
override func viewDidLoad() {
super.viewDidLoad()
animateBackground(colors)
tableView.delegate = self
tableView.dataSource = self
tableView.fetchData(fetchedResultsController as! NSFetchedResultsController<NSFetchRequestResult>)
self.tableView.tableFooterView = UIView(frame: .zero)
}
func numberOfSections(in tableView: UITableView) -> Int {
guard fetchedResultsController.sections?.count != nil else { return 0 }
return fetchedResultsController.sections!.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard fetchedResultsController.sections != nil else { return 0 }
let data = fetchedResultsController.sections![section]
return data.numberOfObjects
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SkillCell", for: indexPath) as! SkillCell
configureCell(cell: cell, indexPath: indexPath as NSIndexPath)
return cell
}
func configureCell(cell: SkillCell, indexPath: NSIndexPath) {
let skill = fetchedResultsController.object(at: indexPath as IndexPath)
cell.skill = skill
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { }
}
From the code above, everything looks normal, yet this distortion occurs. Please help me to see why and how to stop it happening.
As the comment suggests, it's just a visual effect called selectionStyle of your UITableViewCell. Inside your cellForRowAt indexPath method, you can disable it like:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "myCell") as! MyCell
cell.selectionStyle = .none // this removes the effect.
return cell
}
yes you should set tableView selection style to none.
1.Select the tableview in storyboard in the right panel set selection style to none.
or
2.in your tableview cellforrow method set
tableView.selectionstyle = none

How to maintain highlighted multiple UITableView rows after reloading UITableView?

I have a UITableView.
I can select multiple cells make them highlighted.
But, whenever I reload App, the selected and highlighted state disappears.
I think I need to put some codes in 'viewDidAppear' and 'didSelectRowAt'. But I don't have any idea of specific codes.
What do I have to put in this syntax?
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
tableView.reloadData()
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
}
I recommend u add to dataSource item field selected, and in method cellForRowAtindexPath configure by your dataSource items.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cellClass = (self.cellClass(for: indexPath) ?? self.cellClasses.first) else { return UITableViewCell() }
let cell = tableView.dequeueReusableCell(withIdentifier: cellClass.identifier, for: indexPath)
if let configurable = cell as? ConfigurableComponent, let object = self.object(at: indexPath) {
let item = self.dataSource[indexPath.row]
configurable.selected = item.selected
}
return cell
}
When call didSelectRowAt, just take item and change selected field, sample:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let item = self.dataSource[indexPath.row]
item.selected = !item.selected
tableView.reloadData()
}

How do I move custom cells to left in editing mode in UITableView

I have custom cells of UITableView which consist of UIImage and textLabel. When I select the editing mod, the textLabel shows the following image;
I want to move it to left. I tried all of things to do but it didn't work.
Please let me know.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return allRows.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "editCell", for: indexPath) as! CustomTableView
cell.textLabel?.text = self.allRows[indexPath.row].bname
cell.textLabel?.textAlignment = .left
let image:UIImage = UIImage(named: "group")!
cell.imageView!.image = image
return cell
}
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle{
return .delete
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath){
if editingStyle == .delete{
self.allRows.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath as IndexPath], with: .fade)
}
}
#objc func leftEditButtonPressed(_ sender: UIButton) {
self.tableView!.isEditing = true
self.tableView?.setEditing(true, animated: true)
}
look at this, I hope it helps you:
swipe left/right in tableViewCell
func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let closeAction = UIContextualAction(style: .normal, title: "Close", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
print("OK, marked as Closed")
success(true)
})
closeAction.image = UIImage(named: "tick")
closeAction.backgroundColor = .purple
return UISwipeActionsConfiguration(actions: [closeAction])
}
Try using the following code:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.dataArr.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80.0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "TestTableCell") as? TestTableCell else {
return UITableViewCell()
}
cell.customImageView.image = #imageLiteral(resourceName: "ic_audio")
cell.customTitleLabel.text = self.dataArr[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
return UITableViewCellEditingStyle.delete
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
print("delete at \(indexPath.row)")
}
}
Here is the output for this code:
Note: You can change the editing action in editingStyleForRowAt method and for performing the action you need to write the logic in commit editingStyle method.
Hope this help you!
I suggest you to create new label in that UITableViewCell and connect that label to custom UITableViewCell class ! then you are free to do anything !
Swift 4 :
Create a new class which is subclass of UITableViewCell !
In your storyboard in right menu which called Utilities in toolbar of Utilities go to the Identity inspector defince your cell class to your new UITableViewCell class
Drag and drop UILabel from Object library into your cell
now using drag and drop connect that label to your UITableViewCell class then create an Outlet
Perfect !
now use myLabel instead of textLabel ;)
dont forget to cast your cell as! YourCustomCellClass
Good Luck ;)

How to edit row of cell?

I can not turn on editing mode in the first row of the cell. I tried this code but it didn't help.
public func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
if indexPath.row == 1{
return true
}
return false
}
Can someone help me?
Firstly, make sure your have added UITableViewDataSource protocol. Secondly, you may also need the following implementations.
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let myAction = UITableViewRowAction(style: .normal, title: "MY_ACTION") { (action, indexPath) in
print("I'm here")
}
return [myAction]
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
}
If you want to edit first row then replace
if indexPath.row == 1
with
if indexPath.row == 0
Because indexPath.row starts from 0 not from 1.
Hope that will help.
EDIT:
Since you didn't show your complete code I am adding example code here.
check below code:
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tbl: UITableView!
let arr = ["1", "2", "3"]
override func viewDidLoad() {
super.viewDidLoad()
tbl.dataSource = self
tbl.delegate = self
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tbl.dequeueReusableCell(withIdentifier: "cell")!
cell.textLabel?.text = self.arr[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arr.count
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
//set 0 for first cell
if indexPath.row == 0 {
return true
}
return false
}
//Need this method for delete cell
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCellEditingStyle.delete {
tbl.reloadData()
}
}
}