我有一个UIPageViewController
,其中一页是设置屏幕。在该屏幕上,有一个UISwitch
用于打开或关闭设置。
虽然我注意到许多人像我一样轻按UISwitch
来切换它,但我发现有些用户滑动UISwitch
来切换它。
尝试滑动UISwitch
可能会在UIViewController
的一部分UIPageViewController
上滑动时引起问题,因为滑动开关可以开始滑动UIPageViewController
,就像用户想要更改页面。
这种行为感觉很差并且不一致。看来,如果用户触摸了开关,但是在滑动之前犹豫了一下,则UISwitch
记录了触摸,并且按用户期望的那样工作。但是,如果用户触摸UISwitch
并立即开始滑动,则UIPageViewController
会获得触摸。 UISwitch
之间接触与否之间似乎有一条非常细的线(犹豫阈值)。
您将如何解决此问题?
下面是一个示例,该示例以简单的轻敲来切换UISwitch
,然后显示了一些尝试滑动UISwitch
的不同方法,这些结果导致结果不一致:
可能的解决方案和问题
我考虑解决此问题的一种方法是检测设置 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 页面的UIPageViewController
和UIViewController
上检测触摸,但是都没有被调用。我还尝试在视图上设置view.isUserInteractionEnabled = true
,并在不同的true
上设置false
或UIViewController
的不同组合,但似乎仍然无法检测到触摸。
我还考虑过放弃该应用程序的整个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")
}
}
答案 0 :(得分:1)
您可以对正在使用的UISwitch进行子类化吗?这听起来更像是该类的工作,它重写了roleRecognizerShouldBegin()以为水平移动的滑动手势识别器返回NO。该方法的文档中提到UISlider出于相同目的使用该方法。 UISwitch可能应该做同样的事情。
另一个选择可能是创建一个自定义UIGestureRecognizer,如果通过UISwitch重新启动它,则它通过委托或UIGestureRecognizerSubclass方法强制任何其他UISwipeGestureRecognizer失败,并且其自身的cancelsTouchesInView设置为false(“成功”时不执行任何操作) )。
答案 1 :(得分:1)
页面视图控制器具有gestureRecognizers
属性,用于手势识别器控制页面内的交互。我会尝试将平移手势识别器添加到UISwitch
并将其添加到页面控制器。我期望的效果是,页面控制器的平移手势识别器将要求数组中的手势识别器在识别页面平移之前发生故障,因此在您轻按开关时不会发生滚动。如果仍无法解决问题,则可能需要将Page控制器换为带有堆栈或Collection视图的滚动视图,并在其中放置控制器。然后,您可以完全控制学校视图的panGEstureRecognizer
,以实现上述行为。
答案 2 :(得分:0)
只需尝试一下,看看它是否按您的意愿工作。
当
UISwitch
UISwitch
将touchBegan
的委托和数据源设置为“ nil”时,检测UIPageViewController
上的触摸。在
touchesEnd
上再次设置datasource
的{{1}}和delegate
。
通过这种方式,您将可以根据需要与UIPageViewController
进行交互。