Tap Gesture Recognizer for View but not Sub-View in CustomView - ios

I have created a customViewController to act as a customActionsheet. In this customViewController I have a UIView as the main view (self.view) and an IBOutlet UIView that is the custom action sheet (actionSheetView). What I am trying to do is make this custom action sheet act like a regular actionsheet where if you tap in the dark area, in my case the view with blackColor background and alpha 5.0. This is what I have:
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(slideOut)];
tapGesture.numberOfTapsRequired = 1;
[self.view addGestureRecognizer:tapGesture];
The problem with this is that the subview, the custom action sheet view, also gets the tapgesture so tapping anything on the actionSheetView will get the tap gesture. I have tried a few things like - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch and self.actionSheetView.userInteractionEnabled = NO; but both do not seem to work. Anyone have any idea of how I can make the self.view tappable but disable that gesture for self.actionSheetView? Any tips, guidance, or help is greatly appreciated. Thanks in advance.

I was working on this same style of system. I found it works if you:
Add a new UIView as a subview of the main UIView.
Create another UIView where you want the custom UI (could be a table like an action sheet, a picker, etc). Make sure this shows above the UIView in step 1.
Register the UITapGestureRecognizer on the UIView from step 1.
(Optional) Add extra buttons (e.g. "Cancel" and "Done") and set up a delegate that your custom controller fires.
The main UIView (self.view) should be opague, clear color with alpha of 1. The full subview (see step 1) can be any color (I used light gray color), but adjust the alpha value (0.5 for me).
Unfortunately I can't post an image because I don't have enough rep on the site yet.
If you're using IB and having trouble receiving taps, check under the Attributes Inspector (under the view section) to make sure that "User Interaction" is enabled.

You need to set the delegate
tapGesture.delegate = self.actionSheetView
//actionSheetView.m
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
return NO;
}

Related

Enabling touch event on Objects In a UIScrollview

I've a scrollview that has a UIView on it and on those Views, there's a UIImageView on it, three UILabel on it, I want to enable user Interaction on it, but wouldn't work. I've enabled setUserInteraction for both the UIView, UIScrollView, UILabels, UIImageView none is Responding to click actions at all. The layout look like the Image Below....
implement
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
so the gestures of the uiscroll view won't conflict with the subview's recognisers
basically what happens is that the UIScrollView won't pass the events to its subviews because the default of the above method is to return NO
This sounds too easy to be the problem, but I've made the following mistake: Everything is set just right, but I did not drag out one of the SentEvents like TouchUpInside to an action in the implementation.
check this way,
1> first check whether your view controller respond to UIGestureRecognizerDelegate this way
#interface RootViewController : UIViewController<UIGestureRecognizerDelegate>
2> then in design check you map scrollview property and delegate properly
3> apply this code in viewDidload
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapditected)];
tapGesture.delegate = self;
// prevents the scroll view from swallowing up the touch event of child buttons
tapGesture.cancelsTouchesInView = NO;
[self.scroller addGestureRecognizer:tapGesture];
4> check you apply this code
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
5> if all goes wll then this method should detected
-(void)tapditected{
}

UITableview scrollsToTop pressing UINavigationbar

I have a UIView with a UINavigationBar, a UITabBar and a UITableView.
When i press the status bar the UITableView scrolls to top because i have it set to TRUE.
I want to be able to do the same, by pressing the UINavigationBar like it happens in some apps. Setting the UITableView to scrollsToTop = TRUE only works if the user presses the StatusBar.
Method 1:
How about adding a TapGestureRecogniser on your UINavigationBar? This will only work if you dont have any buttons on your navigationBar.
//Create a tap gesture with the method to call when tap gesture has been detected
UITapGestureRecognizer* tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(navBarClicked):];
//isolate tap to only the navigation bar
[self.navigationController.navigationBar addGestureRecognizer:tapRecognizer];
//same method name used when setting the tapGesure's selector
-(void)navBarClicked:(UIGestureRecognizer*)recognizer{
//add code to scroll your tableView to the top.
}
and that's about it really.
Some people have found that their back button stops working when adding a tap gesture to the navigation bar, so you can do one of two things:
Method 2: Set the user interaction enabled to yes and set the tap gesture recogniser like shown in method 2 in detail.
Method 3: Use a UIGestureRecognizerDelegate method called gestureRecognizer:shouldReceiveTouch and make it return NO when the touch's view is a button, otherwise return YES. See method 3 in detail.
Method 2 from point 1: - feels dirty/hackish
[[self.navigationController.navigationBar.subviews objectAtIndex:1] setUserInteractionEnabled:YES];
[[self.navigationController.navigationBar.subviews objectAtIndex:1] addGestureRecognizer:tapRecognizer];
Method 3 from point 2: - a lot better, the right way
implement the UIGestureRecognizerDelegate protocol in your .h file, and in your .m file add the following:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
// Disallow recognition of tap gestures when a navigation Item is tapped
if ((touch.view == backbutton)) {//your back button/left button/whatever buttons you have
return NO;
}
return YES;
}

How do I ignore the tap if the user tapped on a UIBarButtonItem?

