I have a tableview which uses two tableview row Actions one is delete and other is more.
When I tap on more button an alertcontroller is presented which has some actions.
I want that when morebutton is tapped the alertcontroller is presented but the rowActions remain there itself showing on which row the more button was pressed however it fades away as soon as I tap the more button.
Apple mail app and whatsapp do this successfully.
I am using xcode 9 and ios 11.1 in simulator.
I have used below code for implementing swipe to action functionality:
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let conversation = fetchedResultsController.object(at: indexPath)
let conversationId = Int(conversation.id)
let conversationType = Int(conversation.conversation_type_id)
let deleteTitle = getDeleteRowActionTitle(conversationId: conversationId, conversationType: conversationType)
let moreRowAction = UITableViewRowAction(style: UITableViewRowActionStyle.normal, title: "More", handler:{action, indexpath in
self.moreAction(conversation: conversation, conversationId:conversationId,conversationType:conversationType,indexPath:indexpath)
})
moreRowAction.backgroundColor = UIColor.green
let deleteRowAction = UITableViewRowAction(style: UITableViewRowActionStyle.destructive, title: deleteTitle, handler:{action, indexPath in
})
return [deleteRowAction, moreRowAction]
}
func moreAction(conversation:Nd_conversation,conversationId: Int,conversationType:Int,indexPath:IndexPath){
let muteTitle = notify ? "Mute" : "Unmute"
let moreActionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
let action1 = UIAlertAction(title: muteTitle, style: .default, handler: {(action) -> Void in
})
moreActionSheet.addAction(action1)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: {(action) -> Void in })
moreActionSheet.addAction(cancelAction)
self.present(moreActionSheet, animated: true, completion: nil)
}
This is working in ios 10.3 but not in ios 11.
Related
I'm implementing leading/trailing swipe actions in my app.
The leading swipe action is to join/leave an event in the table. The trailing swipe action is to delete an event. Both of these swipe actions should be conditional, based primarily on if the user is logged in or not.
If the user swipes left or right, and the user is not logged in, I want to display an alert ("Login required...").
If the user is logged in, the leading action will conditionally be titled "Leave" or "Join" depending on if the user has already joined the event or not. The trailing "Delete" action will be created only if the user is the also the creator of the event.
When I test the app and the user is logged in, everything works perfectly. (That was working before I decided to add the conditional element.)
When I test the app, and the user is not logged in, the leading swipe works perfectly: I swipe left (in my case), the alert pops up. No swipe action appears in the TableViewCell.
The trailing swipe also shows the alert and reacts correctly, but for some reason it's also showing a "Delete" action, even though my code uses the title "Blah". After dismissing the alert, the red "Delete" action is still visible and clickable.
I've also completely removed the "trailingSwipe..." method but the "Delete" action still appears, so I need to figure out where the default is so I can turn it off and/or override it.
How do I prevent the default Delete action from appearing and display my action instead?
Here's my code for the leading swipe:
override func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
if currentUserID == nil {
showLoginRequiredMessage()
return nil
} else {
var userName = people.randomElement() // for testing
if event.eventMembers.contains(userName) {
let index = event.eventMembers.firstIndex(of: userName)!
let leaveAction = UIContextualAction(style: .normal, title: "Leave") { (action, view, nil) in
event.eventMembers.remove(at: index)
tableView.setEditing(false, animated: true)
tableView.reloadRows(at: [indexPath], with: .automatic)
self.saveEvents()
}
leaveAction.backgroundColor = .red
return UISwipeActionsConfiguration(actions: [leaveAction])
} else {
let joinAction = UIContextualAction(style: .normal, title: "Join") { (action, view, nil) in
event.eventMembers.append(userName)
tableView.setEditing(false, animated: true)
tableView.reloadRows(at: [indexPath], with: .automatic)
self.saveEvents()
}
joinAction.backgroundColor = .green
return UISwipeActionsConfiguration(actions: [joinAction])
}
}
}
Here's my code for the trailing swipe:
override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
if currentUserID == nil {
showLoginRequiredMessage()
return nil
} else {
let trailingAction = UIContextualAction(style: .destructive, title: "Blah") { (action, view, nil) in
tableView.setEditing(false, animated: true)
print ("Delete this event")
}
trailingAction.backgroundColor = .red
return UISwipeActionsConfiguration(actions: [trailingAction])
}
}
And here's the code for the alert:
private func showLoginRequiredMessage() {
let ac = UIAlertController(title: "Login Required", message: "To modify an event, you must first login", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "Sign In", style: .default, handler: {(action) in
if let authenticationController = self.storyboard?.instantiateViewController(withIdentifier: "authenticationScreen") {
self.present(UINavigationController(rootViewController: authenticationController), animated: true)
}
}))
ac.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
present(ac, animated: true)
}
I have solved your issue. I hope that will work for you.
In trailingSwipeActions method change action style to normal, you will get "Blah" title.
Remove return nil from your if statement.
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
if currentUserID == nil {
self.showLoginRequiredMessage()
}
let trailingAction = UIContextualAction(style: .normal, title: "Blah") { (action, view, boolval) in
print ("Custom action event")
tableView.setEditing(false, animated: true)
}
trailingAction.backgroundColor = .gray
return UISwipeActionsConfiguration(actions: [trailingAction])
}
And, add .setEditing(false, animated: true) in below method
private func showLoginRequiredMessage() {
let ac = UIAlertController(title: "Login Required", message: "To modify an event, you must first login", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "Sign In", style: .default, handler: {(action) in
self.myTableView.setEditing(false, animated: true)
if let authenticationController = self.storyboard?.instantiateViewController(withIdentifier: "authenticationScreen") {
self.present(UINavigationController(rootViewController: authenticationController), animated: true)
}
}))
ac.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: {(action) in
self.myTableView.setEditing(false, animated: true)
}))
present(ac, animated: true)
}
Based on ChillY's answer to this question (Why is the leading swipe action also duplicated as a trailing action?), I realized the problem was that I was returning nil instead of UISwipeActionsConfiguration(actions: []).
Now I just have to figure out why the swipes are not disappearing after the action has been executed. Any ideas?
I have a uiTableView with 3 cells that have a uiContextualAction implemented through the trailingSwipeActionsConfigurationForRowAt delegate method.
On tap of the uiContextualAction I display an actionSheet with two actions - delete and dismiss.
When the actionSheet is displayed without having pressed any action, the cell's content for all 3 cells, specifically a uiImageView suddenly disappears.
Is there something inherent to uiTableViews causing this? I placed breakpoints throughout the aforementioned flow but to no avail on how to remedy this. Any thoughts would be appreciated.
BEFORE presented actionSheet - ImageView (red background w/ blue gradient image) of UITableViewCell
AFTER on presented actionSheet - ImageView (red background w/o blue gradient image)
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let delete = UIContextualAction(style: .normal, title: "") { (action, view, completion) in
self.onDeleteCell(indexPath)
completion(true)
}
delete.backgroundColor = UIColor.red
delete.image = #imageLiteral(resourceName: "x_circle")
let config = UISwipeActionsConfiguration(actions: [delete])
config.performsFirstActionWithFullSwipe = false
return config
}
func onDelete(_ indexPath: IndexPath) {
AlertController.showActionSheet(self, title: nil, message: nil, actionOneTitle: "Delete", actionOneStyle: .destructive, actionTwoTitle: "Dismiss", actionTwoStyle: .cancel) { (_) in
self.updateCells(indexPath)
}
}
//From custom AlertController class
static func showActionSheet(_ inViewController: UIViewController, title: String?, message: String?, actionOneTitle: String, actionOneStyle: UIAlertAction.Style, actionTwoTitle: String, actionTwoStyle: UIAlertAction.Style, actionOneHandler: #escaping ((UIAlertAction) -> Void)) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .actionSheet)
let actionOne = UIAlertAction(title: actionOneTitle, style: actionOneStyle, handler: actionOneHandler)
alert.addAction(actionOne)
let actionTwo = UIAlertAction(title: actionTwoTitle, style: actionTwoStyle, handler: nil)
alert.addAction(actionTwo)
inViewController.present(alert, animated: true, completion: nil)
}
Still unsure what the issue is/was...but I replaced the vector image as png and it appears to render and not suddenly vanish anymore..
Not a definitive solution, but it for now happens to work for me.
I have found similar questions. None of which solve the same problem I am having.
This one here: Table view cell background goes white when deleting a cell - iOS
is in objective c. I need a swift answer.
I found this Change default background color while deleting a row from tableView
Answer in swift however when I add this to my code it still does not work.
Here is the code I am using to delete the cell.
override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let delete = UITableViewRowAction(style: .destructive, title: "delete") { (action, indexPath) in
let alertController = UIAlertController(title: "Warning", message: "Are you sure you want to delete this?", preferredStyle: .alert)
let deleteAction = UIAlertAction(title: "Delete", style: .destructive, handler: { (action) in
self.tableView.deleteRows(at: [indexPath], with: .fade)
})
alertController.addAction(deleteAction)
let cancelAction = UIAlertAction(title: "Cancel", style: .default, handler: nil)
alertController.addAction(cancelAction)
self.present(alertController, animated: true, completion: nil)
}
return [delete]
}
I need to maintain the color of the cell as the delete option comes from swiping.
Thanks!
Reload the table after deleting cell and also remove cell data from the array as well or use this line in view did load
tableView.tableFooterView = UIView(frame: .zero)
this will remove the empty cell form table
Well i know these types of questions are answered by SO before, but mine is little different so please read it.
I am using a button inside tableview cell. On click of button i am showing an AlertViewController with list of actions. On selecting action my button text and my custom model class propery is changed.
Button text is changing on button click. But my problem is cell not storing button state. If i change button of 1st cell and then click on second cell button all other buttons back to its default text.
please see this video
Here is my code
setting cell data
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("dbColumns", forIndexPath: indexPath) as! CustomColumnTableViewCell
let column = columns[indexPath.row]
cell.dbColumnName.text = column.name
cell.dbColumnOrder.titleLabel?.text = column.order
cell.dbColumnOrder.tag = indexPath.row
print(columns)
cell.dbColumnOrder.addTarget(self, action: #selector(ViewController.showAlert(_:)), forControlEvents: UIControlEvents.TouchUpInside)
return cell
}
Action on button click
//MARK:Show Alert
func showAlert(sender:UIButton){
let alert = UIAlertController(title: "Column Order", message: "Please select column order", preferredStyle: .ActionSheet)
let index = sender.tag
let indexPath = NSIndexPath(forRow: index, inSection: 0)
alert.addAction(UIAlertAction(title: "None", style: .Default, handler: { (action) in
//execute some code when this option is selected
self.columns[index].order = "None"
self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .None)
}))
alert.addAction(UIAlertAction(title: "Assending", style: .Default, handler: { (action) in
//execute some code when this option is selected
self.columns[index].order = "Assending"
self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .None)
}))
alert.addAction(UIAlertAction(title: "Desending", style: .Default, handler: { (action) in
//execute some code when this option is selected
self.columns[index].order = "Desending"
self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .None)
}))
self.presentViewController(alert, animated: true, completion: nil)
}
Please hemp me.
In cellForRowAtIndexPath method Set button text like this way
First remove this
cell.dbColumnOrder.titleLabel?.text = column.order
Replace this
cell.dbColumnOrder.setTitle("\(column.order)", for: .normal)
And one more thing you need to increase cell.dbColumnOrder width.
Hope it works
Alright, I am testing around a bit with core data, something I recently have started to discover, basically, what i have so far, is a single view app, that has a data source, and i can press a button and it brings up and alert, which from there i can add names to the list, and delete names from the list, i can close my app and still maintain my data. here is the issue/question, i am trying to do an update, so i can edit names in the list, i have a uibutton set up on my prototype cell, and i have it linked to my viewController, and have a function set inside the IBAction for the button. however, the button does not appear in my sim at run time.
here i have some code.
this is code for the edit button, and its function:
#IBAction func editButton(sender: AnyObject) {
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// 2
let alert = UIAlertController(title: "Update",
message: "Please enter the new name.",
preferredStyle: .Alert)
// 3
let updateAction = UIAlertAction(title: "Save",
style: .Default){(_) in
let nameTextField = alert.textFields![0]
self.updateName(indexPath.row, newName: nameTextField.text!)
self.tableView.reloadData()
}
// 4
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
alert.addTextFieldWithConfigurationHandler(nil)
alert.addAction(updateAction)
alert.addAction(cancelAction)
// 5
self.presentViewController(alert, animated: true, completion: nil)
}
here is my cellForRowAtIndexPath func
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell")!
let people = peoples[indexPath.row]
cell.textLabel!.text = people.name
return cell
}
here is an image of my storyboard
Storyboard
if you need further information or code, please let me know and i will provide it.