Reputation: 626
I have a problem with a UIButton that works perfectly well in iOS6, but fails to respond to touch events in iOS7 up to a certain point. To clarify please see below image:
The button that fails is the "Discard All" button that is in the UIView. (Please note, this button is only disabled temporarily and that is NOT the issue. I just don't have a screenshot of the newest test where the button is enabled")
This button ignores all touches, unless one first presses the "Discard" or "Retry" buttons in the UITableViewCell. (This does cause a reload of the view controller, which triggers the lifecycle methods like ViewDidLoad to be called again.) After either the "Discard" or "Retry" buttons in the table view cell have been pressed, the "Discard All" button starts functioning correctly.
The view and the "Discard All" button are build on the Controller's XIB file and not in code. This only fails on iOS7, and starts working as soon as the taleview cell buttons are touched.
Anyone have any ideas?
Thanks!
Upvotes: 8
Views: 14694
Reputation: 5073
I have just faced to this problem. According to @Guntis Treulands advice, I decided to check what happens if I override hitTest:withEvent:
method in my custom header view. This method ignores view objects that are hidden, that have disabled user interactions, or have an alpha level less than 0.01. This method does not take the view’s content into account when determining a hit. Thus, a view can still be returned even if the specified point is in a transparent portion of that view’s content and now, after it has been overridden, receives touches outside the bounds. It did the trick for me. Hope it helps you, guys.
swift
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
guard !isHidden, alpha > 0 else {
return super.hitTest(point, with: event)
}
for subview in subviews {
let subpoint = subview.convert(point, from: self)
let result = subview.hitTest(subpoint, with: event)
if result != nil {
return result
}
}
return super.hitTest(point, with: event)
}
Objective-C
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
if (!self.clipsToBounds && !self.hidden && self.alpha > 0) {
for (UIView *subview in self.subviews.reverseObjectEnumerator) {
CGPoint subPoint = [subview convertPoint:point fromView:self];
UIView *result = [subview hitTest:subPoint withEvent:event];
if (result != nil) {
return result;
}
}
}
// use this to pass the 'touch' onward in case no subviews trigger the touch
return [super hitTest:point withEvent:event];
}
Upvotes: 7
Reputation: 1960
I also got same problem but after adding below code button actions working properly cell.contentView.userInteractionEnabled = NO;
Upvotes: 1
Reputation: 1
Okay, so seems like buttons programatically created in iOS7 won't call their target. I don't know why, but I've found the following solution:
In the InterFace Builder (or nib) add a button and customize and HIDE it. ( theButtonInTheNib
);
Make it IBOutlet property: @property (strong) IBOutlet UIButton *theButtonInTheNib
Make the target IBAction connection: (IBAction)theTargetAction:(id)sender;
Here comes the trick. We will make a copy/or copies of this button:
NSData *archivedData = [NSKeyedArchiver archivedDataWithRootObject:theButtonInTheNib];
UIButton *theCopyButton = [NSKeyedUnarchiver unarchiveObjectWithData:archivedData];
[theCopyButton setHidden:NO];
[theCopyButton setFrame:CGRectMake(x, y, width, height)];
[theCopyButton addTarget:self action:@selector(theTargetAction:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:theCopyButton];
I have added again the target action, but any other action will work.
Upvotes: -1
Reputation: 1770
I had this same issue - buttons did work on iOS6 and didn't on iOS7, problem was with Container UIView
to which one I was adding UIButtons
, I add constrains to container UIView
and it started working. Code that I had to add in my case:
[superView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V: [_controllersView]-|" options:0 metrics:nil views:views]];
[superView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_controllersView(70)]" options:0 metrics:nil views:views]];
[superView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_controllersView]|" options:0 metrics:nil views:views]];
Upvotes: 1
Reputation: 3076
If it's using auto layout, then try adding a log statement in -viewDidAppear:
NSLog(@"Height of UIView: %f", self.<name of UIView>.frame.size.height);
if the result is 0 (or not large enough), then set the height of UIView large than the height of 'Discard All' button.
Upvotes: 0
Reputation: 33
This is weird but I was developing a new app for iOS 7 and setting [cell.contentView setUserInteractionEnabled: YES];
actually worked for me.
Upvotes: 1
Reputation: 4762
Just as an alternative answer - Actually for me, this has never worked (if uibutton is outside it's parent view, then it will not receive touch.) - But in some cases, it is required to have the button outside it's boundaries.
For that reason, there is a hittest function, which can be overridden - to simply check parent view all subviews to find uibutton that is placed outside parent views boundaries. (You would then check each subview, if it is uibutton type, and if touched coordinates are inside uibuttons frame.
By default hittest function skips checking views, that are outside boundaries.
Hittest example: https://stackoverflow.com/questions/17246488/best-way-to-perform-the-hit-test-objective-c .
Upvotes: 2
Reputation: 3702
Not sure if this is the same case, but it might be related:
When the UIButton is in a view with a UIGestureRecognizer which did NOT set delaysTouchesEnded to NO (default is YES), the button won't get TouchUpInside events anymore in iOS 7. It DID get the TouchUpInside events in iOS 6.
If possible, set the delaysTouchesEnded property of the UIGestureRecognizer to NO to solve the problem.
Upvotes: 1
Reputation: 626
I found the solution last night. Okay, so what happens is that I put the above table view and UIView elements onto a target frame.
I'm not 100% sure, but it seems that in iOS6 the buttons respond to events irrespective of where they are placed. For some reason in iOS7 when the button sits outside of the frame it is supposed to be in, it ignores touch events, even though it does get displayed.
I solved the problem by positioning the view's frame in the correct place so it overlays the button.
If I can find any documentation around this, I will post here.
Thanks!
Upvotes: 17