For some reason my UITapGestureRecognizer is blocking my toolbar buttons from being pressed when the recognizer is added to self.view and I don't want it to. In shouldReceiveTouch I want to return NO if the item is the toolbar button.
How do I do this, however? The items aren't UIBarButtonItems apparently, because when I put an if statement to check if touch.view is of that class, it ignores it. If I put a breakpoint there and inspect touch.view its class is UIToolbarTextButton. But [UIToolbarTextButton class] I get a "use of undeclared identifier UIToolbarTextButton" error.
Can I say if it's a subview of UIToolBar? What should I do?
Without any code, this is a hard question to answer... However it sounds like you are adding the Tapgesture recognizer to the same view as your toolbar... You could check the coordinates to see if they are within the CGrect of the uitoolbar... but really what I would recommend is creating a view which contains 2 subviews: one is your toolbar, the other is the main part of your view... then add the tapGesture only to the mainView. Good luck
The better solution is not to add the UITapGestureRecognizer to the self.view.
Add a new view with Interface Builder that covers all the area but the toolbar area.
Put all your controls inside it and add the tap gesture to it.
Alternative: Add this to your ViewDidLoad function or somewhere you find more appropriate.
for (UIView *v in [toolbar items])
{
v.tag = 5; // tag tool bar items
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if (touch.view.tag == 5)
return NO;
return YES;
}

Enlarge UIButton's hitest area for button with background image, imageView and label in it

It may seem like duplicate, but I can't actually find any good answer to my concrete situation.
I have some button with background image (1pt-wide, streched), icon-like image inside along with the text label. It's height is 33pt, I need to make it's hittest area 44pt-high.
I saw two solutions, but neither of them works for me.
First solution is to enlarge frame and adjust image so it would have some padding. But that is not acceptable for me, because I have both background image and image inside the button.
Second solution is to subclass UIButton (which is absolutely acceptable) and override - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event. I did that, when I put some breakpoints in this method and tried to tap in desired area nothing happened (breakpoints worked when tapped inside the button frame).
Are there any other solutions? What could be possibly wrong with the second solution?
If you create the view programmatically, you can instantiate a UIView that is 44px high, add a tap gesture recognizer to it, and add your UIButton as a subview inside this view:
CGRect bigFrame = CGRectMake(0,0,100,44);
UIView *big = [[UIView alloc] initWithFrame:bigFrame];
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(doPress)];
[big addGestureRecognizer:tapRecognizer];
UIButton *yourButton = ...
[big addSubview:yourButton];
[self.view addSubview:big];
Then implement the selector as:
- (void)doPress {
[yourButton sendActionsForControlEvents:UIControlEventTouchUpInside];
}
In that way, the outer view taps will be interpreted as button presses for your button.

Gesture recognition with UIWebView

I have set up some gesture recognition in an app that I'm building. One of the gestures is a single finger single tap, which hides the toolbar at the top of the screen. Works great except for one thing: a tap on a link causes the toolbar to go away, too.
Is it possible to detect a tap that was not a tap on a link? Could I do this by seeing where the tap occurred, and only take action if it didn't occur on an html link? Is this is possible, a pointer to how to determine if a link was tapped would be helpful.
Per Octys suggestion, I did attempt to wrap the UIWebView inside a UIView. I'm using interface builder, so I inserted a view in the hierarchy, and made the UIWebView a "child" of the new UIView. The hierarchy looks like this now:
I added an IBOutlet for the view in my view controller, and linked it up in interface builder.
I changed the gesture recognizer setup to look like this:
UITapGestureRecognizer* singleTap=[[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(handleSingleTap:)];
singleTap.numberOfTouchesRequired=1;
singleTap.delegate=self;
[self.UIWebViewContainer addGestureRecognizer:singleTap];
[singleTap release];
This code resides in viewDidLoad.
As before, the code correctly sees a single finger single tap, but a tap on a link in the UIWebView also causes the toolbar to go away. I only want the toolbar to go away if a link was NOT tapped.
Anyone have any suggestions?
Thank you.
Chris
Thanks
Chris
Try wrapping your UIWebView in a UIView container and set your gesture recognizers on the container view. Touch events that are not handled by the UIWebView will be passed up the view hierarchy and be intercepted by your container view, assuming it implements the appropriate handlers (and it is these handlers that should implement the code for hiding the toolbars...).
OK, so one "hack-ish" workaround is to make the view controller which houses the UIWebView a delegate of the gesture recognizer that you instantiate(UIGestureRecognizerDelegate) I am usually not a fan of solutions like this one, but...
Assign the gesture recognizer to the view that wraps you web view, and set it's delegate to self.
then in the delegate method gestureRecognizer:shouldRecieveTouch method, set the state to indicate the there was a tap event,
Return NO from the delegate method so the event propagates down the responder chain to the UIWebView.
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
_userTapped = YES;
[self performSelectorOnMainThread:#selector(hideMenuIfNotLink) afterDelay:??.?];
//??.?? amount of time to lapse to see if shouldStartLoadWithRequest gets called.
return NO;
}
-(void)hideMenuIfNotLink{
if(_userTapped)
//hideMenu
}
Now, in your UIWebViewDelegate shouldStartLoadWithRequest (which gets called when a user has in fact clicked a link)
if(_userTapped){
_userTapped = NO;
//possibly code to reshow or verify keep showing menu
}
You can use the UIWebViewDelegate protocol's -webView:​shouldStartLoadWithRequest:​navigationType: method.
If the navigationType is UIWebViewNavigationTypeLinkClicked, you can get the URL for the click by checking [request URL].
I've been looking for the same thing and found this: There is an iOS specific property that disables the callout when you hold your finger on a link. You add this into the styling (CSS) of your urls.
-webkit-touch-callout: none;
This worked for me.try adding the below line of code
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
I was having the same problem. This solution worked for me:
1) make sure to add the protocol to your interface: UIGestureRecognizerDelegate
for example:
#interface ViewController : UIViewController _SlideViewProtocol, UIGestureRecognizerDelegate_
2) add this line of code
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
}
3)
UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(nextSlide)];
swipeGesture.numberOfTouchesRequired = 1;
swipeGesture.direction = (UISwipeGestureRecognizerDirectionLeft);
swipeGesture.cancelsTouchesInView = YES;
[swipeGesture setDelegate:self];
[self.view addGestureRecognizer:swipeGesture];

Resources