I am preparing a table in which when I swipe the cell I need to get two rounded buttons. Each button should have one image and and a label.
override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
var hello = UITableViewRowAction(style: .Default, title: "Image") { (action, indexPath) in
// do some action
if let buttonImage = UIImage(named: "Image") {
// self.bgColor = UIColor.imageWithBackgroundColor(image: buttonImage, bgColor: UIColor.blueColor())
}
return editButtonItem()
}
First of all, there are some problems with your code :
You return the result of editButtonItem() method, which basically discards your hello action. I'm gonna assume from the name of it, that this method returned a single action, and not two as you wanted.
In your action handler, you tried to set the background on self. Blocks capture variables from their parent scope, so self in this block didn't relate to hello action, but rather to the class in which your editActionsForRowAtIndexPath method was implemented.
How to achieve what you need (two buttons with title and image) :
override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
var firstAction = UITableViewRowAction(style: .Default, title: "First") { (action, indexPath) in
// action handler code here
// this code will be run only and if the user presses the button
// The input parameters to this are the action itself, and indexPath so that you know in which row the action was clicked
}
var secondAction = UITableViewRowAction(style: .Default, title: "Second") { (action, indexPath) in
// action handler code here
}
firstAction.backgroundColor = UIColor(patternImage: UIImage(named: "firstImageName")!)
secondAction.backgroundColor = UIColor(patternImage: UIImage(named:"secondImageName")!)
return [firstAction, secondAction]
}
We create two separate actions, assign their background colors to use pattern images and return an array containing both our actions. This is the most you can do to alter the appearance of UITableViewRowAction - we can see from the docs, that this class doesn't inherit from UIView.
If you wanted to customize the appearance more, you should look for an external library or implement your own solution from the scratch.
Related
I have an app with multiple view controllers with a tableview in each of them. Each view controller's table have their own specific purpose, but I use the same swipe actions in each table. So far I have just been copying and pasting the same code for trailingSwipeActionsConfigurationForRowAt and leadingSwipeActionsConfigurationForRowAt in each table. This feels wrong and I know there should be a way where I can write the code once and use it throughout the app but I am not sure how to do this.
I have tried to extensions of UITableView but can not seem to use the trailingSwipeActionsConfigurationForRowAt or leadingSwipeActionsConfigurationForRowAt functions in the extension file. What am I missing?
Here's the code for trailingSwipeActionsConfigurationForRowAt which is just swipe to delete:
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let action = UIContextualAction(style: .destructive, title: "") { (action, view, completionHandler) in
if let item = self.dataSource.itemIdentifier(for: indexPath) {
CoreDataManager.sharedManager.deleteItem(item)
}
completionHandler(true)
}
action.image = UIImage(named: "deleteSymbol")
let configuration = UISwipeActionsConfiguration(actions: [action])
return configuration
}
you declare below function as global function for the project and access any where you want
You can modify function by adding parameter which you want to use when button clicked. just simply add parameter in function and pass data when you call
func getSwipeAction(indexpath : IndexPath)-> UISwipeActionsConfiguration{
let action = UIContextualAction(style: .destructive, title: "") { (action,
view, completionHandler) in
completionHandler(true)
}
action.image = UIImage(named: "deleteSymbol")
let configuration = UISwipeActionsConfiguration(actions: [action])
return configuration
}
You can add these inner code in UITableView extension function and try to use it like that. You have to implement trailingSwipeActionsConfigurationForRowAt or leadingSwipeActionsConfigurationForRowAt in each of your view controllers.
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
return self.YourFunctionNameInExtension()
}
You can define a protocol like BaseTableViewProtocol and in this protocol's extension you can write your code. So when you extend your tableView class from this protocol you can use the function. For example,
protocol BaseTableViewProtocol { }
extension BaseTableViewProtocol {
func trailingSwipeActionsConfigurationForRowAt() {
//Something goes here
}
func leadingSwipeActionsConfigurationForRowAt() {
//Something goes here
}
}
In the editing mode of UITableView, I need three things, the first two are easy to get using UITableView delegate methods:
Delete (- in red) button on the left of the row,
Reorder (three bars) row button on the right of the row,
A custom defined action (with title & background color) appearing on the left side of reorder (three bars) button.
How is it possible to get these three actions together?
Hi yes it is possible to make or add your own custom action by implementing the tableView delegate
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let archiveAction:UITableViewRowAction = UITableViewRowAction(style: .default, title: " ") { (rowAct, index) in
}
let deleteAction:UITableViewRowAction = UITableViewRowAction(style: .default, title: " ") { (rowAct, index) in
}
let archiveImg = UIImageView(image: UIImage(named: "archive_btn"))
archiveImg.contentMode = .scaleAspectFit
archiveAction.backgroundColor = UIColor(patternImage:archiveImg.image!)
let deleteImg = UIImageView(image: UIImage(named: "delete_btn"))
deleteImg.contentMode = .scaleAspectFit
deleteAction.backgroundColor = UIColor(patternImage:deleteImg.image!)
return [deleteAction,archiveAction]
}
I'm using SwipeCellKit for my TO DO List app. When the user swipes left it deletes the item, but when the user swipes right I want him to be able to set a reminder on this item, so I've created an actionset a reminder
this action should perform a segue which brings the user to a custom popup with a date picker in it. The problem is that when I click on the button to set a reminder the simulator quits with an uncaught exception. I've already tried to perform deletion from this button it works perfectly, I've also tried to perform another segue to another view controller from this button the simulator quits. Could someone tell me what I'm doing wrong here? Here's my code:
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> [SwipeAction]? { if orientation == .left {
guard isSwipeRightEnabled else { return nil }
let setReminder = SwipeAction(style: .default, title: "Set a reminder") { action, indexPath in
self.updateModelByAddingAReminder(at: indexPath)
}
setReminder.image = UIImage(named: "reminder-icon")
return[setReminder]
}else{
let deleteAction = SwipeAction(style: .destructive, title: "Delete") { action, indexPath in
self.updateModel(at: indexPath)
}
// customize the action appearance
deleteAction.image = UIImage(named: "delete-icon")
// return [setReminder, deleteAction]
return [deleteAction]
}
Ok, I found problem in your options for cell.
From doc
The built-in .destructive, and .destructiveAfterFill expansion styles are configured to automatically perform row deletion when the action handler is invoked (automatic fulfillment).
And you need use destructive style for cell in editActionsForRowAt. Or use another options, for example
func tableView(_ tableView: UITableView, editActionsOptionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> SwipeTableOptions {
var options = SwipeTableOptions()
options.transitionStyle = .border
if orientation == .left{
//or none
options.expansionStyle = .selection
}else{
options.expansionStyle = .destructive
}
return options
}
Hope it's help.
I have a UITableView which in every call has two action.
When I tap on one of them their action not being called and just these action button disappears and cell comes back to its normal place.
their action just being called when I tap and hold for a long time!
how can I fix that?
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let cancel = UITableViewRowAction(style: .destructive, title: "cacel") { action, index in
print("c tapped")
}
let paymentType = UITableViewRowAction(style: .destructive, title: "patmentType") { action, index in
print("p tapped")
}
return [paymentType,cancel]
}
tableView deleagte is set.
I tried code below still bot working :
self.tableView.setEditing(false, animated: true)
and
tableView.isEditing = false
not working yet.
any help please
I'm a beginner of Swift, and I searched a lot of stuffs, but couldn't figure out and decided to post my first question ever here.
I have a table view to show tweets by using twitter fabric and I use UITableViewRowAction to present two options to users when a swipe is done on a row, "funnelOne" and "funnelTwo", to categorize their tweets by adding tags to each tweet.
In the view controller, I add two functions to make an alert and get a value of 'funnelTag' to store it to my core data.
However, I am not sure if I can correctly store the number to the core data because somehow different cell would be deleted if I push one of swipeable buttons. I know I can write a code within 'func tableView' to delete the row, but how I can get access from out of 'func tableView' to delete the row successfully??
If it can be resolved, I should be able to successfully store the value to my core data.
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]? {
let cell = super.tableView(tableView, cellForRowAtIndexPath: indexPath) as? CustomTableViewCell
let funnelOne = UITableViewRowAction(style: .Default, title: "funnel") {
(action, indexPath) -> Void in
funnelTag = 1 // funnelTag is Int I want to store in my Core Data
cell!.tag = funnelTag
// self.tweets.removeAtIndex(indexPath.row) - I know this is working
tableView.setEditing(false, animated: true)
}
let funnelTwo = UITableViewRowAction(style: .Default, title: "funnel") {
(action, indexPath) -> Void in
funnelTag = 2
cell!.tag = funnelTag
tableView.setEditing(false, animated: true)
// self.tweets.removeAtIndex(indexPath.row)
}
These are two functions I add. if I implement these functions, top row would be deleted even though I want to delete other row... the first function, funnelTweet() is properly working, but the second function does not seem to work correctly..
func funnelTweet(cell: CustomTableViewCell){
let index: Int = cell.tag
if SettingStore.sharedInstance.isNoAlert(){
self.submitFunnel(index, cell: cell)
} else {
self.alert = UIAlertController(title: NSLocalizedString("stock_confirm_funnel", comment: ""), message: nil, preferredStyle: .Alert)
self.alert!.addAction(UIAlertAction(title: NSLocalizedString("common_ok", comment: ""), style: .Destructive) { action in
self.submitFunnel(index, cell: cell)
})
self.alert!.addAction(UIAlertAction(title: NSLocalizedString("common_cancel", comment: ""), style: .Cancel) { action in
cell.moveToLeft()
})
self.presentViewController(self.alert!, animated: true, completion: nil)
}
}
func submitFunnel(index: Int, cell: CustomTableViewCell){
var tweet = self.tweets[index]
// store to local storage
TagStore.sharedInstance.saveData(tweet.createdAt, funnelTag: funnelTag, id: tweet.tweetID)
self.tweets.removeAtIndex(index)
self.tableView!.reloadData()
}
Thank you for your help!
In the Second function you have not initialized the index before using it.
func submitFunnel(index: Int, cell: CustomTableViewCell){
// Initialize index here before using it in the next statement.. that is give it a value, otherwise it will return nil
var tweet = self.tweets[index]
// store to local storage
TagStore.sharedInstance.saveData(tweet.createdAt, funnelTag: funnelTag, id: tweet.tweetID)
self.tweets.removeAtIndex(index)
self.tableView!.reloadData()
}