在其中一个页面中包含的 UISwitch 上开始触摸时禁用 UIPageViewController 滚动
Disable UIPageViewController scrolling when touches start on UISwitch contained in one of the pages
我有一个 UIPageViewController
,其中一页是 设置 屏幕。在该屏幕上,有一个 UISwitch
用于打开或关闭设置。
虽然我注意到许多人像我一样点击 UISwitch
来切换它,但我观察到一些用户滑动 UISwitch
来切换它。
当 UISwitch
位于 UIPageViewController
的一部分时,尝试滑动 UISwitch
可能会导致问题,因为滑动开关可以开始滑动 UIPageViewController
如果用户想要更改页面。
这种行为让人感觉非常崩溃和不一致。看起来,如果用户触摸开关,但在滑动前短暂犹豫,则触摸由 UISwitch
注册,并且按用户期望的方式工作。但是,如果用户触摸 UISwitch
并立即开始滑动,则 UIPageViewController
会获得触摸。 UISwitch
触及与否之间似乎有一条非常细的线(犹豫阈值)。
你会如何解决这个问题?
这是一个示例,首先是简单的点击来切换 UISwitch
,然后展示了一些尝试滑动 UISwitch
的不同方法,这些方法会导致不一致的结果:
可能的解决方案和问题
我考虑过解决这个问题的一种方法是检测 设置 UIViewController
中任何位置的触摸,如果触摸开始于 [=] 框架中的某处13=],防止UIPageViewController
滑动.
我担心的是,简单地禁用 UIPageViewController
的滑动并不能保证将触摸传递给 UISwitch
。这意味着用户可能会尝试滑动 UISwitch
而 UIPageViewController
不会滑动,但 UISwitch
也不会响应触摸,使其看起来仍然损坏且不一致。
为了开始探索这个可能的解决方案,我尝试通过覆盖 touchesBegan
方法来检测触摸,如下所示:
override func touchesBegan(_ touches: Set<UITouch>,
with event: UIEvent?) {
print("touchesBegan")
super.touchesBegan(touches,
with: event)
}
我已经尝试在特定 设置 页面的 UIPageViewController
和 UIViewController
上以这种方式检测触摸,但都没有被调用。我也试过在视图上设置 view.isUserInteractionEnabled = true
,在不同的 UIViewController
上设置 true
或 false
的不同组合,但似乎仍然无法检测到触摸。
我还考虑过放弃此应用程序的整个 UIPageViewController
范式,并改为将 设置 屏幕设为模态,因为那样可以解决对此的需求一种复杂的解决方案,但应用程序中的 UIPageViewController
范例还有其他优点,所以我想探讨是否可以保留它。最终,这似乎比奇怪的解决方法更好,但我还是想post这样做,以防其他人遇到同样的问题或任何人有其他可能的解决方案。
更新:解决方案
我花了很多时间根据提交的答案进行试验,同时也了解了很多 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")
}
}
您可以子class 您正在使用的 UISwitch 吗?这听起来更像是 class 的工作,将 gestureRecognizerShouldBegin() 重写为 return NO,用于水平移动的滑动手势识别器。该方法的文档提到 UISlider 出于相同目的使用该方法; UISwitch 应该也可以这样做。
另一种选择可能是创建自定义 UIGestureRecognizer,它通过委托或 UIGestureRecognizerSubclass 方法强制任何其他 UISwipeGestureRecognizer 在 UISwitch 上启动时失败,并且它本身通过 cancelsTouchesInView 设置为 false(而不是在 "succeeds" 时做任何事情)。
试试这个,看看它是否如您所愿。
Detect the touches on UISwitch
when UISwitch
touchBegan
set delegate and datasource of UIPageViewController
to `nil.
On touchesEnd
set again set datasource
and delegate
for UIPageViewController
.
通过这种方式,您将能够随心所欲地与您的 UISwitch
互动。
页面视图控制器具有 gestureRecognizers
属性 用于控制页面内交互的手势识别器。我会尝试将平移手势识别器添加到 UISwitch
并将其添加到页面控制器。我期望的效果是页面控制器的平移手势识别器将要求数组中的手势识别器在识别页面平移之前失败,因此当您轻按开关时不会发生滚动。如果结果不是这样,您可能希望将页面控制器换成带有堆栈视图的滚动视图或包含控制器的集合视图。然后您将完全控制学校视图的 panGEstureRecognizer
以实现上述行为。
我有一个 UIPageViewController
,其中一页是 设置 屏幕。在该屏幕上,有一个 UISwitch
用于打开或关闭设置。
虽然我注意到许多人像我一样点击 UISwitch
来切换它,但我观察到一些用户滑动 UISwitch
来切换它。
当 UISwitch
位于 UIPageViewController
的一部分时,尝试滑动 UISwitch
可能会导致问题,因为滑动开关可以开始滑动 UIPageViewController
如果用户想要更改页面。
这种行为让人感觉非常崩溃和不一致。看起来,如果用户触摸开关,但在滑动前短暂犹豫,则触摸由 UISwitch
注册,并且按用户期望的方式工作。但是,如果用户触摸 UISwitch
并立即开始滑动,则 UIPageViewController
会获得触摸。 UISwitch
触及与否之间似乎有一条非常细的线(犹豫阈值)。
你会如何解决这个问题?
这是一个示例,首先是简单的点击来切换 UISwitch
,然后展示了一些尝试滑动 UISwitch
的不同方法,这些方法会导致不一致的结果:
可能的解决方案和问题
我考虑过解决这个问题的一种方法是检测 设置 UIViewController
中任何位置的触摸,如果触摸开始于 [=] 框架中的某处13=],防止UIPageViewController
滑动.
我担心的是,简单地禁用 UIPageViewController
的滑动并不能保证将触摸传递给 UISwitch
。这意味着用户可能会尝试滑动 UISwitch
而 UIPageViewController
不会滑动,但 UISwitch
也不会响应触摸,使其看起来仍然损坏且不一致。
为了开始探索这个可能的解决方案,我尝试通过覆盖 touchesBegan
方法来检测触摸,如下所示:
override func touchesBegan(_ touches: Set<UITouch>,
with event: UIEvent?) {
print("touchesBegan")
super.touchesBegan(touches,
with: event)
}
我已经尝试在特定 设置 页面的 UIPageViewController
和 UIViewController
上以这种方式检测触摸,但都没有被调用。我也试过在视图上设置 view.isUserInteractionEnabled = true
,在不同的 UIViewController
上设置 true
或 false
的不同组合,但似乎仍然无法检测到触摸。
我还考虑过放弃此应用程序的整个 UIPageViewController
范式,并改为将 设置 屏幕设为模态,因为那样可以解决对此的需求一种复杂的解决方案,但应用程序中的 UIPageViewController
范例还有其他优点,所以我想探讨是否可以保留它。最终,这似乎比奇怪的解决方法更好,但我还是想post这样做,以防其他人遇到同样的问题或任何人有其他可能的解决方案。
更新:解决方案
我花了很多时间根据提交的答案进行试验,同时也了解了很多 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")
}
}
您可以子class 您正在使用的 UISwitch 吗?这听起来更像是 class 的工作,将 gestureRecognizerShouldBegin() 重写为 return NO,用于水平移动的滑动手势识别器。该方法的文档提到 UISlider 出于相同目的使用该方法; UISwitch 应该也可以这样做。
另一种选择可能是创建自定义 UIGestureRecognizer,它通过委托或 UIGestureRecognizerSubclass 方法强制任何其他 UISwipeGestureRecognizer 在 UISwitch 上启动时失败,并且它本身通过 cancelsTouchesInView 设置为 false(而不是在 "succeeds" 时做任何事情)。
试试这个,看看它是否如您所愿。
Detect the touches on
UISwitch
whenUISwitch
touchBegan
set delegate and datasource ofUIPageViewController
to `nil.On
touchesEnd
set again setdatasource
anddelegate
forUIPageViewController
.
通过这种方式,您将能够随心所欲地与您的 UISwitch
互动。
页面视图控制器具有 gestureRecognizers
属性 用于控制页面内交互的手势识别器。我会尝试将平移手势识别器添加到 UISwitch
并将其添加到页面控制器。我期望的效果是页面控制器的平移手势识别器将要求数组中的手势识别器在识别页面平移之前失败,因此当您轻按开关时不会发生滚动。如果结果不是这样,您可能希望将页面控制器换成带有堆栈视图的滚动视图或包含控制器的集合视图。然后您将完全控制学校视图的 panGEstureRecognizer
以实现上述行为。