UIButton with two state - touch and long touch - iphone

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.

Related

How to detect touch inside an UITableViewCell

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.

How do I display a pop-up menu when a user touches content within a Quartz-drawn PDF?

I created an iPhone PDF viewer using Quartz that also has a page-flip animation. This works well, but now I'd like to add some more interactive functionality.
In particular, I'd like to add the ability to pop up a menu when the user touches some part of the PDF content. How can I make my PDF display respond to touch events over certain parts of the displayed PDF material?
It's pretty easy. Just add a UIGestureRecognizer to your scrollview.
You may wanna make some calculations to get the correct touch point relative to the pdf.
I've written an pdf iOS framework that does exactly that, you may wanna check it out. There I create the tap recognizers in the ScrollView's init method:
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTapped:)];
singleTap.numberOfTapsRequired = 1;
[singleTap requireGestureRecognizerToFail:doubleTap];
[self addGestureRecognizer:singleTap];
[singleTap release];
(Note that I added here the "requireGestureRecognizerToFail:doubleTap" because I also respond to double and tripple taps for zomming)

Two fingered swipe v. one fingered drag in iOS

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.

UILongPressGestureRecognizer recognize only when moving my finger

i try to use UILongPressGestureRecognizer in my App and the problem is that this function call only when i move my finger a little bit.
this is the code i am using :
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(doRewind)];
[uiNextButton addGestureRecognizer:longPress];
I know I am late to answer this question, but I think this might help someone.
I was having the same problem. I needed to fire the event and move to the next screen without moving or touching up my screen. As the gesture recognizer has different states:
UIGestureRecognizerStateBegan and UIGestureRecognizerStateEnded
I was using UIGestureRecognizerStateEnded and that was creating the problem, because it first checks if the state has begun and the event was not firing without moving my finger.
So I replaced my UIGestureRecognizerStateEnded state with
UIGestureRecognizerStateBegan and everything worked fine.
Now you don't need to move your finger away. Just touch hold and everything work fine.
if (gesture.state == UIGestureRecognizerStateBegan) {
// Do your stuff
}
Thats the correct way, other ways like numberOfTapsRequired, allowableMovement are meant for different purposes.
Your UILongPressGestureRecognizer has been created with the bare minimum of configuration information. At a minimum you should look into setting these properties:
minimumPressDuration
allowableMovement
And in special cases you can also set:
numberOfTouchesRequired
numberOfTapsRequired
In your case I think you want to set the allowableMovement to 0, the default value is 10 (pixels). You can read more from the class reference I linked.
When adding the UILongPressGestureRecognizer, you also need to set the interval for which you want the user to hold. You can do this with the following line of code:
[longPress setMinimumPressDuration:2];

Custom actions for UIGestureRecognizers (with custom parameters)

Short version of my problem:
I cannot figure out how to make the "action" for my UITapGestureRecognizer take additional parameters, and actually use them.
Here's the rundown of my problem:
I am trying to make it so that my iPad app records (with NSLog) the coordinates of the UITouch that occurs whenever they press one of my app's UIButtons. The location of the touch needs to be relative to the button that was touched.
What I've done:
I have implemented a UITapGestureRecognizer and added it to each of my buttons. My problem is with the action to use, since it needs to be dynamic for each and every button.
I currently have this code:
UITapGestureRecognizer *iconClickRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(logIcon:withTag:)];
[iconClickRecognizer setNumberOfTapsRequired:1];
[iconClickRecognizer setNumberOfTouchesRequired:1];
[iconClickRecognizer setDelegate:self];
[[self.view viewWithTag:1] addGestureRecognizer:iconClickRecognizer];
[iconClickRecognizer release];
When I know that this works, I will use a for-loop to add the iconClickRecognizer to all of the buttons by their tag.
The logIcon:(int)withTag method is shown here:
-(void)logIcon:(UIGestureRecognizer *)gestureRecognizer withTag:(int)tag {
NSLog(#"tag X: %f", [gestureRecognizer locationInView:(UIView*)[self.view viewWithTag:tag]].x);
NSLog(#"tag Y: %f", [gestureRecognizer locationInView:(UIView*)[self.view viewWithTag:tag]].y);
}
What isn't working:
When I hard-code a tag into logIcon method, it records the information correctly. However, I do not know how to make this method dynamic, and actually use the "tag" parameter.
Any help would be greatly appreciated.
Thanks,
Alex
The issue is that you can only get one argument from target / action style registration, that is the sender (in this case the gesture recognizer itself). You're not able to pass arbitrary contexts. But you could, in your action, check the recognizer's view property and examine that view's tag.
The docs for UIGestureRecognizer class specify that the action must be of the form:
- (void)handleGesture;
- (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer;
not your form of:
- (void)logIcon:(UIGestureRecognizer *)gestureRecognizer withTag:(int)tag
So you could ask the gestureRecognizer where it is on the whole window, then compare to your buttons, or you could walk through your buttons and ask the gesture where it is with respect to each button.
Probably best would be to subclass UIButton and make each button itself the target; then you know exactly what view you're in.