im trying to send a parameter from my touchesEnded handler like so...
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint currentPosition = [touch locationInView:self.view];
CGFloat deltaX = fabsf(gestureStartPoint.x - currentPosition.x);
CGFloat deltaY = fabsf(gestureStartPoint.y - currentPosition.y);
if (deltaX >= 0.3 && deltaY <= 100) { //horizontal swipe detected
[self performSelector:#selector(refreshCover:)
withObject:nil afterDelay:0];
if (gestureStartPoint.x < currentPosition.x) { //swipe right
[self refreshCover:#"backward"];
NSLog(#"swipe backward");
} else { //swipe left
[self refreshCover:#"forward"];
NSLog(#"swipe forward");
}
}
}
then in refreshCover, i just have :
- (void)refreshCover:(NSString*)direction {
NSLog(#"direction: %#", direction);
}
when a user swipes, refreshCover is called, but the direction parameter is not getting passed. if i call [self refreshCover:#"forward"] from anywhere else, the parameter is passed without problems.
any ideas? thanks in advance.
The problem is with this code
[self performSelector:#selector(refreshCover:)
withObject:nil afterDelay:0];
The performSelector will call the function. I think this code is not needed since you are calling the function individually
Related
I am using MHRotaryKnob to make Rotary dial like animation. I am using it for making old telephone dial pad.. At present it is just showing animation when i dial the pad it just come back with animation. even the first circle from lower not even getting touch detected and touch is working there also where there is no circle to dial. Below i am posting the code i am using.
- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint point = [touch locationInView:self];
if (self.interactionStyle == MHRotaryKnobInteractionStyleRotating)
{
// If the touch is too close to the center, we can't calculate a decent
// angle and the knob becomes too jumpy.
if ([self squaredDistanceToCenter:point] < MinDistanceSquared)
return NO;
// Calculate starting angle between touch and center of control.
_angle = [self angleBetweenCenterAndPoint:point];
}
else
{
_touchOrigin = point;
_angle = [self angleForValue:self.value];
}
self.highlighted = YES;
[self showHighlighedKnobImage];
_canReset = NO;
return YES;
}
- (BOOL)handleTouch:(UITouch *)touch
{
if (touch.tapCount > 1 && self.resetsToDefault && _canReset)
{
[self setValue:self.defaultValue animated:YES];
return NO;
}
CGPoint point = [touch locationInView:self];
if (self.interactionStyle == MHRotaryKnobInteractionStyleRotating)
{
if ([self squaredDistanceToCenter:point] < MinDistanceSquared)
return NO;
// Calculate how much the angle has changed since the last event.
float newAngle = [self angleBetweenCenterAndPoint:point];
float delta = newAngle - _angle;
_angle = newAngle;
// We don't want the knob to jump from minimum to maximum or vice versa
// so disallow huge changes.
if (fabsf(delta) > 45.0f)
return NO;
self.value += (self.maximumValue - self.minimumValue) * delta / (MaxAngle*2.0f);
// Note that the above is equivalent to:
//self.value += [self valueForAngle:newAngle] - [self valueForAngle:angle];
}
else
{
self.value = [self valueForPosition:point];
}
return YES;
}
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
if ([self handleTouch:touch] && self.continuous)
[self sendActionsForControlEvents:UIControlEventValueChanged];
return YES;
}
- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
self.highlighted = NO;
[self showNormalKnobImage];
// You can only reset the knob's position if you immediately stop dragging
// the knob after double-tapping it, i.e. when tracking ends.
_canReset = YES;
[self handleTouch:touch];
[self sendActionsForControlEvents:UIControlEventValueChanged];
[self setValue:self.defaultValue animated:YES];
}
I am trying to achieve that which circle is selected to dial that can be detected and only circles can be used to dial not outside the circles. Thanks in advance, any sort of help is appreciated.
I was wondering how to pass on a tap on an UIView to an UITextView. This is my code so far:
- (void)foundTap:(UITapGestureRecognizer *)recognizer {
label.text = #"Touch detected";
[self.view bringSubviewToFront:aTextView];
[aTextView touchesBegan:touches withEvent:event];
}
Now, this obviously does not work as touches and event are not defined. But how do I define them? I can't declare touches as 1 (won't work). I could initialise it like so:
UITouch *touches =[touches anyObject];
But then again, touches is still undeclared. And I have no idea of how to declare the event. This is usually easy if you use the - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {} method, but I want to pass on the tap not the touches. Any help would be very much appreciated.
Edit:
I rewrote the method, but I still can't pass on the tap to the UITextView. I now need to double tap in order to edit it, i.e. the first tap for bringing the aTextView upfront and the second tap will then edit the UITextView (as it is in front and thus receives all the touches swipes etc.):
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesMoved:touches withEvent:event];
UITouch *touch = [touches anyObject];
CGPoint currentPosition = [touch locationInView:self.view];
CGFloat deltaX = fabsf(gestureStartPoint.x - currentPosition.x); // will always be positive
CGFloat deltaY = fabsf(gestureStartPoint.y - currentPosition.y); // will always be positive
if (deltaY == 0 && deltaX == 0) {
label.text = #"Touch"; [self performSelector:#selector(eraseText) withObject:nil afterDelay:2];
[self.view bringSubviewToFront:aTextView];
[self.view bringSubviewToFront:doneEdit];
[aTextView touchesBegan:touches withEvent:event];
}
}
See if this previous SO question iPhone: Detecting Tap in MKMapView helps you.
I was wondering if there is an easy method to set the minimum swipe length, i.e. the length in pixel the user needs to swipe so that the gesture is recognised as a swipe.
I noticed that the normal swipe can be quite unresponsive (as compared to swiping photos in your photo library for instance).
This is the normal way, but I would like to reduce the required length of the swipe:
- (void)viewDidLoad
{
// SWIPING GESTURES:
UISwipeGestureRecognizer *swipeLeftRecognizer;
swipeLeftRecognizer=[[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(foundLeftSwipe:)];
swipeLeftRecognizer.direction=UISwipeGestureRecognizerDirectionLeft;
//swipeRecognizer.numberOfTouchesRequired=1;
[self.view addGestureRecognizer:swipeLeftRecognizer];
[swipeLeftRecognizer release];
UISwipeGestureRecognizer *swipeRightRecognizer;
swipeRightRecognizer=[[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(foundRightSwipe:)];
swipeRightRecognizer.direction=UISwipeGestureRecognizerDirectionRight;
//swipeRecognizer.numberOfTouchesRequired=1;
[self.view addGestureRecognizer:swipeRightRecognizer];
[swipeRightRecognizer release];
[super viewDidLoad];
}
#pragma mark -
#pragma mark Swipes
- (void)foundLeftSwipe:(UISwipeGestureRecognizer *)recognizer {
// do something
}
- (void)foundRightSwipe:(UISwipeGestureRecognizer *)recognizer {
// do something
}
I remember that there is a way to get the pixel start position and end position and then compare the two, but was just wondering if there is a simpler method, i.e. by simply defining a value for the minimum required swipe length in the code I have here.
EDIT:
This is how I recoded the whole thing:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
gestureStartPoint = [touch locationInView:self.view];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint currentPosition = [touch locationInView:self.view];
CGFloat deltaXX = (gestureStartPoint.x - currentPosition.x); // positive = left, negative = right
CGFloat deltaYY = (gestureStartPoint.y - currentPosition.y); // positive = up, negative = down
CGFloat deltaX = fabsf(gestureStartPoint.x - currentPosition.x); // will always be positive
CGFloat deltaY = fabsf(gestureStartPoint.y - currentPosition.y); // will always be positive
if (deltaX >= kMinimumGestureLength && deltaY <= kMaximumVariance) {
if (deltaXX > 0) {
label.text = #"Horizontal Left swipe detected";
[self performSelector:#selector(eraseText) withObject:nil afterDelay:2];
}
else {
label.text = #"Horizontal Right swipe detected";
[self performSelector:#selector(eraseText) withObject:nil afterDelay:2];
}
}
if (deltaY >= kMinimumGestureLength && deltaX <= kMaximumVariance) {
if (deltaYY > 0) {
label.text = #"Vertical up swipe detected";
[self performSelector:#selector(eraseText) withObject:nil afterDelay:2];
}
else {
label.text = #"Vertical down swipe detected";
[self performSelector:#selector(eraseText) withObject:nil afterDelay:2];
}
}
}
I was facing the exact same thing, and I was looking for a solution. There is no such thing as required distance in UISwipeGestureRecognizer but that's not all you can use. I ended up using UIPanGestureRecognizer! It looks like a super class of swipe gesture recognizer and it certainly exposes more useful data.
There is a method available in this class called translationInView:(UIView *)aView the returns a CGPoint where x & y is the total distance over the whole pan gesture! something amazingly useful for our request! And it respects the direction by positive and negative values, meaning: y=+100 -> swipe up to down 100 points, x=+100 swipe left to right 100 points, etc...
What am I doing is to check if the user has panned for a given amount of points (I was looking for something like swipe down, so for me it was y>150) and then do my thing...
here is some code excerpts:
-(void)viewDidLoad
{
UIPanGestureRecoginzer *panDown=[[UIPanGestureRecoginzer alloc] initWithTarget:self action:#selector(swipedDown:)];
[self.view addGestureRecognizer:panDown];
}
.
.
.
-(void)swipedDown:(UIPanGestureRecoginzer *)recognizer
{
CGPoint panned=[recognizer translationInView:self.view];
if(panned.y>150){
//swiped down for 150 points
doSomething();
}
}
It also gives you the velocity of the pan: velocityInView:
Note: You should use your superview (self.view in most cases) if you want to have an overall pan effect.
Hope this helps: UIPanGestureRecognize Class Reference
Please see this documentation http://developer.apple.com/library/ios/#documentation/uikit/reference/UIResponder_Class/Reference/Reference.html
You can use touchesBegan, touchesMoved, and touchesEnded methods to find the start/end positions of the swipe. By finding the delta between the start and the end, you can get the swipe length.
Maybe something like this.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
UITouch *touch = [touches anyObject];
gestureStartPoint = [touch locationInView:self.view];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint gestureEndPoint = [touch locationInView:self.view];
// compare gestureStartPoint and gestureEndPoint to determine swipe length
}
Check out this question: UISwipeGestureRecognizer Swipe length
Swift 3:
var gestureStartPoint: CGPoint = .zero
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
gestureStartPoint = touch!.location(in: self.view)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
let gestureEndPoint = touch!.location(in: self.view)
let dist = distance(gestureStartPoint, gestureEndPoint)
print(dist)
}
func distance(_ a: CGPoint, _ b: CGPoint) -> CGFloat {
let xDist = a.x - b.x
let yDist = a.y - b.y
return CGFloat(sqrt((xDist * xDist) + (yDist * yDist)))
}
In touchesBegan:
CGPoint touch_point = [[touches anyObject] locationInView:self.view];
There are tens of UIImageView around, stored in a NSMutableArray images. I'd like to know is there a built-in function to check if a CGPoint (touch_point) is inside one of the images, e.g.:
for (UIImageView *image in images) {
// how to test if touch_point is tapped on a image?
}
Thanks
Follow up:
For unknown reason, pointInside never returns true. Here is the full code.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
touch_point = [touch locationInView:self.view];
for (UIImageView *image in piece_images) {
if ([image pointInside:touch_point withEvent:event]) {
image.hidden = YES;
} else {
image.hidden = NO;
}
NSLog(#"image %.0f %.0f touch %.0f %.0f", image.center.x, image.center.y, touch_point.x, touch_point.y);
}
}
although I can see the two points are sometimes identical in the NSLog output.
I also tried:
if ([image pointInside:touch_point withEvent:nil])
the result is the same. never returns a true.
To eliminate the chance of anything goes with with the images. I tried the following:
if (YES or [image pointInside:touch_point withEvent:event])
all images are hidden after the first click on screen.
EDIT 2:
Really weird. Even I hard coded this:
point.x = image.center.x;
point.y = image.center.y;
the code becomes:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint point; // = [touch locationInView:self.view];
for (UIImageView *image in piece_images) {
point.x = image.center.x;
point.y = image.center.y;
if ([image pointInside:point withEvent:event]) {
image.hidden = YES;
NSLog(#"YES");
} else {
image.hidden = NO;
NSLog(#"NO");
}
NSLog(#"image %.0f %.0f touch %.0f %.0f", image.center.x, image.center.y, point.x, point.y);
}
}
pointInside always returns false ...
Sounds to me like the problem is you need to convert coordinates from your view's coordinates to the UIImageView's coordinates. You can use UIView's convertPoint method.
Try replacing
if ([image pointInside:touch_point withEvent:event]) {
with
if ([image pointInside: [self.view convertPoint:touch_point toView: image] withEvent:event]) {
(Note that you are allowed to pass nil instead of event.)
I guess this is a bit late for the questioner, but I hope it is of use to someone.
if ([image pointInside:touch_point withEvent:event]) {
// Point inside
}else {
// Point isn't inside
}
In this case event is taken from :
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:self.view];
for (UIImageView *piece in piece_images) {
CGFloat x_min = piece.center.x - (piece.bounds.size.width / 2);
CGFloat x_max = x_min + piece.bounds.size.width;
CGFloat y_min = piece.center.y - (piece.bounds.size.height / 2);
CGFloat y_max = y_min + piece.bounds.size.height;
if (point.x > x_min && point.x < x_max && point.y > y_min && point.y < y_max ) {
piece.hidden = YES;
} else {
piece.hidden = NO;
}
}
}
too bad, I have do it myself...
it's OS 3.2, XCode 3.2.2, tried both on simulator and iPad
I'm making an iPhone app in which the user can do gestures (left and right swipes) to flick through tabs. My problem is that some of the pages have views such as the pickerview, webview, textfields and buttons. The swipes don't work on these. Is there any way to have global gestures?
For reference, my gesture code example:
//Swipe between tabs
#define mindrag 100
CGPoint mystartTouchPosition;
BOOL isProcessingListMove;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint newTouchPosition = [touch locationInView:self.view];
if(mystartTouchPosition.x != newTouchPosition.x || mystartTouchPosition.y != newTouchPosition.y) {
isProcessingListMove = NO;
}
mystartTouchPosition = [touch locationInView:self.view];
[super touchesBegan:touches withEvent:event];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = touches.anyObject;
CGPoint currentTouchPosition = [touch locationInView:self.view];
// If the swipe tracks correctly.
double diffx = mystartTouchPosition.x - currentTouchPosition.x + 0.1; // adding 0.1 to avoid division by zero
double diffy = mystartTouchPosition.y - currentTouchPosition.y + 0.1; // adding 0.1 to avoid division by zero
if(abs(diffx / diffy) > 2.5 && abs(diffx) > mindrag)
{
// It appears to be a swipe.
if(isProcessingListMove) {
// ignore move, we're currently processing the swipe
return;
}
if (mystartTouchPosition.x < currentTouchPosition.x) {
isProcessingListMove = YES;
self.tabBarController.selectedViewController = [self.tabBarController.viewControllers objectAtIndex:1];
return;
}
else {
isProcessingListMove = YES;
self.tabBarController.selectedViewController = [self.tabBarController.viewControllers objectAtIndex:3];
return;
}
}
else if(abs(diffy / diffx) > 1)
{
isProcessingListMove = YES;
[super touchesMoved:touches withEvent:event];
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
isProcessingListMove = NO;
[super touchesEnded:touches withEvent:event];
}
// End of swipe
Any input is appreciated.
You can subclass UIImagePickerController and UIWebView and add these gesture capturing views to them, so long as you gesture detection can still pass touches to the underlying views of course.