Hey @dagna, I don’t believe it’s in the plans at the moment, but I’ll definitely mention to the team that there’s interest!
There’s a few things which have changed since this was written beyond the introduction of Swift as well - UITableViewRowAction should help a ton if you’re just looking to add reasonably simple swipe-under buttons.
The main reason would be wanting to use something more customizable than UITableViewRowAction allows for.
As of right now, you can change the background color and the title of a row action, and add a background effect, but that’s about it. No images, no font changes, no ability to do what the mail app does and allow swiping all the way off to one side to delete/archive.
There are certainly existing libraries which help with those things, but this tutorial is about making it work if you want to do it yourself. Hope that helps!
Unfortunately I haven’t had too much of a chance to look at how the cell hierarchy in iOS 9 has changed, but I would advise using the view debugger in Xcode to take a look at what the various Views within the cell are nowadays.
The biggest thing is making sure that you’re adding the content you want to be under your main cell to the cell’s contentView, since otherwise it won’t actually be visible to the user.
In theory you should be able to flip what’s assigned to the left constraint and right constraint and have it work relatively well - you may have to do some flipping of what’s positive vs. negative in the gesture recognizer handler in order for the math to work correctly, but the general theory should be the same.
I will note that this tutorial hasn’t been updated in a couple years though, so I have no idea how well it runs on iOS 10.
@designatednerd, thanks for the great tutorial.
I used it as a bases for three action buttons inside a table view cell in swift 3 and with some minor changes regarding the “point of no return” calculation.
As far as iOS 10 compatibility goes, you did an awesome job. Works perfectly on my end.
Thanks for the tutorial, I am using the same system too. The difference for me is that I don’t have buttons, I have actions that occur based on how far you pull. Here is my challenge though. My table view has complex data, different sections have different data and therefore different actions. Implementing which actions should show and what should the actions do doesn’t really have any place in the code. Looking at it logically though, UITableViewDataSource and UITableViewDelegate are the ones that should be called to implement this behaviour.
When a user starts swiping, the cell should call UITableViewDataSource with something like actionForSwipe(swipe: Swipe) -> Action, where the action struct has the title, colour and other stuff that can be displayed. Once a swipe is complete, the delegate should be called, probably something like tableView(_ tableView: UITableView, didSwipeRowAt indexPath: IndexPath withSwipe swipe: Swipe).
My question is: Is it possible in Swift 3 or 4 to extend UITableViewDataSource and UITableViewDelegate with these custom functions so that I don’t need to know the class, I just need to know it conforms to the protocols? Or perhaps, I could create a new protocol that inherits from the table view protocols and includes custom functions, but then is it possible to subclass uitableview and change the type of dataSource and delegate variables from UITableViewDataSource and UITableViewDelegate to some custom SwipeableTableViewDataSource and SwipeableTableViewDelegate?
You can probably use protocol oriented programming to make this work - you can create a protocol and then add a default implementation for Self: UITableViewDataSource or whatever, then use it as a mix-in for whatever you’re using that actually implements the data source. You’d probably still have to do some set-up though.
There problem, however, is that I need to make the delegate conform to this. The point is that when a cell is about to swipe, it can call onto the dataSource through its reference to its parent tableView without knowing about the data source itself. So I would need to subclass UITableView and redefine dataSource property as being of SwipeableTableViewDataSource rather than its original UITableViewDataSource. Unfortunately, unless I’m missing something, I can’t change the type of a property, even if the new type inherits from the original type.
Hi, thanks for this great tutorial!
I have only one question - what’s the best way to make this accessible?
Using this approach we ended up having the UpperContentView and bellow it two buttons. The VoiceOver detects my two buttons bellow the content view, but when I try double tapping on them, it just performs cell action (which is expected, since the buttons are not visible).
It seems like I should make the “area for cell action” smaller when the VoiceOver is on, but I’m not sure how to do it.
So, any help would be very appreciated
Ooh, great question. In the visual hierarchy, the top view of the cell moves over, then taps go straight onto the UIButtons added in the view below them. Theoretically since the buttons you’re adding are standard UIButtons, they should only require a single tap and should be intercepting any taps that come through. I’ll be honest though, I’ve got no idea how that works in practice with VoiceOver.
I would look at how VoiceOver normally handles swipe to delete functionality. Since there’s a certain level of precision that’s expected when using the visual interface, maybe there’s some other method of showing what portion of the screen needs to be tapped for the actions.
The biggest piece of advice for better VoiceOver support I’d give is to use the new APIs that support this natively rather than faffing around with all this. This tutorial is from quite a while ago, so there’s a lot more of this functionality available directly from the system, which includes niceties like VoiceOver support.
@krmar, @designatednerd: Usual practice when making elements compatible with Voice Over and other assistive technologies is that each element has a single responsibility. In this case, the cell’s tap action should be the only responsibility of the cell as its the only exposed action (the other buttons are hidden until the user swipes).
You could look to making this accessible by setting the cell’s accessibility trait to none and messing around passing scroll events through so that the user can reveal the content however this won’t make it any easier for somebody using the assistive technologies.
A better way to handle this in your application would be to think of these actions as shortcuts or quick actions for a more experienced user of your app but to always provide a clear way for a less familiar user to perform the same actions. The Mail app is a perfect example of this because all the actions that can be performed using this method can also be performed when the user taps on the cell and views the email (they’re all clearly visible in the toolbar).
Apple have some great sessions on accessibility from both this year and previous events and I recommend checking them out if you are looking to improve the experience when using your app with the assistive technologies
Also because this tutorial is over 6 months old now, I’m going to close further discussion until it’s updated. In the meantime feel free to open any more specific questions in the relevant areas of the forums. Thanks