Incomprehensible touches: Began and touchEnded

I looked at the Apple touch touch application and it does not concern my problem. In his application example, when a touch event occurs, he tries to save the view (s) located where the touch event occurs. This makes the logic simple. They are simply looking for views whose frames contain the location of the touch.

This does not work in my scenario. Here is my script.

There is a view containing a bunch of subitems. The idea is to allow the user to sort the cast of one of the subzones in the direction they create. I want the touchesBegan event to find a view whose center is closest to the touch.

Then I want the touchesEnded event touchesEnded move the same view at the speed determined by the start and end events. The speed will not necessarily be the same as the speed of the finger, so I can’t just β€œattach” the view to the touch location, as Apple did in the sample application.

I was thinking about marking the view specified in touchesBegan with a touch object and use it to compare with the touch object in the touchesEnded event, but this does not work. The touch object does not match the touchesBegan and touchesEnded .

So what am I missing? How to keep the connection between the moved view and touch?

0
source share
3 answers

The touch object is actually the same in touchesBegan and touchesEnded . It turned out to be a way to track strokes.

0
source

TouchObject will not be like. The object will be changed using touch, location, etc. See the UITouch Class for more details.

Suggestion 1:

I implemented the same thing in my project using a subclass of UIView and added touch delegates inside the subclass. And I created an instance of this subclass instead of the usual UIView.

 @interface myView : UIView @end @implementation myView //over ride the following methods - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { } - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event { } @end 

Offer 2

Use UIPanGesture for this. This will be an easier way.

 UIPanGestureRecognizer *panGesture = [[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureMoveAround:)] autorelease]; [panGesture setMaximumNumberOfTouches:2]; [panGesture setDelegate:self]; [yourSubView addGestureRecognizer:panGesture]; -(void)panGestureMoveAround:(UIPanGestureRecognizer *)gesture; { UIView *piece = [gesture view]; [self adjustAnchorPointForGestureRecognizer:gesture]; if ([gesture state] == UIGestureRecognizerStateBegan || [gesture state] == UIGestureRecognizerStateChanged) { CGPoint translation = [gesture translationInView:[piece superview]]; [piece setCenter:CGPointMake([piece center].x + translation.x, [piece center].y+translation.y*0.1)]; [gesture setTranslation:CGPointZero inView:[piece superview]]; } } 

Example here

0
source

Here is my solution. In this solution, scaledView is the view in which the arrows move. They have a spriteView class, which is a subclass of UIView .

 -(spriteView *)findArrowContainingTouch:(UITouch *)touch inView:(UIView *)scaledView atPoint:(CGPoint) touchPoint //There could be multiple subviews whose rectangles include the point. Find the one whose center is closest. { spriteView * touchedView = nil; float bestDistance2 = 9999999999.9; float testDistance2 = 0; for (spriteView *arrow in scaledView.subviews) { if (arrow.tag == ARROWTAG) { if (CGRectContainsPoint(arrow.frame, touchPoint)) { testDistance2 = [self distance2Between:touchPoint and:arrow.center]; if (testDistance2<bestDistance2) { bestDistance2 = testDistance2; touchedView = arrow; } } } } return touchedView; } 

The distance2Between method calculates the square of the distance between two points.

 -(spriteView *)findArrowTouchedAtLocation:(CGPoint)p inView:(UIView *)scaledView { spriteView * arrow = nil; for (spriteView *testArrow in scaledView.subviews) { if (testArrow.tag == ARROWTAG) { if ((px == testArrow.touch.x) && (py == testArrow.touch.y)) { arrow = testArrow; } } } return arrow; } 

There is a subspecies that are not arrows in scaledView , so I use the ARROWTAG constant to identify the arrows.

 #pragma mark - Touches -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UIView *scaledView = [self getScaledView]; for (UITouch *touch in touches) { CGPoint touchLocation = [touch locationInView:scaledView]; spriteView * arrow = [self findArrowContainingTouch:touch inView:scaledView atPoint:touchLocation]; if (!(arrow==nil)) { //Record the original location of the touch event in a property, originalTouchLocation, of the arrow instance. Additionally, store the same point on the property touch. //Both properties are necessary. The originalTouchLocation will be used in `touchesEnded` and is not available in the `touch` object. So the information is stored separately. //The `touch` property, a CGPoint, is stored in order to identify the view. This property is updated by every touch event. The new value will be used by the upcoming event to find the appropriate view. arrow.touch = CGPointMake(touchLocation.x, touchLocation.y); arrow.originalTouchLocation = CGPointMake(touchLocation.x, touchLocation.y); arrow.debugFlag = YES; arrow.timeTouchBegan = touch.timestamp; } } } -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { UIView *scaledView = [self getScaledView]; for (UITouch *touch in touches) { CGPoint touchLocation = [touch locationInView:scaledView]; CGPoint previousLocation = [touch previousLocationInView:scaledView]; //previousLocation is used to find the right view. This must be in the coordinate system of the same view used in `touchesBegan`. spriteView * arrow = [self findArrowTouchedAtLocation:previousLocation inView:scaledView]; if (!(arrow==nil)) { arrow.touch = CGPointMake(touchLocation.x, touchLocation.y); } } } -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { UIView *scaledView = [self getScaledView]; for (UITouch *touch in touches) { CGPoint touchLocation = [touch locationInView:scaledView]; CGPoint previousLocation = [touch previousLocationInView:scaledView]; spriteView * arrow = [self findArrowTouchedAtLocation:previousLocation inView:scaledView]; if (!(arrow==nil)) { arrow.touch = CGPointMake(touchLocation.x, touchLocation.y); float strokeAngle = [self findAngleFrom:arrow.originalTouchLocation to:touchLocation]; float strokeDistance2 = sqrt([self distance2Between:arrow.originalTouchLocation and:touchLocation]); NSTimeInterval timeElapsed = touch.timestamp - arrow.timeTouchBegan; float newArrowSpeed = strokeDistance2 / timeElapsed / 100; //might want to use a different conversion factor, but this one works quite well arrow.transform = CGAffineTransformMakeRotation(strokeAngle); arrow.currentSpeed = newArrowSpeed; } } } -(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { UIView *scaledView = [self getScaledView]; for (UITouch *touch in touches) { CGPoint previousLocation = [touch previousLocationInView:scaledView]; spriteView * arrow = [self findArrowTouchedAtLocation:previousLocation inView:scaledView]; if (!(arrow==nil)) { arrow.originalTouchLocation = CGPointMake(99999.0, 99999.0); NSLog(@"Arrow original location erased"); } } } 
0
source

All Articles