可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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.
回答1:
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 }
回答2:
For anyone in search of the Swift
version of VaporwareWolf's answer, here it is:
func animateRevealHideActionForRow(tableView: UITableView, indexPath: NSIndexPath) { let cell = tableView.cellForRowAtIndexPath(indexPath); // Should be used in a block var swipeLabel: UILabel? = UILabel.init(frame: CGRectMake(cell!.bounds.size.width, 0, 200, 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.whiteColor() cell!.addSubview(swipeLabel!) UIView.animateWithDuration(0.3, animations: { cell!.frame = CGRectMake(cell!.frame.origin.x - 100, cell!.frame.origin.y, cell!.bounds.size.width + 100, cell!.bounds.size.height) }) { (finished) in UIView.animateWithDuration(0.3, animations: { cell!.frame = CGRectMake(cell!.frame.origin.x + 100, cell!.frame.origin.y, cell!.bounds.size.width - 100, cell!.bounds.size.height) }, completion: { (finished) in swipeLabel?.removeFromSuperview() swipeLabel = nil; }) } }
回答3:
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 }) } }
回答4:
Swift 3 Equivalent of Burak's answer. You can programmatically fire off this call wherever you want, I put it in a helper function so any table view could show this. And the first time a user uses my app I swipe it open (I felt a longer animation time was needed).
class func animateRevealHideActionForRow(tableView: UITableView, indexPath: NSIndexPath) { let cell = tableView.cellForRow(at: indexPath as IndexPath); // Should be used in a block var swipeLabel: UILabel? = UILabel.init(frame: CGRect.init(x: cell!.bounds.size.width, y: 0, width: 200, height: cell!.bounds.size.height)) swipeLabel!.text = " Swipe Me"; swipeLabel!.backgroundColor = UIColor.red swipeLabel!.textColor = UIColor.white cell!.addSubview(swipeLabel!) UIView.animate(withDuration: 1.0, animations: { cell!.frame = CGRect.init(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: 1.0, animations: { cell!.frame = CGRect.init(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; }) } }