I have a UITableView where the user can swipe left to reveal actions (like in iOS 8 mail). That all works as expected. I want to trigger this when the user taps on a certain part of the cell. How can I invoke this slide action programmatically?
Current behavior: User must swipe the cell left to disclose the action buttons.
Desired behavior: User taps (an actions button) on the cell. Cell slides over to disclose the action buttons.
Well I couldn't find a way to do this programmatically, but I came up with this workaround. When the user taps the cell, I animated (pan) it to the left to momentarily reveal afake "Swipe Me" button. This is quickly reversed so the cell is back to normal. This provides a visual cue to let the user know that they can swipe the cell:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
__block UILabel *swipeLabel = [[UILabel alloc]initWithFrame:CGRectMake(cell.bounds.size.width,
0,
200,
cell.bounds.size.height)];
swipeLabel.text = @" Swipe Me";
swipeLabel.backgroundColor = [UIColor greenColor];
swipeLabel.textColor = [UIColor whiteColor];
[cell addSubview:swipeLabel];
[UIView animateWithDuration:0.3 animations:^{
[cell setFrame:CGRectMake(cell.frame.origin.x - 100, cell.frame.origin.y, cell.bounds.size.width, cell.bounds.size.height)];
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.3 animations:^{
[cell setFrame:CGRectMake(cell.frame.origin.x + 100, cell.frame.origin.y, cell.bounds.size.width, cell.bounds.size.height)];
} completion:^(BOOL finished) {
[swipeLabel removeFromSuperview];
swipeLabel = nil;
}];
}];
}
Hope this helps someone.
Note that you need to set your tableViewCell's selection type to none. Else the gray bar will obscure it.
Update. I thought I'd post a more Swifty version:
func previewActions(forCellAt indexPath: IndexPath) {
guard let cell = tableView.cellForRow(at: indexPath) else {
return
}
let label: UILabel = {
let label = UILabel(frame: CGRect.zero)
label.text = " Swipe Me "
label.backgroundColor = .blue
label.textColor = .white
return label
}()
// Figure out the best width and update label.frame
let bestSize = label.sizeThatFits(label.frame.size)
label.frame = CGRect(x: cell.bounds.width - bestSize.width, y: 0, width: bestSize.width, height: cell.bounds.height)
cell.insertSubview(label, belowSubview: cell.contentView)
UIView.animate(withDuration: 0.3, animations: {
cell.transform = CGAffineTransform.identity.translatedBy(x: -label.bounds.width, y: 0)
label.transform = CGAffineTransform.identity.translatedBy(x: label.bounds.width, y: 0)
}) { (finished) in
UIView.animateKeyframes(withDuration: 0.3, delay: 0.25, options: [], animations: {
cell.transform = CGAffineTransform.identity
label.transform = CGAffineTransform.identity
}, completion: { (finished) in
label.removeFromSuperview()
})
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
previewActions(forCellAt: indexPath)
return
}
For anyone in search of the Swift
version of VaporwareWolf's answer, here it is:
func animateRevealHideActionForRow(tableView: UITableView, indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
// Should be used in a block
var swipeLabel: UILabel? = UILabel.init(frame: CGRect(x: cell!.bounds.size.width,
y: 0,
width: 200,
height: cell!.bounds.size.height))
swipeLabel!.text = " Swipe Me";
swipeLabel!.backgroundColor = UIColor.init(red: 255/255, green: 41/255, blue: 53/255, alpha: 1) // Red
swipeLabel!.textColor = UIColor.white
cell!.addSubview(swipeLabel!)
UIView.animate(withDuration: 0.3, animations: {
cell!.frame = CGRect(x: cell!.frame.origin.x - 100, y: cell!.frame.origin.y, width: cell!.bounds.size.width + 100, height: cell!.bounds.size.height)
}) { (finished) in
UIView.animate(withDuration: 0.3, animations: {
cell!.frame = CGRect(x: cell!.frame.origin.x + 100, y: cell!.frame.origin.y, width: cell!.bounds.size.width - 100, height: cell!.bounds.size.height)
}, completion: { (finished) in
swipeLabel?.removeFromSuperview()
swipeLabel = nil;
})
}
}
Don't go with a hacky way and use a library like this until they implement the feature.
https://github.com/SwipeCellKit/SwipeCellKit
This library let you do things like: cell.showSwipe(orientation: .right, animated: true)
And for a Swift 3 version where you want to call this function for every row.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath);
UIView.animate(withDuration: 0.3, animations: {
cell!.frame = CGRect(x: cell!.frame.origin.x - 100, y: cell!.frame.origin.y, width: cell!.bounds.size.width + 100, height: cell!.bounds.size.height)
}) { (finished) in
UIView.animate(withDuration: 0.3, animations: {
cell!.frame = CGRect(x: cell!.frame.origin.x + 100, y: cell!.frame.origin.y, width: cell!.bounds.size.width - 100, height: cell!.bounds.size.height)
}, completion: { (finished) in
})
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With