【问题标题】:Pan view using UIPanGestureRecognizer within a functional UIScrollView在功能性 UIScrollView 中使用 UIPanGestureRecognizer 平移视图
【发布时间】:2021-10-10 06:49:34
【问题描述】:

问题

我有一个包含UIViewUIScrollView,我希望允许用户使用UIPanGestureRecognizer 进行平移。

为了使其按预期工作,用户应该能够用一根手指平移视图,但 能够用另一根手指平移滚动视图 - 在同一时间(每个用一根手指)。

但是,当用户平移其中包含的视图时,滚动视图将停止工作。在视图的平移手势结束之前无法平移它。

尝试的解决方法

我尝试通过覆盖以下 UIGestureRecognizerDelegate 方法来同时滚动平移视图和包含它的 UIScrollView 来解决此问题:

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

然而,这使得平移视图移动滚动视图。每个元素的平移手势应该相互独立,而不是链接。

演示项目

我创建了一个简单的演示项目来演示这一点,在这里:

https://github.com/jeffc-dev/ScrollViewPannerTest

这个项目包含一个带有方形视图的滚动视图,应该能够独立于其包含的滚动视图进行平移,但不能。

我为什么要这样做

这样做的目的是让用户更容易/更快地找到将视图平移到的目标。这有点类似于在 Springboard 中重新排列图标:您可以用一根手指平移应用程序图标,同时同时用另一根手指在页面之间平移,快速找到放置它的位置.我没有使用分页滚动视图——只是一个普通视图——我希望它是一个无缝的平移手势(我不需要/希望用户必须进入“摆动模式”),但基本原则是一样的。


更新:DonMag 提出了使用UILongPressGestureRecognizer 将视图移出滚动视图以进行平移的想法,这似乎很有希望。但是,如果我走那条路,我想我需要在这样做之后无缝过渡到使用UIPanGestureRecognizer(因为我确实使用了一些平移手势识别器特定的功能)。

【问题讨论】:

    标签: ios uiscrollview uikit uigesturerecognizer uipangesturerecognizer


    【解决方案1】:

    我确信有不同的方法可以做到这一点,但这里有一种方法......

    我没有使用UIPanGesture,而是使用了UILongPressGesture

    当手势开始时,我们将视图从滚动视图移动到它的父视图。当我们继续按下视图并拖动它时,它现在独立于滚动视图。当我们结束手势(抬起手指)时,我们将视图添加回滚动视图。

    在拖动时,我们可以用第二根手指滚动滚动视图的内容。

    代码的主要部分如下所示:

    @objc func handleLongPress(_ g: UILongPressGestureRecognizer) -> Void {
        
        switch g.state {
        
        case .began:
            
            // get our superview and its superview
            guard let sv = superview as? UIScrollView,
                  let ssv = sv.superview
            else {
                return
            }
            theScrollView = sv
            theRootView = ssv
            
            // convert center coords
            let cvtCenter = theScrollView.convert(self.center, to: theRootView)
            self.center = cvtCenter
            curCenter = self.center
            
            // add self to ssv (removes self from sv)
            ssv.addSubview(self)
            
            // start wiggling anim
            startAnim()
            
            // inform the controller
            startCallback?(self)
            
        case .changed:
            
            guard let thisView = g.view else {
                return
            }
            
            // get the gesture point
            let point = g.location(in: thisView.superview)
            
            // Calculate new center position
            var newCenter = thisView.center;
            newCenter.x += point.x - curCenter.x;
            newCenter.y += point.y - curCenter.y;
            
            // Update view center
            thisView.center = newCenter
            curCenter = newCenter
            
            // inform the controller
            movedCallback?(self)
            
        default:
            
            // stop wiggle anim
            stopAnim()
            
            // convert center to scroll view (original superview) coords
            let cvtCenter = theRootView.convert(curCenter, to: theScrollView)
            
            // update center
            self.center = cvtCenter
            
            // add self back to scroll view
            theScrollView.addSubview(self)
            
            // inform the controller
            endedCallback?(self)
            
        }
        
    }
    

    我 fork 你的 GitHub 存储库并添加了一个新控制器来演示:https://github.com/DonMag/ScrollViewPannerTest

    您会发现它只是此方法的起点。被拖动的视图(实际上,在这个演示中,你可以用两个手指同时拖动两个视图)使用闭包来通知控制器有关拖动...

    目前,“拖放”不会影响滚动视图中的任何其他子视图。唯一能做任何事情的闭包是“结束”闭包,此时控制器会重新计算滚动视图的 contentSize。 “moved”闭包可用于重新定位视图——但这是另一项任务。

    【讨论】:

    • 谢谢,唐!我快速浏览了您的解决方案,从表面上看,它似乎可以满足我的需求。我的生产(非演示)应用程序实际上做了类似的事情——在平移时将平移视图移动到滚动视图的超级视图——所以我认为长按手势识别器将是我的关键变化。我将尝试调整我自己的代码来执行此操作,然后检查我发现的内容。再次感谢。
    • 仔细观察一下,似乎完全删除 UIPanGestureRecognizer 并非没有代价。我的简化演示没有反映这一点,但我确实在我的生产应用程序的平移手势识别器中使用了“速度”跟踪。我看过的一种方法是使用 UILongPressGestureRecognizer 将视图移出滚动视图并让它开始使用 UIPanGestureRecognizer 后缀,但我不知道如何在两者之间无缝转换。如果您(或其他任何人)有任何想法,我肯定有兴趣听听。
    • @JeffC。 - 我曾尝试单独使用 PanGesture 或与 LongPress 一起使用 PanGesture,但没有成功。您可能想尝试自己使用 LongPress 实现 Velocity。
    • @JeffC。 -- 如果您仍在寻找解决方案,我更新了我的 GitHub 存储库,使用 UILongPressGestureRecognizer 方法的速度计算。
    • 有机会我会看看这个。虽然我有点担心偏离纯粹的平移手势控制器方法,但如果速度的东西有效,我可能会根据我的需要调整它。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-25
    • 1970-01-01
    • 1970-01-01
    • 2016-12-31
    相关资源
    最近更新 更多