UIView 子视图未接收到触摸

UIView subview not receiving touches

我想了解为什么我的子视图没有接收到触摸。

下面是一张显示我遇到的行为的 gif:当我单击右侧的青色按钮时,没有任何反应(左侧视图的背景应该会改变颜色)。当我点击左边的绿色按钮时,它正确地接收到触摸事件,触发附加的 TouchDown 动作并且视图的颜色发生变化。

这个 "app" 显然不是真正的应用程序,只是为了说明我遇到的行为。我真正想要的是学习如何实现您在许多应用程序中看到的常见 "slide out menu" 模式;通常带有一个伴随的汉堡包按钮。

在许多此类应用中,主要的应用内容似乎被移到一边以显示菜单,"hiding" 可以说是在应用下方。我试图在这里复制同样的行为。

我将我的 ViewController 代码粘贴到这里。你在下面看到的代码就是我所有的。

import UIKit

class ViewController: UIViewController {

    var originalX : CGFloat!
    var originalY : CGFloat!

    var containerView = UIView()

    var button : UIButton!
    var button2 : UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()

        originalX      = self.view.frame.origin.x
        originalY      = self.view.frame.origin.y

        button = UIButton(frame: CGRectMake(200, 25, 100, 100))
        button.backgroundColor = UIColor.greenColor()
        button.addTarget(self, action: "foo", forControlEvents: .TouchDown)

        view.addSubview(button)

        containerView.frame = CGRectMake(self.view.frame.width, originalY, 150, self.view.frame.height)
        containerView.userInteractionEnabled = true
        containerView.backgroundColor = UIColor.magentaColor()
        containerView.clipsToBounds = false

        button2 = UIButton(frame: CGRectMake(25, 25, 100, 100))
        button2.backgroundColor = UIColor.cyanColor()
        button2.addTarget(self, action: "bar", forControlEvents: .TouchDown)

        view.addSubview(containerView)
        containerView.addSubview(button2)
    }

    @IBAction func left() {
        UIView.animateWithDuration(0.3) {
            self.view.frame = CGRectMake(self.originalX - 150, self.originalY, self.view.frame.width, self.view.frame.height)
        }
    }

    @IBAction func right() {
        UIView.animateWithDuration(0.3) {
            self.view.frame = CGRectMake(self.originalX, self.originalY, self.view.frame.width, self.view.frame.height)
        }
    }

    func foo() {
        UIView.animateWithDuration(1.0) {
            self.view.backgroundColor = UIColor.redColor()
        }
    }

    func bar() {
        UIView.animateWithDuration(1.0) {
            self.view.backgroundColor = UIColor.blueColor()
        }
    }

}

您需要保持主 view 足够大以接收事件。在 left().

中使用 self.view.frame.width + 150 作为 CGRectMake 的第三个参数

但是,无论您尝试做什么,这都是一个奇怪而脆弱的解决方案。您不应该移动主视图的框架。这必须覆盖整个 UIWindow,仅此而已。您只想为子视图设置动画,并考虑您是否真的在使用 PageViewController idiomCollectionView 习惯用法、UIScrollView 习惯用法或 SpriteKit 习惯用法。想想你为什么要移动你的中央控制按钮和你的中央标签,使一个无法使用的 'jumpy' 界面。

一个脆弱性是在 viewDidLoad() 中进行布局计算,这在 ViewController 生命周期中还为时过早。参见:wrong frame size in viewDidLoad

正确的方法是多做一些工作:约束一个自定义的 UIView 子类来填充您的主视图,然后如果您必须进行非情节提要代码内布局计算,请在重写的 layoutSubviews() 该自定义子类的方法——此时正确的几何形状 可用。 (但是,在代码中向自定义 UIView 子类添加子视图应该在 layoutSubviews()` 中完成,而是在构造或 nib 唤醒时完成。)

如果您的主视图不需要移动,事情会变得 很多 容易。如果您能熟练阅读 Objective-C,请尝试:http://www.teehanlax.com/blog/custom-uiviewcontroller-transitions/

然后您将获得真正的关注点分离,您的滑动设置真正是独立的。引用:

Here’s the interaction we’re going to create. It’s nothing special – just a view appearing from the right edge of the screen. What is special is that we’re actually presenting a view controller, even though the presenting view controller remains visible.

containerViewview 的子视图,但 containerView 的原点在其父视图 (view) 的右边缘右侧,因为行:

containerView.frame = CGRectMake(self.view.frame.width, originalY, 150, self.view.frame.height)

超出其 superview 边界的子视图的任何部分都不会接收触摸事件。触摸事件只会被父视图边界 的子视图部分传递和识别 这就是为什么当你点击它时你的青色按钮不会 "fire" .

解决它的一种方法是不操纵 view 的框架,而是使用辅助子视图(称为 overlayView)覆盖并覆盖 containerView,然后操纵它的框架。确保至少有一部分两个视图都在主视图的范围内,以便它们可以接收触摸事件。

对于您的代码,您已将 containerView 添加到 self.view,但它的框架不在 self.view.bounds 中,因此 containerView 无法接收任何触摸,所以你应该做的是

  • 只需确保 self.view 足够大以包含 containerView,至少包含 button2

  • 只需为 containerView 帧制作动画,使其在 self.view