In my UITableViewCell subclass I add a pan gesture and in gestureRecognizerShouldBegin method I checked self.frame.origin.x and self.frame.origin.y both are 0.000000 and 0.000000and after applying TranslationInView CGPoint translation = [gestureRecognizer translationInView:[self superview]]; I am getting x=-4.000000 and y=0.000000
How TranslationInView work, I am trying to wrap my head around it, when I am getting the correct location of cell 0.0 and 0.0 because the first cell will have 0.0 and 0.0, why I need TranslationInView.
TranslationInView is a method of UIPanGestureRecognizer and it tells you how far the touch moved since it was last reset. It resets when the touch goes down or if you reset it yourself.
For example
- (void) pan: (UIPanGestureRecognizer *) recognizer
{
if ((recognizer.state == UIGestureRecognizerStateChanged)||(recognizer.state == UIGestureRecognizerStateEnded)) {
CGPoint translation = [recognizer translationInView:self];
}
}
The CGPoint traslation gets increased/decreased the distance that the gesture has moved.
Related
I's using this method:
- (void)setTranslation:(CGPoint)translation inView:(UIView *)view
From UIPanGestureRecognizer class, and I don't understand the velocity discussions around that.
Appel's documentation says:
Sets the translation value in the coordinate system of the specified
view. Changing the translation value resets the velocity of the pan.
What's that exactly mean? What is "reset velocity of the pan"?
Any help will be appreciated.. Thanks in advance!
--EDIT
See this code:
if (recognizer.state == UIGestureRecognizerStateChanged) {
CGPoint translation = [recognizer translationInView:self.cardsScrollView];
recognizer.view.center = CGPointMake(recognizer.view.center.x, recognizer.view.center.y + translation.y);
[recognizer setTranslation:CGPointMake(0, 0) inView:recognizer.view];
...
}
What it means is that if you're in the middle of the panning gesture (you're dragging something) and you call setTranslation:inView: on that gesture, it's velocity is going to be reset to 0;
A pan gesture not only gives you the translation but also the velocity of the gesture (how fast you're dragging) in units per second (points per second in this case). You can access the velocity by calling velocityInView:.
If you don't use the velocity then don't worry about it, otherwise keep the above in mind.
UPDATE:
I'm guessing you're trying to move the view as you drag it. I would do it slightly differently.
if (recognizer.state == UIGestureRecognizerStateBegan) {
CGAffineTransform transform = recognizer.view.transform;
[recognizer setTranslation:CGPointMake(transform.tx, transform.ty) inView:self];
} else if (recognizer.state == UIGestureRecognizerStateChanged) {
CGPoint translation = [recognizer translationInView:self.cardsScrollView];
recognizer.view.transform = CGAffineTransformMakeTranslation(translation.x, translation.y);
}
The thing to keep in mind is that self.cardsScrollView should be the superview of the view you're trying to move.
I'm using a UIPanGestureRecognizer and UIAttachmentBehavior to move a UIView around the screen. When the user ends the gesture I apply the velocity of the gesture recognizer to the view using a UIDynamicItemBehavior and the addLinearVelocity:forItem: method.
Here is the code I use:
- (void)_handlePanGestureRecognized: (UIPanGestureRecognizer *)panGestureRecognizer
{
if (panGestureRecognizer.state == UIGestureRecognizerStateBegan)
{
_attachmentBehavior.anchorPoint = panGestureRecognizer.view.center;
[_dynamicAnimator addBehavior: _attachmentBehavior];
}
else if (panGestureRecognizer.state == UIGestureRecognizerStateChanged)
{
CGPoint point = [panGestureRecognizer locationInView: panGestureRecognizer.view.superview];
_attachmentBehavior.anchorPoint = point;
}
else if (panGestureRecognizer.state == UIGestureRecognizerStateEnded)
{
[_dynamicAnimator removeBehavior: _attachmentBehavior];
CGPoint velocity = [panGestureRecognizer velocityInView: panGestureRecognizer.view.superview];
[_dynamicItemBehavior addLinearVelocity: velocity
forItem: self];
}
}
When the view stops moving I would then like to have it snap to the closest edge of the screen but I currently have no way of knowing when it has stopped moving short of polling the view's center with a CADisplayLink.
Have you tried attaching a UIDynamicAnimatorDelegate to your animator, and using the dynamicAnimatorDidPause: method to trigger snapping to the closest edge?
From reading on the developer forums, it sounds like some have had problems with their views staying in motion for a very long time (jiggling back and forth by 1 pixel, for example), but perhaps this will work for your case.
I have a pan gesture recogniser acting as a slider, code as follows:
- (void)minutePan:(UIPanGestureRecognizer *)gesture
{
if ((gesture.state == UIGestureRecognizerStateChanged) ||
(gesture.state == UIGestureRecognizerStateEnded)){
CGPoint translation = [gesture translationInView:gesture.view.superview];
float leftBound = gesture.view.bounds.size.width / 2.0f;
float rightBound = gesture.view.bounds.size.width + (leftBound - 60);
float position;
if(gesture.view.center.x < leftBound){
position = leftBound;
}else if(gesture.view.center.x > rightBound){
position = rightBound;
}else{
position = gesture.view.center.x + translation.x;
}
gesture.view.center = CGPointMake(position, gesture.view.center.y);
[gesture setTranslation:CGPointZero inView:gesture.view.superview];
}
}
I have a UIView with the gesture recogniser attached inside another UIView acting as the boundary for it. Its working fine except when I get to the left and right edges. The position variable should not get set lower than half the panned views width but it seems to be updating the view on the screen before the code runs. This causes the view to go outside the bounds and flicker back as long as the user is dragging. Any help would be greatly appreciated thanks.
I'm learning iOS and I can't find how to add drag and drop behavior to a UIView.
I tried:
[_view addTarget:self action:#selector(moved:withEvent:) forControlEvents:UIControlEventTouchDragInside];
It says "no visible interface for UIView declares selector addTarget (etc)"
Also I tried adding a pan gesture recognizer but not sure if that's what I need
- (IBAction)test:(id)sender {
NSLog(#"dfsdfsf");
}
It's called, but don't know how to get the coordinates of the event. What't the standard, simple way in iOS to register a callback for move events / do drag and drop?
Thanks in advance.
A UIPanGestureRecognizer is definitely the way to go. If you want the user to drag the view around, you'll need the “translation” (movement) of the gesture in the superview's coordinate system:
- (IBAction)panWasRecognized:(UIPanGestureRecognizer *)recognizer {
CGPoint translation = [recognizer translationInView:_view.superview];
Once you have the translation, you can move (“drag”) the view by changing its center:
CGPoint center = _view.center;
center.x += translation.x;
center.y += translation.y;
_view.center = center;
Finally, you want to set the pan gesture recognizer's translation back to zero, so the next time you get the message, it only tells you how much the gesture has moved since the last message:
[recognizer setTranslation:CGPointZero inView:_view.superview];
}
Here it is all together for easy copy/paste:
- (IBAction)panWasRecognized:(UIPanGestureRecognizer *)recognizer {
CGPoint translation = [recognizer translationInView:_view.superview];
CGPoint center = _view.center;
center.x += translation.x;
center.y += translation.y;
_view.center = center;
[recognizer setTranslation:CGPointZero inView:_view.superview];
}
Start with touchesBegan, touchesMoved, touchesEnded. Override these in your UIView subclass and you'll be on your way to learning the event system. You can get the event coordinates like so:
- (void) touchesBegan:(NSSet *) touches withEvent:(UIEvent *) event
{
float x = [[touches anyObject] locationInView:self].x;
float y = [[touches anyObject] locationInView:self].y;
}
Then there's a ton of stuff for converting coordinates between different views and so on. Once you've understood that, you can work with the UIGestureRecognizer stuff you've already found which is what you need.
You are going to need a pan gesture recognizer to do drag/drop. You can use the locationInView: selector in UIPanGestureRecognizer to find out where you are at any given moment.
You add your gesture recognizer like so, not with the target-action stuff you were trying:
UIPanGestureRecognizer *dragDropRecog = [[UIPanGestureRecognizer alloc] initWithTarget:yourView action:#selector(thingDragged:)];
[yourView addGestureRecognizer:dragDropRecog];
Then you have to implement the selector thingDragged: in your view:
- (void) thingDragged:(UIPanGestureRecognizer *) gesture
{
CGPoint location = [gesture locationInView:self];
if ([gesture state] == UIGestureRecognizerStateBegan) {
// Drag started
} else if ([gesture state] == UIGestureRecognizerStateChanged) {
// Drag moved
} else if ([gesture state] == UIGestureRecognizerStateEnded) {
// Drag completed
}
}
You'll be translating the view being dragged in the changed bit, and handling the drop in the ended section.
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(pan:)];
[self addGestureRecognizer:panRecognizer];
- (void)pan:(UIPanGestureRecognizer *)gesture {
NSLog(#"%f", [gesture translationInView:self].x);
}
The above code will log the relative position of my current pan, but how can I get the absolute position for the view I'm in?
I'm simply just wanting to slide a UIImageView to wherever the user's finger is.
translationInView gives you the pan translation (how much x has changed) and not the position of the pan in the view (the value of x). If you need the position of the pan, you have to use the method locationInView.
You can find the coordinates relatively to the view as follows:
- (void)pan:(UIPanGestureRecognizer *)gesture {
NSLog(#"%f", [gesture locationInView:self].x);
}
Or relatively to the superview:
- (void)pan:(UIPanGestureRecognizer *)gesture {
NSLog(#"%f", [gesture locationInView:self.superview].x);
}
Or relatively to the window:
- (void)pan:(UIPanGestureRecognizer *)gesture {
NSLog(#"%f", [gesture locationInView:self.window].x);
}
Swift 5
Use the method .location() that returns a CGPoint value. [documentation]
For example, relative location of your gesture to self.view:
let relativeLocation = gesture.location(self.view)
print(relativeLocation.x)
print(relativeLocation.y)
I think a simple way of something like this is to get the x and y of the touch and tracking it, once it has 2 points (say X:230 Y:122) you set the scroll of the UIScroll view to the x and y.