ios 如果将 UIView 添加为子视图,则 UIButton 目标不起作用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24814401/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
UIButton targets not working if a UIView is added as a subview
提问by Jason Silberman
I have a UIButton
. It has two subviews. I then call:
我有一个UIButton
. 它有两个子视图。然后我打电话:
[createButton addTarget:self action:@selector(openComposer) forControlEvents:UIControlEventTouchUpInside];
If I tap the parts of the UIButton
that aren't covered but one of its subviews, it works fine. However if I tap one of the subviews instead, it does not trigger the action.
如果我点击UIButton
未覆盖的部分但它的子视图之一,它工作正常。但是,如果我点击其中一个子视图,则不会触发该操作。
On both subviews, I has .userInteractionEnabled
set to YES
.
在两个子视图中,我都.userInteractionEnabled
设置为YES
.
Both subviews are plain UIViews
s with a frame
and backgroundColor
.
两个子视图都是UIViews
带有 aframe
和 的普通s backgroundColor
。
How can I get the tap to "pass through" the UIView
and onto the UIButton
?
我怎样才能让水龙头“通过”UIView
和 到UIButton
?
Thanks
谢谢
EDIT:I need to use UIControlEvents because I need UIControlEventTouchDown.
编辑:我需要使用 UIControlEvents,因为我需要 UIControlEventTouchDown。
EDIT 2:
编辑2:
Here is the code for the button.
这是按钮的代码。
@interface CreateButton ()
@property (nonatomic) Theme *theme;
@property (nonatomic) UIView *verticle;
@property (nonatomic) UIView *horizontal;
@property (nonatomic) BOOL mini;
@end
@implementation CreateButton
#pragma mark - Accessors
- (UIView *)verticle {
if (! _verticle) {
_verticle = [[UIView alloc] init];
_verticle.backgroundColor = [self.theme colorForKey:@"createButtonPlusBackgroundColor"];
_verticle.userInteractionEnabled = NO;
}
return _verticle;
}
- (UIView *)horizontal {
if (! _horizontal) {
_horizontal = [[UIView alloc] init];
_horizontal.backgroundColor = [self.theme colorForKey:@"createButtonPlusBackgroundColor"];
_verticle.userInteractionEnabled = NO;
}
return _horizontal;
}
#pragma mark - Init
- (instancetype)initWithTheme:(Theme *)theme frame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
_theme = theme;
self.layer.cornerRadius = roundf(frame.size.width / 2);
self.layer.shadowColor = [UIColor blackColor].CGColor;
self.layer.shadowOpacity = .1f;
self.layer.shadowOffset = CGSizeZero;
self.layer.shadowRadius = 15.f;
self.backgroundColor = [self.theme colorForKey:@"createButtonBackgroundColor"];
[self addSubview:self.verticle];
[self addSubview:self.horizontal];
[self addTarget:self action:@selector(animate) forControlEvents:UIControlEventTouchDown];
[self addTarget:self action:@selector(animate) forControlEvents:UIControlEventTouchUpInside];
[self addTarget:self action:@selector(animate) forControlEvents:UIControlEventTouchUpOutside];
}
return self;
}
#pragma mark - Actions
- (void)animate {
[UIView animateWithDuration:0.2 delay:0 usingSpringWithDamping:0.4 initialSpringVelocity:8 options:kNilOptions animations:^{
if (self.mini) {
self.transform = CGAffineTransformMakeScale(1.0, 1.0);
self.mini = NO;
} else {
self.transform = CGAffineTransformMakeScale(0.90, 0.90);
self.mini = YES;
}
} completion:nil];
}
#pragma mark - UIView
- (void)layoutSubviews {
CGSize size = self.bounds.size;
NSInteger width = 3;
NSInteger verticleInset = 12;
self.verticle.frame = CGRectMake((size.width - width) / 2, verticleInset, width, size.height - (verticleInset * 2));
self.horizontal.frame = CGRectMake(verticleInset, (size.height - width) / 2, size.width - (verticleInset * 2), width);
}
@end
回答by Tyler
Set userInteractionEnabled
to NO
for your subviews to let touches pass through them and onto your button.
设置userInteractionEnabled
到NO
你的子视图,让触摸通过他们到您的按钮。
Also make sure to change _verticle.userInteractionEnabled = NO;
in your lazy-loader for your horizontal
property to _horizontal.userInteractionEnabled = NO;
as I believe that's a typo.
还要确保将_verticle.userInteractionEnabled = NO;
您的惰性加载器更改为您的horizontal
财产,_horizontal.userInteractionEnabled = NO;
因为我认为这是一个错字。
回答by Mostafa Aghajani
please use the code like below (replace the 'ViewControllerFilterCategory' with your own one + the nibName) to add the controller from nib (child one) as the child controller of current controller before adding the view as sub view. Then the iOS will call actions attached to the child controller as you expect:
在将视图添加为子视图之前,请使用如下代码(将“ViewControllerFilterCategory”替换为您自己的+笔尖名称)将笔尖(子一)中的控制器添加为当前控制器的子控制器。然后 iOS 将按照您的预期调用附加到子控制器的操作:
let vcCats = ViewControllerFilterCategory(nibName: "ViewControllerFilterCategory", bundle: Bundle.main);
self.addChildViewController(vcCats);
self.view.addSubview(vcCats.view);
P.S. don't forget to call 'removeFromParentViewController' before removing your sub view (like below):
PS 在删除子视图之前不要忘记调用“removeFromParentViewController”(如下所示):
@IBAction func onCanceled(_ sender: Any) {
self.removeFromParentViewController()
self.view.removeFromSuperview()
}
回答by user859375
You have to set isUserInteractionEnabled to true for the view you are trying to add gesture targets.
对于您尝试添加手势目标的视图,您必须将 isUserInteractionEnabled 设置为 true。
Also the user interaction is disabled when animation is on as per documentation of Apple UIView.animate function.
根据 Apple UIView.animate 函数的文档,当动画打开时,用户交互也被禁用。
"During an animation, user interactions are temporarily disabled for the views being animated. (Prior to iOS 5, user interactions are disabled for the entire application.)"
“在动画过程中,正在动画的视图的用户交互被暂时禁用。(在 iOS 5 之前,整个应用程序的用户交互被禁用。)”
So the solution is to run any animation inside DispatchQueue.main.asyncAfter
所以解决方案是在 DispatchQueue.main.asyncAfter 中运行任何动画
Also use this call inside completion block of UIView.animate if you are starting another animation from there
如果您从那里开始另一个动画,也可以在 UIView.animate 的完成块内使用此调用
For example
例如
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.7, options: [.curveEaseInOut, .allowUserInteraction], animations: {
topConstraint.constant = 0
windowView.layoutIfNeeded()
oldNotificationView?.removeFromSuperview()
}, completion: { result in
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
//Its important to run below animation in asyncAfter as otherwise setting delay for 4 seconds seems to change frame such that tap gesture or touchesBegan is not sent for the view. So execting after delay using dispatch queue is right way for touch events to be fired instead of using animate functions delay.
UIView.animate(withDuration: 0.5, delay:0
, options: [.curveEaseOut , .allowUserInteraction], animations: {
topConstraint.constant = -height
windowView.layoutIfNeeded()
} , completion: { result in
notificationView.removeFromSuperview()
self.inAppNotificationView = nil
})
}
})
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.7, options: [.curveEaseInOut, .allowUserInteraction], animations: {
topConstraint.constant = 0
windowView.layoutIfNeeded()
oldNotificationView?.removeFromSuperview()
}, completion: { result in
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
//Its important to run below animation in asyncAfter as otherwise setting delay for 4 seconds seems to change frame such that tap gesture or touchesBegan is not sent for the view. So execting after delay using dispatch queue is right way for touch events to be fired instead of using animate functions delay.
UIView.animate(withDuration: 0.5, delay:0
, options: [.curveEaseOut , .allowUserInteraction], animations: {
topConstraint.constant = -height
windowView.layoutIfNeeded()
} , completion: { result in
notificationView.removeFromSuperview()
self.inAppNotificationView = nil
})
}
})
回答by Daniel Omine
I faced this issue.
我遇到了这个问题。
In my case, i had nib loaded as subview.
就我而言,我将笔尖加载为子视图。
UIViewController *vc = [[[NSClassFromString(@"nib_controller") alloc] initWithNibName:@"nib_name" bundle:nil] autorelease];
[self.view addSubview:vc.view];
Into the nib view (vc.view) all buttons was not being calling the action.
进入笔尖视图(vc.view)所有按钮都没有被调用。
[(UIButton*)[self.view viewWithTag:button_tag] addTarget:self action:@selector(btnActions:) forControlEvents:UIControlEventTouchUpInside];
-(IBAction)btnActions:(id)sender{
// list star buttons for bookmark
NSLog(@"btnActions tag %d", [sender tag]);
// bla bla bla
}
I was able to touch the buttons but the method btnActions
was not being fired.
我能够触摸按钮,但该方法btnActions
没有被触发。
Then, i just tried something really simple and logic.
然后,我只是尝试了一些非常简单和逻辑的东西。
On the parent view controller, i have an method with same name:
在父视图控制器上,我有一个同名的方法:
-(IBAction)btnActions:(id)sender{
// list star buttons for bookmark
NSLog(@"parent btnActions tag %d", [sender tag]);
// bla bla bla
}
I just added the NSLog inside to see what happens. The result appeared on log console:
我只是在里面添加了 NSLog 看看会发生什么。结果出现在日志控制台上:
parent btnActions tag xxx
This was not possible in iOS versions previous do 9.
这在之前 do 9 的 iOS 版本中是不可能的。
But now, its possible to access methods from parent view if the view is loaded from nib controller view.
但是现在,如果视图是从 nib 控制器视图加载的,则可以从父视图访问方法。
For who still confusing, see the bellow illustration
对于谁仍然感到困惑,请参阅下面的插图
parent-> A
child> B
父级-> A
子级> B
----------
| |
| A |
| |
----------
|
|--- -(IBAction)btnActions:(id)sender
----------
| |
| B |
| |
----------
|
|--- -(IBAction)btnActions:(id)sender (the controller have an method with same name as parent)
The B.view is added from A controller
B.view是从A控制器添加的
----------
| |
| A |
| |
----------
|
|--- (touching some button -> execute this:
UIViewController *B = [[[NSClassFromString(@"B_controller") alloc] initWithNibName:@"B_name" bundle:nil] autorelease];
[self.view addSubview:B.view]; // The B.view is added as subview.
The buttons inside B.view send actions to -(IBAction)btnActions
B.view 中的按钮将动作发送到 -(IBAction)btnActions
Sample
样本
[(UIButton*)[self.view viewWithTag:button_tag] addTarget:self action:@selector(btnActions:) forControlEvents:UIControlEventTouchUpInside];
All buttons seems to working well because all them could be touched or clicked (xcode simulator). But the -(IBAction)btnActions
method declared into B.controller
was not being called. I stucked on solve this for many hours until i realize the actions was being sent to the A.Controller
, as described above.
所有按钮似乎都运行良好,因为它们都可以被触摸或点击(xcode 模拟器)。但是没有调用-(IBAction)btnActions
声明为 into的方法B.controller
。我坚持解决这个问题好几个小时,直到我意识到动作被发送到A.Controller
,如上所述。
The headache here is, in the iOS early versions this was not possible.
令人头疼的是,在 iOS 早期版本中这是不可能的。
I'm not sure, but i think from iOS9, we have this different behaviour.
我不确定,但我认为从 iOS9 开始,我们有这种不同的行为。
The app was working well until iOS8.
该应用程序运行良好,直到 iOS8。