2017-03-05 75 views
0

我有一個TableView,它已被編碼,以便在使用didSelectRowAt方法選擇任何單元格時執行操作。如何添加滑動左手勢到TableView並返回在Swift中滑動時的單元格位置3

現在,我想向表格(或單元格)添加一個向左滑動手勢,以便在單元格被切換而不是點擊時執行輔助操作。

1)我希望單元格在划動時向左移動,但我不想在單元格從其移動的空間中添加按鈕。

2)相反,我希望能夠將單元格拖動到某個點(例如半路),然後在該點處使用indexPath執行輔助操作(這樣我就知道哪個單元格被拖動了) 。 3)如果用戶停止拖動或放開單元格,我希望它返回到它的起始位置並且不發生任何動作。

我見過很多樣品,做了各種各樣的這件事,但大多數是在Obj-C或插入與單元格在同一行中的按鈕。

另外,將手勢添加到每個單元格會更好嗎? 似乎更聰明,將其添加到表...

編輯:用代碼下面請參閱我的完整的答案

+0

可能重複的[在iOS 9中可滑動的表格視圖單元格](http://stackoverflow.com/questions/32004557/swipe-able-table-view-cell-in-ios-9) – 2017-03-05 19:52:34

+0

這不是OP詢問的是什麼 –

+0

@MichaelFourre是正確的。不過,我剛剛發現了兩個帖子,顯示了我正在尋找的內容,以及幾乎完全相同的內容。 GENERAL:https://www.raywenderlich.com/77974/making-a-gesture-driven-to-do-list-app-like-clear-in-swift-part-1 EXACT:https://gabrielghe.github .io/swift/2016/03/20/swipable-uitableviewcell – wayneh

回答

3

我做了一些研究,創造瞭如何將這個一個最基本的例子 - 創建一個表格單元格,可以滑動並輕敲。我在音樂播放器中使用它 - 點擊一個單元格並播放該歌曲,輕掃相同的單元格並繼續播放到不同的視圖。

我已經建立了我的解決方案基於這兩個現有樣本: https://www.raywenderlich.com/77974/making-a-gesture-driven-to-do-list-app-like-clear-in-swift-part-1

https://gabrielghe.github.io/swift/2016/03/20/swipable-uitableviewcell

我沒有一個倉庫來共享,因此所有的代碼是在這裏。

我使用的Xcode 8.2.1和斯威夫特3

STEP 1:

  • 創建一個新的,單一視圖斯威夫特項目,並打開故事板。
  • 將TableView拖動到現有的ViewController上並拖動它以適應視圖。

第2步:

  • 添加新雨燕文件添加到項目並將其命名爲 「TableViewCellSliding.swift」。
  • 將以下代碼複製/粘貼到新文件中。

    // 
    // TableViewCellSliding.swift 
    // 
    
    import UIKit 
    
    protocol SlidingCellDelegate { 
        // tell the TableView that a swipe happened 
        func hasPerformedSwipe(touch: CGPoint) 
        func hasPerformedTap(touch: CGPoint) 
    } 
    
    class SlidingTableViewCell: UITableViewCell { 
        var delegate: SlidingCellDelegate? 
        var originalCenter = CGPoint() 
        var isSwipeSuccessful = false 
        var touch = CGPoint() 
    
    required init?(coder aDecoder: NSCoder) { 
        fatalError("init(coder:) has not been implemented") 
    } 
    
    override init(style: UITableViewCellStyle, reuseIdentifier: String?) { 
        super.init(style: style, reuseIdentifier: reuseIdentifier) 
    
        // add a PAN gesture 
        let pRecognizer = UIPanGestureRecognizer(target: self, action: #selector(SlidingTableViewCell.handlePan(_:))) 
        pRecognizer.delegate = self 
        addGestureRecognizer(pRecognizer) 
    
        // add a TAP gesture 
        // note that adding the PAN gesture to a cell disables the built-in tap responder (didSelectRowAtIndexPath) 
        // so we can add in our own here if we want both swipe and tap actions 
        let tRecognizer = UITapGestureRecognizer(target: self, action: #selector(SlidingTableViewCell.handleTap(_:))) 
        tRecognizer.delegate = self 
        addGestureRecognizer(tRecognizer) 
    } 
    
    override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { 
        if let panGestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer { 
         let translation = panGestureRecognizer.translation(in: superview!) 
         //look for right-swipe 
         if (fabs(translation.x) > fabs(translation.y)) && (translation.x > 0){ 
    
         // look for left-swipe 
         //if (fabs(translation.x) > fabs(translation.y)) && (translation.x < 0){ 
          //print("gesture 1") 
          touch = panGestureRecognizer.location(in: superview) 
          return true 
         } 
         //not left or right - must be up or down 
         return false 
        }else if gestureRecognizer is UITapGestureRecognizer { 
         touch = gestureRecognizer.location(in: superview) 
         return true 
        } 
        return false 
    } 
    
    func handleTap(_ recognizer: UITapGestureRecognizer){ 
        // call function to get indexPath since didSelectRowAtIndexPath will be disabled 
        delegate?.hasPerformedTap(touch: touch) 
    } 
    
    func handlePan(_ recognizer: UIPanGestureRecognizer) { 
        if recognizer.state == .began { 
         originalCenter = center 
        } 
    
        if recognizer.state == .changed { 
         checkIfSwiped(recongizer: recognizer) 
        } 
    
        if recognizer.state == .ended { 
         let originalFrame = CGRect(x: 0, y: frame.origin.y, width: bounds.size.width, height: bounds.size.height) 
         if isSwipeSuccessful{ 
          delegate?.hasPerformedSwipe(touch: touch) 
    
          //after 'short' swipe animate back to origin quickly 
          moveViewBackIntoPlaceSlowly(originalFrame: originalFrame) 
         } else { 
          //after successful swipe animate back to origin slowly 
          moveViewBackIntoPlace(originalFrame: originalFrame) 
         } 
        } 
    } 
    
    func checkIfSwiped(recongizer: UIPanGestureRecognizer) { 
        let translation = recongizer.translation(in: self) 
        center = CGPoint(x: originalCenter.x + translation.x, y: originalCenter.y) 
    
        //this allows only swipe-right 
        isSwipeSuccessful = frame.origin.x > frame.size.width/2.0 //pan is 1/2 width of the cell 
    
        //this allows only swipe-left 
        //isSwipeSuccessful = frame.origin.x < -frame.size.width/3.0 //pan is 1/3 width of the cell 
    } 
    
    func moveViewBackIntoPlace(originalFrame: CGRect) { 
        UIView.animate(withDuration: 0.2, animations: {self.frame = originalFrame}) 
    } 
    func moveViewBackIntoPlaceSlowly(originalFrame: CGRect) { 
        UIView.animate(withDuration: 1.5, animations: {self.frame = originalFrame}) 
    } 
    
    } 
    

步驟3:

  • 複製/粘貼下面的代碼到現有文件「的ViewController。雨燕」

    // 
    // ViewController.swift 
    // 
    
    import UIKit 
    
    class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, SlidingCellDelegate { 
    
    @IBOutlet weak var tableView: UITableView! 
    
    override func viewDidLoad() { 
        super.viewDidLoad() 
        // Do any additional setup after loading the view, typically from a nib. 
    
        tableView.dataSource = self 
        tableView.delegate = self 
        tableView.register(SlidingTableViewCell.self, forCellReuseIdentifier: "cell") 
        tableView.rowHeight = 50; 
    } 
    
    func hasPerformedSwipe(touch: CGPoint) { 
        if let indexPath = tableView.indexPathForRow(at: touch) { 
         // Access the image or the cell at this index path 
         print("got a swipe row:\(indexPath.row)") 
        } 
    } 
    
    func hasPerformedTap(touch: CGPoint){ 
        if let indexPath = tableView.indexPathForRow(at: touch) { 
        // Access the image or the cell at this index path 
         print("got a tap row:\(indexPath.row)") 
        } 
    } 
    
    override func didReceiveMemoryWarning() { 
        super.didReceiveMemoryWarning() 
        // Dispose of any resources that can be recreated. 
    } 
    
    func numberOfSectionsInTableView(tableView: UITableView) -> Int { 
        return 1 
    } 
    func tableView(_ tableView: UITableView,numberOfRowsInSection section: Int)-> Int { 
        return 100 
    } 
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
        let cell=tableView.dequeueReusableCell(withIdentifier: "cell",for: indexPath) as! SlidingTableViewCell 
        // Configure cell 
        cell.selectionStyle = .none 
        cell.textLabel?.text = "hello \(indexPath.row)" 
        cell.delegate = self 
        return cell 
    } 
    func tableView(sender: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { 
        // do stuff with indexPath.row and indexPath.section 
        //never make it here because we added a tap gesture but this will 
        print("selected cell") 
    } 
    } 
    

第4步:

連接這一切的故事板

  • 打開故事板視圖,並選擇TableView中轉到連接督察(大寫。然後從New Referencing Outlet拖動到TableView並從彈出式菜單中選擇「tableView」。

  • 在仍然選中TableView的情況下,將Outlets> dataSource拖到Storyboard中的TableView中。重複從Outlets> delegate開始。

STEP 5:

  • 運行它!

我沒有深入討論任何代碼的細節,因爲頂部的兩個鏈接做得非常好。這只是關於您可以構建的完整,簡單,乾淨的代碼。請享用。