在页面之一中包含的UISwitch上开始触摸时,禁用UIPageViewController滚动

时间:2018-12-16 19:11:04

标签: ios uipageviewcontroller uiswitch

我有一个UIPageViewController,其中一页是设置屏幕。在该屏幕上,有一个UISwitch用于打开或关闭设置。

虽然我注意到许多人像我一样轻按UISwitch来切换它,但我发现有些用户滑动UISwitch来切换它。

尝试滑动UISwitch可能会在UIViewController的一部分UIPageViewController上滑动时引起问题,因为滑动开关可以开始滑动UIPageViewController,就像用户想要更改页面。

这种行为感觉很差并且不一致。看来,如果用户触摸了开关,但是在滑动之前犹豫了一下,则UISwitch记录了触摸,并且按用户期望的那样工作。但是,如果用户触摸UISwitch并立即开始滑动,则UIPageViewController会获得触摸。 UISwitch之间接触与否之间似乎有一条非常细的线(犹豫阈值)。

您将如何解决此问题?

下面是一个示例,该示例以简单的轻敲来切换UISwitch,然后显示了一些尝试滑动UISwitch的不同方法,这些结果导致结果不一致:

inconsistent-uiswitch-behavior


可能的解决方案和问题

我考虑解决此问题的一种方法是检测设置 UIViewController上任何位置的触摸,如果触摸在UISwitch框架中的某处开始,请防止UIPageViewController滑动。

我担心的是,仅禁用UIPageViewController的滑动并不能保证触摸会传递给UISwitch。这意味着用户可能会尝试滑动UISwitch,而UIPageViewController不会滑动,但是UISwitch也不会对触摸做出响应,从而使其看起来仍然很破碎且不一致。 / p>

为了开始探索这种可能的解决方案,我尝试通过覆盖touchesBegan这样的方法来检测触摸:

override func touchesBegan(_ touches: Set<UITouch>,
                           with event: UIEvent?) {

    print("touchesBegan")

    super.touchesBegan(touches,
                       with: event)
}

我尝试以此方式在特定 Settings 页面的UIPageViewControllerUIViewController上检测触摸,但是都没有被调用。我还尝试在视图上设置view.isUserInteractionEnabled = true,并在不同的true上设置falseUIViewController的不同组合,但似乎仍然无法检测到触摸。

我还考虑过放弃该应用程序的整个UIPageViewController范例,而将 Settings 屏幕设置为模式,因为这将解决对这种复杂解决方案的需求,但是应用程序中的UIPageViewController范例还有其他优点,因此我想探讨是否可以保留。最终,这似乎比怪异的解决方法更好,但是我还是想发布此消息,以防其他人遇到相同的问题或任何其他人有其他可能的解决方案。


更新:解决方案

我花了很多时间根据提交的答案进行实验,同时还学习了很多有关iOS工作原理的知识,所以谢谢所有回答的人。

最终,Leon的答案使我沿着使用UIPanGestureRecognizer的简单解决方案前进,这与我根据Carl的答案使用UISwipeGestureRecognizer尝试的解决方案非常相似,但最终没有产生相同的结果。

我最终继承了UISwitch的子类,并添加了一个UIPanGestureRecognizer什么也不做。这使得它的行为完全符合我的期望:每当用户开始滑动开关时,UIPageViewController都不会平移。

class NoPanSwitch: UISwitch {

    override init(frame: CGRect) {
        super.init(frame: frame)

        let recognizer = UIPanGestureRecognizer(target: self,
                                                action: nil)
        addGestureRecognizer(recognizer)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

3 个答案:

答案 0 :(得分:1)

您可以对正在使用的UISwitch进行子类化吗?这听起来更像是该类的工作,它重写了roleRecognizerShouldBegin()以为水平移动的滑动手势识别器返回NO。该方法的文档中提到UISlider出于相同目的使用该方法。 UISwitch可能应该做同样的事情。

另一个选择可能是创建一个自定义UIGestureRecognizer,如果通过UISwitch重新启动它,则它通过委托或UIGestureRecognizerSubclass方法强制任何其他UISwipeGestureRecognizer失败,并且其自身的cancelsTouchesInView设置为false(“成功”时不执行任何操作) )。

答案 1 :(得分:1)

页面视图控制器具有gestureRecognizers属性,用于手势识别器控制页面内的交互。我会尝试将平移手势识别器添加到UISwitch并将其添加到页面控制器。我期望的效果是,页面控制器的平移手势识别器将要求数组中的手势识别器在识别页面平移之前发生故障,因此在您轻按开关时不会发生滚动。如果仍无法解决问题,则可能需要将Page控制器换为带有堆栈或Collection视图的滚动视图,并在其中放置控制器。然后,您可以完全控制学校视图的panGEstureRecognizer,以实现上述行为。

答案 2 :(得分:0)

只需尝试一下,看看它是否按您的意愿工作。

  
      
  1. UISwitch UISwitchtouchBegan的委托和数据源设置为“ nil”时,检测UIPageViewController上的触摸。

  2.   
  3. touchesEnd上再次设置datasource的{​​{1}}和delegate

  4.   

通过这种方式,您将可以根据需要与UIPageViewController进行交互。