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 idiom
、CollectionView
习惯用法、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.
containerView
是 view
的子视图,但 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 中
我想了解为什么我的子视图没有接收到触摸。
下面是一张显示我遇到的行为的 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 idiom
、CollectionView
习惯用法、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.
containerView
是 view
的子视图,但 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 中