【问题标题】:Glitch when interactively dismissing modal交互式关闭模式时出现故障
【发布时间】:2016-05-13 07:22:37
【问题描述】:

我们在通过UIPercentDrivenInteractiveTransition 实现模态视图控制器的交互解除(向下拖动模态应该解除它)时遇到了这个问题。

设置:

  1. 设置UIViewController 嵌入在UINavigationController 中,在UINavigationBar 中至少有一个按钮
  2. 模态呈现另一个嵌入在UINavigationController 中的UIViewController,并在UINavigationBar 中至少有一个按钮
  3. 设置UIPanGestureRecognizer 在模态上呈现UINavigationController 驱动UIPercentDrivenInteractiveTransition
  4. UINavigationBar上按点将模态向下“按住”

问题:

  • 在缓慢向下拖动时,动画故障导致模态视图上下跳跃

  • 故障仅在以下情况出现:

    1. UINavigationBars 都至少有一个按钮
    2. 你在UINavigationBar点上“持有”模式

小例子可以从github repo下载。

有人遇到过这样的问题吗?有什么解决方法吗?我们的设置有什么缺陷吗?

更新

问题已在 iPhone 5 模拟器上运行上面的项目模拟,iOS 9.3OSX 10.11.4,用 Xcode 7.3.1 编译。

更新 2

进一步调查表明,该问题可能不在动画中:由于某种原因,在给定的设置中 pan.translationInView(view) 正在返回导致动画跳转的意外值。

部分解决方法

根据 Vladimir 的想法,我们通过覆盖 UINavigationBarhitTest 方法部分解决了这个问题:

class DraggableNavigationBar: UINavigationBar {

    override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
        guard let view = super.hitTest(point, withEvent: event) else { return nil }

        if view is UIControl || pointIsInsideNavigationButton(point) {
            return view
        } else {
            return nil
        }
    }

    private func pointIsInsideNavigationButton(point: CGPoint) -> Bool {
        return subviews
            .filter { $0.frame.contains(point) }
            .filter { String($0.dynamicType) == "UINavigationItemButtonView" }
            .isEmpty == false
    }
}

【问题讨论】:

  • 为我工作。在我的 iPhone 6 或 iPhone 6 的 iOS 模拟器中看不到任何故障。
  • 上面的代码没有问题。像魅力一样工作
  • 可以与我分享确切的问题。哪个操作系统类型和 xCode 版本和部署目标等。
  • 我已经能够重现故障。只有从UINavigationBar 启动锅时才会发生这种情况。向下拖动,动画跳回到 0%,然后回到预期的 1-2%。取消解雇时也会发生相同的模式,在您达到 0% 后,它会跳回 1-2%,然后又回到 0%。消除故障的事情: 1. 从模态 VC 中删除 UIBarButtonItem 2. 从呈现的 VC 中删除 UIBarButtonItem 2. 注释掉 modalPresentationStyle 分配
  • @bsmith11 是的,这就是我所描述的故障。不幸的是,您提到的解决方案都不适用于我们的案例:注释掉 modalPresentationStyle 会导致背景视图控制器消失,我们需要在两个导航栏上都有按钮。

标签: ios uinavigationcontroller modalviewcontroller


【解决方案1】:

非常有趣的故障。几天前我找到了这个问题的部分解决方案,由于没有人找到完整的解决方案,我会发布这个,也许会有所帮助。

如果您覆盖UINavigationBarhitTest 方法,您可以在拖动模式时通过按住UINavigationBar 来解决此问题:

extension UINavigationBar {

    override public func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {

        guard let view = super.hitTest(point, withEvent: event) else { return nil }

        if view.isKindOfClass(UIControl) {
            return super.hitTest(point, withEvent: event)
        } else {
            return nil
        }
    }
}

不幸的是,如果您在UINavigationBar 上按住UIBarButtonItem 拖动模态框,故障仍然存在。

您也可以尝试其他方法。

如您所见,pan.translationInView(view) 返回的值不正确,会导致动画跳转。 您需要在拖动过程中将此值与模态视图的y 坐标进行比较。您可以通过检查模态视图控制器的表示层来获取此值:

...

let translation = pan.translationInView(view)

if let layer = view.layer.presentationLayer() {
            print(layer.frame.origin.y)
}

...

您可以看到,当pan.translationInView(view) 开始显示错误值时,layer.frame.origin.y 在那一刻仍然是正确的。您可以比较这两个值并找出值不正确时的模式,并通过在translation.y 值上添加几个点来将其更改为正确。

【讨论】:

  • 感谢您的建议!我最终覆盖了hitTest,但也允许点击后退按钮(令人惊讶的是它们不是UIControl)。对translationpresentationLayer 的差异做出反应会非常棘手,因为必须考虑不同的拖动速度和方向变化。
【解决方案2】:

我没有完整的解决方案,但我能够将故障减少一定程度。我可以使用iOS 9.3.2 [通过按住导航栏向下拖动屏幕] 在 iPhone 5s 上重现此问题

问题似乎出在DismissalAnimatorUIView.animateWithDuration 块中。通过注释掉延迟和选项,即保持它们为默认值,您可以减少视图的跳跃。你也可以尝试检查不同的UIViewAnimationOptions,你会得到最小的跳跃。

    UIView.animateWithDuration(0.3,
        animations: {
            dismissedView.frame = finalFrame
        },
        completion: { _ in
            let didComplete = !transitionContext.transitionWasCancelled()
            transitionContext.completeTransition(didComplete)
        }
   )

a question 似乎正在处理您面临的相同问题。并且响应从禁用自动布局到将layoutIfNeeded 放入动画块[尝试过,两者都不起作用]。

【讨论】:

  • 感谢您的建议。但是,更改 .CurveLinear 会导致动画与手指运动不同步。另外,考虑到这个问题的具体程度(UINavigationBar 中的按钮,UINavigationBar 中的点拖动),我认为链接的问题不相关,但会检查一下。
猜你喜欢
  • 1970-01-01
  • 2017-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-12
  • 1970-01-01
  • 2022-12-16
相关资源
最近更新 更多