Interactive Pop Gesture Recognizer blocking button touchupinside event in custom uitableviewcell - ios

I have a UITableViewController that is pushed from a RootViewController. In the UITableView for the UITableViewController, I'm using a custom cell which has a button at the left with frame: CGRectMake(0,0,30,30).
It seems like when I set self.navigationController.interactivePopGestureRecognizer.enabled = NO; in the UITableViewController, the touch events for the button are received, but if I set it to enabled = YES, the touch events on the button are lost:
Here's my code for creating the button inside the custom tableviewcell.
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(0,0,30,30);
[button addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:button];
Any thoughts/suggestions on how I can fix this would be appreciated!
Thanks.

Set the cancelsTouchesInView property on the gesture recognizer to NO. The default is YES, which means the view to which it's attached won't get to also handle the touches.

Related

Having a UIButton be tapped in a UICollectionViewCell

I have a UICollectionView with its cells all laid out.
I have this declared as a subview:
#property (nonatomic, strong) UIButton *aButton;
I then have that declared in each cell like so:
if (_aButton == nil)
{
_aButton = [UIButton buttonWithType:UIButtonTypeSystem];
}
// Add in all _aButton info here
[self.contentView addSubview:_aButton];
// Call to button pressed for button
[_aButton addTarget:self action:#selector(aButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
The button click method is like so:
- (IBAction) aButtonPressed:(UIButton *) sender
{
// Code never gets heree
}
The if(_aButton== `nil) is needed since cells get reused.
How do I make this work now? Thanks.
Add button action code before button added to view.... May be it will work .
// Call to button pressed for button
[_aButton addTarget:self action:#selector(aButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
// Add in all _aButton info here
[self.contentView addSubview:_aButton];
I think, the way you are initializing the button is going to give you frame as 0,0,0,0 . So first give it a proper frame and title to be visible on the screen.
Then try tapping on that title and see if it works or not.
It's unclear what you trying to achieve here, but the button is not working because you not setting it's position and size on the cell. It could be done by setting frame or layout constraints.
Try to set button frame:
_aButton.frame = CGRectMake(0.0f, 0.0f, 50.0f, 50.0f);
You can also set background color for the button, just to make it visible on the cell:
_aButton.backgroundColor = [UIColor redColor];
Everything else is correct, button should work.

iOS gestureRecognizer not handled subviews

i have the following problem: in my iphone app i have a UIView that holds 0 to several subviews. Those subviews may overflow the parent and therefore be hidden and all of them are UIButtons. I added a UISwipeGestureRecognizer to the UIView to move the buttons around which works great. However it only works when the gesture is done on background, the UIButtons interfere with the gesture recognizer.
How i can i pass the gesture through? Btw. i still need the tap of the Buttons.
Thanks!
EDIT:
I tried to add the gesture recognizer to the UIButtons too, but it is not triggered... Although performing the swipe gesture prevents the UIButton from going to highlighted state it doesn't trigger the gesture. I added setDelaysTouchesBegan:YES as suggested in UIButton and Swipe Gesture. That's how i do it right now:
UIButton *breadcrumb = [UIButton buttonWithType:UIButtonTypeCustom];
[breadcrumb setImage:[UIImage imageNamed:#"Next"] forState:UIControlStateNormal];
[breadcrumb setTitle:title forState:UIControlStateNormal];
[breadcrumb.titleLabel setFont:[UIFont systemFontOfSize:12.0f]];
[breadcrumb sizeToFit];
[breadcrumb setTag:level];
UISwipeGestureRecognizer *gr = [[UISwipeGestureRecognizer alloc] init];
[gr setDelegate:self];
[gr setDirection:UISwipeGestureRecognizerDirectionRight];
[gr setDelaysTouchesBegan:YES];
[self.tableView addGestureRecognizer:gr];
[breadcrumb addGestureRecognizer:gr];
EDIT 2:
I have now subclassed UIButton and initilizing it now like so: [BreadcrumbButton buttonWithType:UIButtonTypeCustom]. In the initializer i added the button itsself as a listener to all touch events [self addTarget:self action:#selector(eventReceiver:) forControlEvents:UIControlEventAllTouchEvents]; to inspect whats going on.
- (void)eventReceiver:(UIButton *)btn {
NSLog(#"Reveived event: %# ---------------", btn);
for(UIGestureRecognizer *gr in ev.gestureRecognizers) {
NSLog(#"Gesture: %#", gr);
}
}
What i see is that a) the button has just one gesture recognizer added and b) that this UISwipeGestureRecognizer jumps to state Possible during swipe but does not forward to its delegate methods.
You would have to subclass the UIButton and over ride the tap delegate callback and forward this call to whatever is handling a UISwipeGestureRecognizer. Unless you add the gesture recognizer on the UIButton, it will always call it's touch handler before the view behind it. You can also explicitly tell the button to not handle it's touch events thus passing the touch event down the chain (via userInteractionEnabled), but as you've already stated you do not want this. The best way to go about this would be by creating a subclass of UIButton and handling the touch events there and/or forwarding the events using delegation. Pressing the button is a touch event, so you may just want to add a tap gesture recognizer to the button and call the IBAction from that and then have the swipegesturerecognizer forward a delegate call.

Dismiss Keyboard

So I have a self created top bar controller that is being implemented in my other controllers views. I have a textfield on this top bar. I was wondering what the best approach to having the keyboard dismiss if the user clicks anywere outside the keyboard. I do have a tap gesture recognizer that performs the method dismisskeyboard. However, this only works if the user clicks on the top bar outside the keyboard. Is there a way to set it up so if the user clicks anywere on the screen, then this will dismiss the keyboard?
The approach I would describe is a hack but still works.
create a transparent UIButton with the frame of the view, like below:
UIButton* overlay = [UIButton buttonWithType:UIButtonTypeCustom];
overlay.frame = self.view.bounds;
overlay.backgroundColor = [UIColor clearColor];
[overlay addTarget:self action:#selector(hideOverlay:) forControlEvents:UIControlEventTouchDown];
[self.view.subviews[0] insertSubview:overlay belowSubview:self.textField];
Create a method hideOverlay to dismiss the keyboard and hide the transparent:
-(void)hideOverlay:(id)sender {
UIView* overlay = sender;
[overlay removeFromSuperview];
[self.textField resignFirstResponder];
}
You should ideally call the first block of code in textFieldDidBeginEditing: protocol method of UITextFieldDelegate and you should register your calling class accordingly.
You might try giving the text field a transparent inputAccessoryView, sized to fill the rest of the screen, that catches taps and dismisses the keyboard.

Programmatically adding a view with a button

I want to add a view and a button programmatically like follows.
The problem is that the button does not react on clicking. I mean neither does it get highlighted or calls the selector.
The reason is that I want to implement a list row for a recording (a sound file). The list row should be selectable for drill-down and have a play button. So I got a RecordingView subclassing UIView that itself adds the button using a target from the constructor. See code below.
If anyone has a better approach to do this that could also be a solution.
#implementation MyViewController
- (IBAction) myAction {
RecordingView *recordingView = [[RecordingView alloc] initWithFrame:CGRectMake(30, 400, 130, 50)withTarget:self];
[recordingView setUserInteractionEnabled:YES];
[[self view] addSubview:recordingView];
}
#implementation RecordingView
- (id)initWithFrame:(CGRect)frame withTarget:(id) target
{
self = [super initWithFrame:frame];
UIButton *playButton = [[UIButton alloc] initWithFrame:CGRectMake(185, 5, 80, 40)];
[playButton setTitle:#"Play" forState:UIControlStateNormal];
[playButton setTitleColor:[UIColor darkTextColor]forState:UIControlStateNormal];
// creating images here ...
[playButton setBackgroundImage:imGray forState: UIControlStateNormal];
[playButton setBackgroundImage:imRed forState: UIControlStateHighlighted];
[playButton setEnabled:YES];
[playButton setUserInteractionEnabled:YES];
[playButton addTarget: target
action: #selector(buttonClicked:)
forControlEvents: UIControlEventTouchDown];
[self addSubview:playButton];
return self;
}
When I add the button the same way, directly in the view controller .m-file, the button does react on clicking. So there is something about the RecordingView. What do I need to do different here?
Also, are there any better ways to provide the target and selector for the touch event?
You may simply need to set userInteractionEnabled to YES on your RecordingView.
Another problem is that you are creating the RecordingView with a frame width of 130, but you are setting the X-axis origin of playButton to 185. This means playButton is entirely outside of the bounds of its superview. The default value for clipsToBounds is NO, so the button is drawn anyway. But touch events will never reach the button, because they are rejected when the system hit-tests the RecordingView.
This is from the hitTest:withEvent: documentation in UIView Class Reference:
Points that lie outside the receiver’s bounds are never reported as hits, even if they actually lie within one of the receiver’s subviews. This can occur if the current view’s clipsToBounds property is set to NO and the affected subview extends beyond the view’s bounds.
You need to either make RecordingView's frame wider, or move playButton to be inside the bounds of its superview.

exclusiveTouch in subviews added to UITableViewCell

I'm trying to ignore touches for a certain subviews added to my custom UITableViewCell subclass. I set exclusiveTouch to YES for that subview but the touches still trigger the cell selection.
Is there a way to avoid that selection just when touches are in that subiew?
Thanks
In my experience, #Ali3n's solution doesn't work (i.e. using view.userInteractionEnabled = NO). When you tap on the view, the cell is still selected.
However, I've found that if you add a UIButton as a subview, and add your subviews to that then it does work as you'd expect - i.e. you tap on the area covered by the button and the cell is not selected.
If you use a custom style UIButton then it doesn't look any different to a plain UIView anyway.
Here's how I add a UISwitch to the accessoryView with a non-tappable UIButton behind it. If you miss the button and hit the background the cell is not selected.
UIButton* button =[UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(0, 0, 100, 67);
self.accessoryView = button;
self.accessoryView.backgroundColor = [UIColor grayColor];
UISwitch* statusSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(0, 20, 80, 40)];
[self.accessoryView addSubview:statusSwitch];
you can disable user interation on those views using userInteractionEnabled property of UIView
Like :--
view.userInteractionEnabled = NO;

Resources