I am trying to get my view controller to detect swipes in the UINavigationBar that is automatically displayed by my app, but it refuses to detect swipes. Is there any way I can do it?
Supposing you want to detect swipes to the left in your navigation bar, you could do something like this when you create the navigation controller:
UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(scrollViewSwipedLeft:)];
[swipeLeft setDirection:UISwipeGestureRecognizerDirectionLeft];
[self.navigationController.navigationBar addGestureRecognizer:swipeLeft];
and then create a method like the one below to handle it:
-(void) didSwipedLeft: (UISwipeGestureRecognizer *) gesture {
if (gesture.state != UIGestureRecognizerStateEnded) {
return;
}
//do something
}
OBS: As you navigation controller is a class that will remain alive for several steps of you application life cycle, it is important to pay attention to that and add the gesture recognizer only when you create the navigation controller (which means only add it once) so that you dont keep piling gestures recognizer one over each other, wich will lead not only to a memory leak, but also might make your method didSwipedLeft to be called more than once.
Related
I have a custom UITableViewCell with four UIImageView inside it. I want to detect touch on these imageViews and notify my ViewController (which is containing the UITableView) which ImageView inside which cell has been tapped. How may I do that?
Try this:
-(void)createGestureRecognizers {
for(/*each of the UIImageViews*/) {
UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(handleSingleTap:)];
singleFingerTap.numberOfTapsRequired = 1;
[imageView addGestureRecognizer:singleFingerTap];
imageView.tag = i;
[singleFingerTap release];
}
}
- (void)handleSingleTap:(UIGestureRecognizer *)sender {
UIImageView *imageView = (UIImageView *)sender.view;//this should be your image view
}
There are a couple variants to hit the target. In fact it doesn't matter at all how you are doing it at the cell's level. It may be buttons, image view with tap gesture recognizers or custom drawing and proceeding touch events. I will not provide you with code now as you have a lot of code already given and may find a lot more by little search, thought it may be provided by demand. The real "problem" is in transporting message to the controller. For that purpose I've found only two reasonable solutions. First is the notifications and second is the delegations. Note that the notifications method may lead to visible lag between tap and actual event occurrence as sometimes notifications are brought to objects with little delay...
Hope that it helps.
Use four buttons and set them with different tag values. Then just check the tag value to see which one was pressed.
I'd like to make a button perform different methods, depending on if the user taps or does a long tap.
I've tried:
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(doRewind)];
[uiNextButton addGestureRecognizer:longPress];
[longPress release];
But the app registers my touch only when I touch the button and move the finger a little bit.
What am I doing wrong?
If you are setting both a "normal" tap and a "long" tap gesture, there could be interactions between the two of them.
Have you tried setting the minimumPressDuration property for UILongPressGestureRecognizer?
Also, using requireGestureRecognizerToFail: can be useful to make one of the two gesture handler fire only if the other one did not.
Have a look at the relevant document for those two methods.
If this does not help, please, give more details about your view and all the gesture handlers you are defining.
In my app I have a UIView derived class Canvas that uses touchesBegan: withEvent:, touchesMoved: withEvent:, and touchesEnded: withEvent: to draw in the canvas. I also want to use a swipe to load the previous (or next) canvas in an array. I tried setting up the following gesture (and a similar one for right):
UISwipeGestureRecognizer* leftSwipe = [[UISwipeGestureRecognizer alloc] initWithTarget: self action: #selector(pageFlipNext)];
leftSwipe.direction = UISwipeGestureRecognizerDirectionLeft;
leftSwipe.numberOfTouchesRequired = 2;
[_canvas addGestureRecognizer: leftSwipe];
[leftSwipe release];
But my two fingered swipes are still being treated as one-fingered drawing instructions.
How do I get my app to handle the two-fingered swipe correctly?
First of all, I would get started verifying whether _canvas.multipleTouchEnabled is set to YES. If it isn't, set it to YES.
You might also want to consider
leftSwipe.delaysTouchesBegan = YES;
This will delay the touches to be sent to the _canvas until the gesture fails. You can also use a UIPanGestureRecognizer and do something like this,
[pan requireGestureRecognizerToFail:leftSwipe];
I think that you can use UIPanGestureRecognizer
UIPanGestureRecognizer is a concrete
subclass of UIGestureRecognizer that
looks for panning (dragging) gestures.
The user must be pressing one or more
fingers on a view while they pan it.
I'm drawing a graph on a UIView, which is contained by a UIScrollView so that the user can scroll horizontally to look around the entire graph.
Now I want to zoom the graph when a user pinches in with two fingers, but instead of zooming in a view with the same rate for X and Y direction, I want to zoom only in the X direction by changing the X scale, without changing the Y scale.
I think I have to catch the pinch in/out gesture and redraw the graph, overriding the default zooming behavior.
But is there a way to do this?
I've been having a very difficult time to catch the pinch gesture on the UIScrollView, as it cancels the touches when it starts to scroll. I want the zooming to work even after the UIScrollView cancels the touches. :(
Thanks,
Kura
Although you cannot delete the existing pinch gesture recognizer, you can disable it and then add your own:
// Disable existing recognizer
for (UIGestureRecognizer* recognizer in [_scrollView gestureRecognizers]) {
if ([recognizer isKindOfClass:[UIPinchGestureRecognizer class]]) {
[recognizer setEnabled:NO];
}
}
// Add our own
UIPinchGestureRecognizer* pinchRecognizer =
[[UIPinchGestureRecognizer alloc] initWithTarget:self
action:#selector(pinch:)];
[_scrollView addGestureRecognizer:pinchRecognizer];
[pinchRecognizer release];
Then in
- (void) pinch:(UIPinchGestureRecognizer*)recognizer { .. }
use
[recognizer locationOfTouch:0 inView:..]
[recognizer locationOfTouch:1 inView:..]
to figure out if the user is pinching horizontally or vertically.
You should instead access the gestureRecognizers (defined in UIView), there are several of them being used by the scroll view,
figure out which one is the pinch recognizer and call removeGestureRecognizer: on the scroll view, then create your own and have it do the work, add it back with addGestureRecognizer:.
these are all public API,
the recognizers and what order they are in are not (currently),
so program defensively when accessing them
(this is a perfectly valid way to manipulate UIKit views, and Apple won't/shouldn't have issues with it - though they will not guarantee it works in any future release)
You should be able to subclass UIScrollView and override the touchesBegan: method. Don't call [super touchesBegan:] but instead, adjust the zoom as you like:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
//Anything you want. Probably you would want to store all the touches
//or their values, so that you can compare them to the touches
//in the touchesEnded: method,
//thus letting you know what the pinch amount was
}
If you like, you can judge whether it's a pinch or not, and if it's not, call the super method, and only handle it yourself for custom pinches.
Edsko & bshirley answers are good, but they don't tell where to place the code.
First, I placed it in viewDidLoad method, but no Pinch Gesture Recognizer was found in the scrollview (maybe because my scrollview is an IBOutlet).
Then I tried in viewWillAppear or viewDidAppear and the UIPinchGestureRecognizer was here.
Total nooob here. I'm trying to figure out how to implement a
transition from one UIWebview to another with a swipe and still be able to scroll/zoom w/in each webview.
Each webview should respond normally to all touches/gestures unless a swipe is detected and the boundry of the view/content is at the corresponding edge of the screen (like a paging scroll view).
My content is an html string from a data object.
Any tips would be appreciated. Thanks.
Looks like putting a UIWebview in a UIScrollview works fine in iPhone 3.0 - 'Doh!!!
There may be reasons to put a UIWebView in a ScrollView, but supporting BOTH swipe and scrolling in UIWebView is not one of them. The UIWebView handles scrolling around on the page just fine by itself, and the view controller that owns it can support swipe to change to something else like another controller by doing the following:
1) In the viewController which owns the WebView implement the UIGestureRecognizerDelegate method:
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gr shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGr
{
return YES;
}
This allows the gesture recognizer you implement in your webViewController to ALSO get gestures from the UIWebView. Else the UIWebView consumes all of them and will not pass them on to you.
2) To make a distinction between a Swipes and scrolling around on a page. On the actual gesture recognizer you are adding to the UIWebView set the number of touches required to be called a "Swipe" to something like 2 or 3. This allows one finger scrolling on a page and will only return a SwipeGesture when 2 or 3 fingers are used. Do it something like this:
UISwipeGestureRecognizer *swipeGR;
swipeGR = [[[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeLeft)] autorelease];
swipeGR.direction = UISwipeGestureRecognizerDirectionLeft;
swipeGR.delegate = self;
swipeGR.numberOfTouchesRequired = 2;
[myWebView addGestureRecognizer:swipeGR];