带有 UIPanGestureRecognizer 的 UITableView 导致 "jumping" 触摸

UITableView with UIPanGestureRecognizer causes "jumping" touch

案例:https://github.com/ArtworkAD/ios_jumping_y.git

容器

class ContainerController: UIViewController { 
    @IBOutlet weak var container: UIView!   
    @IBOutlet weak var foregroundTopSpace: NSLayoutConstraint!
    @IBOutlet weak var foregroundBottomSpace: NSLayoutConstraint!
}

容器连接到其右侧的 UITableViewController。

我想做什么

用户滚动 table,当他到达顶部时,我想用相同的动作将 table 向下移动。所以我干脆把容器视图的top/bottomspace改一下。然而,这会导致 table 跳转。

class MainController: UITableViewController, UIGestureRecognizerDelegate {

    var panRecognizer: UIPanGestureRecognizer!

    var gotStart: Bool = true

    var startTouch: CGPoint!

    override func viewDidLoad() {
        super.viewDidLoad()

        self.tableView.bounces = false

        self.panRecognizer = self.tableView.panGestureRecognizer
        self.panRecognizer.addTarget(self, action: "pan:")
        self.tableView.addGestureRecognizer(self.panRecognizer)
    }

    func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }

    func pan(rec:UIPanGestureRecognizer){

        if let parent = self.parentViewController as? ContainerController {

            var y = self.tableView.contentOffset.y
            var touch = rec.locationInView(self.view)

            // JUMPING y
            println(touch.y)

            if y == -64 {

                if self.gotStart  || y < -64 || y > -64 {

                    self.startTouch = touch
                    self.gotStart = false

                } else {

                    if rec.state == .Changed {

                        var changedVerticalHeight = (self.startTouch.y - touch.y)*(-1)

                        if changedVerticalHeight <= parent.view.frame.size.height && touch.y >= changedVerticalHeight {

                            parent.foregroundTopSpace.constant = changedVerticalHeight
                            parent.foregroundBottomSpace.constant = -changedVerticalHeight
                        }

                    } else if rec.state == .Ended {

                        parent.foregroundTopSpace.constant = 0
                        parent.foregroundBottomSpace.constant = 0

                        self.gotStart = true
                    }
                }
            }
        }
    }
}

结果:

有什么想法吗?容器视图肯定有问题,因为当我直接移动 table 视图时没有跳转。

您正在根据 self.view 系统坐标打印位置。 UITableViewController 使用像 self.view 这样的 table 视图。所以当用户滚动时,原点 (x:0 y:0) 开始移动。

您必须使用静态系统坐标。正确使用 UIViewControllerUITableView panGestureRecognizer 属性 打印位置并滚动:

  1. 新建 UIViewController.
  2. 添加 UITableview 并设置 AutoLayout
  3. 连接 IBOutletUITableView

将代码添加到 UIViewController class:

var panRecognizer: UIPanGestureRecognizer!
@IBOutlet weak var tableView: UITableView?

override func viewDidLoad() {
    super.viewDidLoad()

    self.panRecognizer = tableView?.panGestureRecognizer;
    self.panRecognizer .addTarget(self, action: "pan:")
    tableView?.addGestureRecognizer(self.panRecognizer)

}

func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    return true
}

func pan(rec:UIPanGestureRecognizer){
    println(rec.locationInView(self.view).y)
}

您可以下载项目示例here

如果您只需要控制滚动,请记住 UIScrollView delegate method:

optional func scrollViewDidScroll(_ scrollView: UIScrollView)

可以帮到你。这是一个更清洁更简单的解决方案:

祝你好运。

我相信正是你想要的:

import UIKit

class MainController: UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
        let beginingContentOffset: CGFloat = -64
        if scrollView.contentOffset.y < beginingContentOffset {
            scrollView.bounces = false
            UIView.animateWithDuration(0.05, animations: { () -> Void in
                scrollView.contentOffset = CGPointMake(0, 0)
                }, completion: { (finished: Bool) -> Void in
                scrollView.bounces = true
            })
        }
    }

    // Default table stuff, not related to problem

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 20
    }

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var cell_ : UITableViewCell? = tableView.dequeueReusableCellWithIdentifier("CELL_ID") as? UITableViewCell
        if(cell_ == nil){
            cell_ = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "CELL_ID")
        }

        cell_!.textLabel!.text = "Row " + String(indexPath.row)

        return cell_!
    }
}

P.S。那个“-64”值。这是情节提要的保证金。您可以取消选中约束边距,它将为“0”。会最清楚

在我放完整代码之前,我会在我的答案中澄清一些事情

  1. 你可以使用函数scrollViewWillEndDragging来知道contentOffset的确切位置,看下面的代码:

    override func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
       println(targetContentOffset.memory.y)        
    }
    
  2. 您可以使用函数scrollViewDidEndDecelerating知道滚动何时结束。

然后您可以通过以下方式合并以上两个技巧来实现您的目标:

class MainController: UITableViewController {

   var position : CGFloat!

   override func viewDidLoad() {
      super.viewDidLoad()       
   }

   override func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {  
      // Save where the contentOffset go        
      position = targetContentOffset.memory.y
   }   

   override func scrollViewDidEndDecelerating(scrollView: UIScrollView) {

       // If reach the top or more than the top when the user move the scroll
       if (position < 0) {               
           var to = scrollView.contentOffset.y + 213
           scrollView.setContentOffset(CGPoint(x: 0, y: to), animated: true)
       }        
   }    

   // Default table stuff, not related to problem  

   /* Here comes the rest of your code of TableView */    
}

我为您的项目删除了一些相对于 panGestureRecognizer 的代码并跳出进行测试。

var to = scrollView.contentOffset.y + 213行你可以添加position变量或者你想要的值,我放213只是为了测试下行。

希望对你有所帮助。