IOS 9 - 子视图上的 UIButton 不触发 IBAction 插座
IOS 9 - UIButton on subview does not fire IBAction outlet
我已经为此苦苦挣扎了几天,但一直无法查明问题的原因,正如标题所说,子视图上的 UIButton 没有触发"clicked" 时的 IBAction 出口。
让我详细说明一下,我正在开发一个 "tinder-like" 应用程序,我正在使用 this third party library。我正在实现自定义视图,其中包含按钮和其他控制器。这些 "Cards" 中的按钮未触发其 IBAction 插座。
据我所知,该库执行以下操作:
堆叠 3 "DraggableViews" 彼此叠加,每个可拖动视图有 2 个 child 视图,一个是内容视图,我的自定义视图所在的位置,另一个是叠加视图,上面有一个图像视图。可拖动视图使用两个手势识别器来完成它的工作,第一个是点击手势,它调用委托方法来处理卡片中的点击事件(在他们的示例中,它用于显示浏览器视图)。第二个手势是用于实现卡片滑动功能的平移手势。
我已完成作业并尝试了几种不同的解决方案,但我无法触发 IBAction。我尝试了以下方法:
使用 DraggableViews 的 parent 视图在按钮上触发触摸事件时禁用手势识别器。 - 这有效(手势被禁用)但 IBAction 未被触发。在平移手势的情况下,我不再能够在触摸按钮时 "swipe" 卡片,并且点击事件不会在上面提到的委托方法中遇到断点。在 UI 中,我的按钮在动画时对触摸做出反应,但它在视图控制器中的出口无法击中断点。我已将其禁用:
//- Called when each DraggableView is visible (not called for view at index 0, but works alright for debugging in the mean time)
func koloda(koloda: KolodaView, didShowCardAtIndex index: UInt) {
let subviews = koloda.subviews
for subview in subviews {
if let recognizers = subview.gestureRecognizers {
for gesture in recognizers {
if gesture is UIPanGestureRecognizer || gesture is UITapGestureRecognizer{
//- Also tried setting this to false but nothing.
gesture.cancelsTouchesInView = false
gesture.delegate = self
}
}
}
}
//- On the gestureRecognizerDelegate
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
if touch.view is UIButton {
return false
} else {
return true
}
}
以编程方式在按钮上实现点击手势,在 viewDidLoad 上我将动作添加到点击手势,但这也不会触发插座。
- 以编程方式将 ImageView 的 userInteractionEnabled 属性 设置为 True,希望这将允许触摸事件通过响应链(尽管我在另一个 post 中读到这会产生相反的效果效果?)。
我还在故事板中检查了自定义视图中的所有相关视图和控制器都启用了 userInteractionEnabled 选项。
我不知道它是否相关,但我的自定义视图位于 xib 文件中,当我将视图传递给库时,我通过实例化视图控制器并传递它的视图来实现,如下所示:
if let vc = spiViewConntroller {
return vc.view
}
如有任何帮助或建议,我们将不胜感激!
干杯!
编辑:
继续寻找真相,我已经从库中完全删除了覆盖视图,在 UI 调试器上检查我的自定义视图,我可以看到覆盖视图及其 ImageView 不再存在。该按钮仍然没有触发其出口,因此我可以假设叠加视图不会导致此问题。
我 fork 了 Koloda 库并创建了一个 demo example 的分支,分支名称是 "WhosebugDemo"。我添加了一个带有一个按钮的自定义视图,我在它的视图控制器中创建了两个插座,我在其中更改按钮的标题(有效),视图确实加载了。我还禁用了按钮上的两个手势以复制我当前在我的应用程序中获得的内容。 如果你要复制它,你需要刷掉第一张卡片,因为索引 0 处的卡片不会禁用手势。
我会继续挖掘,希望有人能指出我做错了什么!
干杯。
我可以建议一种方法,它可以帮助您检测问题。当模拟器为 运行 时,使用 xcode 中的调试器视图。它将以 3-D 模式向您显示视图的层次结构,这可以帮助您找出问题所在。
如何使用 debuggin 视图:
https://developer.apple.com/library/ios/documentation/ToolsLanguages/Conceptual/Xcode_Overview/ExaminingtheViewHierarchy.html
好的,我找到了答案。在进一步挖掘之后,我能够解决这个问题。但是我的解决方案感觉很脏,我不确定它是否破坏了 MVC 模式。
我认为我的问题是我的 xib 文件的自定义视图控制器以某种方式丢失或无法响应这些事件。在创建要显示为可拖动卡片内容的视图时,我正在创建视图控制器的实例并返回其视图。令我感到奇怪的是,视图控制器的 ViewDidLoad 方法在加载视图时正在执行其工作(即更改插座的值)。
解法:
我从 lib 中删除了文件所有者,创建了一个继承自 UIView 的自定义 class,例如 MyCustomUIView,并将视图控制器逻辑、其出口和操作移动到 class.然后在 xib 文件上,我将内容视图链接到 MyCustomUIView。然而,这个解决方案感觉很脏,因为我希望视图的视图控制器能够处理所有逻辑。可能需要多读一些关于 nib 和可重用视图的文章。
丹尼尔。
您的问题是您没有将视图控制器添加为子视图控制器以使用 Koloda 操作的视图控制器。结果显示了你的 vc.view,因为 Koloda 保留了它,但没有人保留你的视图控制器,所以你失去了重要的生命周期方法,它被释放了。
您尝试使用的方法称为容器视图控制器。 Apple 在此处对其实施提出了建议:https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/ImplementingaContainerViewController.html
此处简单实现:
- (void) displayContentController: (UIViewController*) content {
[self addChildViewController:content];
content.view.frame = [self frameForContentController];
[self.view addSubview:self.currentClientView];
[content didMoveToParentViewController:self];
}
我已经为此苦苦挣扎了几天,但一直无法查明问题的原因,正如标题所说,子视图上的 UIButton 没有触发"clicked" 时的 IBAction 出口。
让我详细说明一下,我正在开发一个 "tinder-like" 应用程序,我正在使用 this third party library。我正在实现自定义视图,其中包含按钮和其他控制器。这些 "Cards" 中的按钮未触发其 IBAction 插座。
据我所知,该库执行以下操作:
堆叠 3 "DraggableViews" 彼此叠加,每个可拖动视图有 2 个 child 视图,一个是内容视图,我的自定义视图所在的位置,另一个是叠加视图,上面有一个图像视图。可拖动视图使用两个手势识别器来完成它的工作,第一个是点击手势,它调用委托方法来处理卡片中的点击事件(在他们的示例中,它用于显示浏览器视图)。第二个手势是用于实现卡片滑动功能的平移手势。
我已完成作业并尝试了几种不同的解决方案,但我无法触发 IBAction。我尝试了以下方法:
使用 DraggableViews 的 parent 视图在按钮上触发触摸事件时禁用手势识别器。 - 这有效(手势被禁用)但 IBAction 未被触发。在平移手势的情况下,我不再能够在触摸按钮时 "swipe" 卡片,并且点击事件不会在上面提到的委托方法中遇到断点。在 UI 中,我的按钮在动画时对触摸做出反应,但它在视图控制器中的出口无法击中断点。我已将其禁用:
//- Called when each DraggableView is visible (not called for view at index 0, but works alright for debugging in the mean time) func koloda(koloda: KolodaView, didShowCardAtIndex index: UInt) { let subviews = koloda.subviews for subview in subviews { if let recognizers = subview.gestureRecognizers { for gesture in recognizers { if gesture is UIPanGestureRecognizer || gesture is UITapGestureRecognizer{ //- Also tried setting this to false but nothing. gesture.cancelsTouchesInView = false gesture.delegate = self } } } } //- On the gestureRecognizerDelegate func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool { if touch.view is UIButton { return false } else { return true } }
以编程方式在按钮上实现点击手势,在 viewDidLoad 上我将动作添加到点击手势,但这也不会触发插座。
- 以编程方式将 ImageView 的 userInteractionEnabled 属性 设置为 True,希望这将允许触摸事件通过响应链(尽管我在另一个 post 中读到这会产生相反的效果效果?)。
我还在故事板中检查了自定义视图中的所有相关视图和控制器都启用了 userInteractionEnabled 选项。
我不知道它是否相关,但我的自定义视图位于 xib 文件中,当我将视图传递给库时,我通过实例化视图控制器并传递它的视图来实现,如下所示:
if let vc = spiViewConntroller {
return vc.view
}
如有任何帮助或建议,我们将不胜感激!
干杯!
编辑: 继续寻找真相,我已经从库中完全删除了覆盖视图,在 UI 调试器上检查我的自定义视图,我可以看到覆盖视图及其 ImageView 不再存在。该按钮仍然没有触发其出口,因此我可以假设叠加视图不会导致此问题。
我 fork 了 Koloda 库并创建了一个 demo example 的分支,分支名称是 "WhosebugDemo"。我添加了一个带有一个按钮的自定义视图,我在它的视图控制器中创建了两个插座,我在其中更改按钮的标题(有效),视图确实加载了。我还禁用了按钮上的两个手势以复制我当前在我的应用程序中获得的内容。 如果你要复制它,你需要刷掉第一张卡片,因为索引 0 处的卡片不会禁用手势。
我会继续挖掘,希望有人能指出我做错了什么!
干杯。
我可以建议一种方法,它可以帮助您检测问题。当模拟器为 运行 时,使用 xcode 中的调试器视图。它将以 3-D 模式向您显示视图的层次结构,这可以帮助您找出问题所在。 如何使用 debuggin 视图: https://developer.apple.com/library/ios/documentation/ToolsLanguages/Conceptual/Xcode_Overview/ExaminingtheViewHierarchy.html
好的,我找到了答案。在进一步挖掘之后,我能够解决这个问题。但是我的解决方案感觉很脏,我不确定它是否破坏了 MVC 模式。
我认为我的问题是我的 xib 文件的自定义视图控制器以某种方式丢失或无法响应这些事件。在创建要显示为可拖动卡片内容的视图时,我正在创建视图控制器的实例并返回其视图。令我感到奇怪的是,视图控制器的 ViewDidLoad 方法在加载视图时正在执行其工作(即更改插座的值)。
解法: 我从 lib 中删除了文件所有者,创建了一个继承自 UIView 的自定义 class,例如 MyCustomUIView,并将视图控制器逻辑、其出口和操作移动到 class.然后在 xib 文件上,我将内容视图链接到 MyCustomUIView。然而,这个解决方案感觉很脏,因为我希望视图的视图控制器能够处理所有逻辑。可能需要多读一些关于 nib 和可重用视图的文章。
丹尼尔。 您的问题是您没有将视图控制器添加为子视图控制器以使用 Koloda 操作的视图控制器。结果显示了你的 vc.view,因为 Koloda 保留了它,但没有人保留你的视图控制器,所以你失去了重要的生命周期方法,它被释放了。
您尝试使用的方法称为容器视图控制器。 Apple 在此处对其实施提出了建议:https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/ImplementingaContainerViewController.html
此处简单实现:
- (void) displayContentController: (UIViewController*) content {
[self addChildViewController:content];
content.view.frame = [self frameForContentController];
[self.view addSubview:self.currentClientView];
[content didMoveToParentViewController:self];
}