-2

Evening ladies and gentleman, I am currently getting used to Swift and wanted to start with a little todo app. So far I can add an item and safe it persistently in a context. When an item has been added, it will be shown in a tableview. Now, I want to use a check swipe to strikethrough items, which have been added and safe this information in my context. Deleting using a swipe works perfectly fine.

Has anybody an idea how realize this? I tried to solve it by myself, but couldnt get it done. A similar question has been asked here before, but didnt get a proper answer: Add strikethrough to tableview row with a swipe

func checkAccessoryType(cell: UITableViewCell, isCompleted: Bool) {
    if isCompleted {
        cell.accessoryType = .checkmark

    } else {
        cell.accessoryType = .none
    }
}

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let todo = CoreDataManager.shared.getTodoItem(index: indexPath.row)
    todo.completed = !todo.completed
    CoreDataManager.shared.safeContext()

    if let cell = tableView.cellForRow(at: indexPath){
        checkAccessoryType(cell: cell, isCompleted: todo.completed)
    }
}

2 Answers2

1

Assuming you are trying to strikethrough the title of your task -- which should be defined as a label -- here is the approach to take:

1- Make sure your label is set to attributed text rather than plain. To do that, go to Main.storyboard, select your label, and inside the attribute inspector, set text to Attributed.

2- Inside your completion block (that is the completion block executed after a swipe) add the following code:

(SWIFT 5)

let attributeString: NSMutableAttributedString =  NSMutableAttributedString(string: taskLabel.text)
attributeString.addAttribute(.strikethroughStyle, value: 1, range: NSRange(location: 0, length: taskLabel.text.count))
taskLabel.attributedText = attributeString

Just a little advice: it's always helpful if you add some code when you ask a question. Let me know if anything doesn't make sense.

rs7
  • 1,423
  • 1
  • 5
  • 15
  • Hey, I added my code lines for the swipe to my question. Ive done the first step of your suggested solution, but Im not sure what do you mean with the completion block? – Jakob Wiemer May 22 '19 at 01:11
  • Hey, completion block is the block of code that gets executed after your cell is swiped. So basically, add the code after the 'in' keyword where I added the print statement: `let action = UIContextualAction(style: .normal, title: "Check") { (action, view, completion) in print("This is the completion block") }` – rs7 May 23 '19 at 04:28
  • Hey, thanks a lot for your answer. I set the label identifier to taskLabel in the MainStoryboard. But when i paste your code, xCode throws an error that says: Use of unresolved identifier 'taskLabel'. Has it anything to do with that the string, which is shown by the label, is generated by using core data? – Jakob Wiemer May 27 '19 at 04:47
  • Hey, not a problem. Did you create an IBOutlet inside the ViewController? – rs7 May 28 '19 at 04:31
  • I think so. I connected the table view with the view controller with an outlet: @IBOutlet var todoTableView: UITableView! – Jakob Wiemer May 29 '19 at 07:08
  • Okay. Are you using a custom tableviewcell? If yes, did you create a file for it and created and connected all the IBOutlets properly? You also need to make sure to register your cell using a reuse identifier. If what I'm talking about seems foreign to you, just post your code and I'll try to guide you. – rs7 May 29 '19 at 22:44
  • The cell has the identifier 'cell', I set this the inspector under the option 'Identifier'. My cell style is set to 'basic'. I changed my mind a little bit. I added a feature to check the todo in the tableview by using the accessory 'Checkmark'. Instead of the swipe, I want to strikethrough the cell when the todo is checked. You can find the code above :) – Jakob Wiemer May 30 '19 at 03:09
  • In your cellForRowAt method, make sure you dequeue the cell properly: `let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)`. Also, if it's a basic cell, the way to access the label is as follows: `cell.textLabel!.text = "Hello"`. Basic cells have a set format. FYI, you don't need to subclass basic cells. – rs7 May 30 '19 at 05:31
0

Looking at the link that you provided, you need swipe action on your UITableViewCell.

Try looking into:

  • leadingSwipeActionsConfigurationForRowAt
  • trailingSwipeActionsConfigurationForRowAt

You need this action to perform the strikethrough label or delete:

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])

 }

 func tableView(_ tableView: UITableView,
                trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
 {
     let modifyAction = UIContextualAction(style: .normal, title:  "Update", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
         print("Update action ...")
         success(true)
     })
     modifyAction.image = UIImage(named: "hammer")
     modifyAction.backgroundColor = .blue

     return UISwipeActionsConfiguration(actions: [modifyAction])
 }

Left Swipe

Right Swipe

Source: https://developerslogblog.wordpress.com/2017/06/28/ios-11-swipe-leftright-in-uitableviewcell/

Kelvin Tan
  • 157
  • 1
  • 13
  • The app unfortunately crashes when I perform the delete swipe using your provided code. I am using core data to generate, save and load my todos in the table view. Has it something to do with that maybe? – Jakob Wiemer May 30 '19 at 10:56