how do i add straight vertical slide in UIPanGestureRecognizer on image. i have some code:
- (IBAction)HandlePan:(UIPanGestureRecognizer *)panner
{
CGPoint translation = [panner translationInView:panner.view];
CGPoint newCenter = CGPointMake(self.pesawat.center.x + translation.x, self.pesawat.center.y);
int offset = 80; // pixels to offset
if (newCenter.x < offset)
newCenter = CGPointMake(offset, newCenter.y);
else if (newCenter.x > self.view.bounds.size.width - offset)
newCenter = CGPointMake(self.view.bounds.size.width - offset, newCenter.y);
self.pesawat.center = newCenter;
[panner setTranslation:CGPointMake(0, 0) inView:panner.view];
}
if i change code to like this:
CGPoint newCenter = CGPointMake(self.pesawat.center.x + translation.x, self.pesawat.center.y + translation.y);
it's become dragable(horizontal,vertical,diagonal too), what i want is just to make it's straight vertical and horizontal without image to move diagonal
and this viewdidload:
UIPanGestureRecognizer * panner = [[UIPanGestureRecognizer alloc]init];
[panner addTarget:self action:#selector(HandlePan:)];
[self.view addGestureRecognizer:panner];
could anyone give a hint?
CGPoint translation = [panner translationInView:panner.view];
if (translation.x > translation.y)
translation.y = 0.0f;
else
translation.x = 0.0f;
CGPoint newCenter = CGPointMake(self.pesawat.center.x + translation.x, self.pesawat.center.y + translation.y);
This will only apply the bigger part of translation.
Related
I've added a pan gesture to my button, when i move it without any additional code, everything is well, but when i add some piece of code, which is commented in the example below, button starts reseting to its origin position.
Why is this happening? What's the reason for this?
- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer {
switch([recognizer state]){
case UIGestureRecognizerStateBegan: {
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setFrame:recognizer.view.frame];
[button setBackgroundColor: [UIColor redColor]];
// [self.view insertSubview:button belowSubview:recognizer.view];
_tempButton = button;
}break;
case UIGestureRecognizerStateChanged: {
CGPoint translation = [recognizer translationInView:self.view];
recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x, recognizer.view.center.y + translation.y);
[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
}break;
}
}
The code that you have added at the UIGestureRecognizerStateChanged case, move it in the header of your Action Method:
CGPoint translation = [recognizer translationInView:self.view];
recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x,
recognizer.view.center.y + translation.y);
[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
After that another thing for you to do is to make another Case in your Switch Method:
//This checks if you ended the pan gesture (removed finger from object)
case UIGestureRecognizerStateEnded:
{
CGPoint velocity = [recognizer velocityInView:self.view];
CGFloat magnitude = sqrtf((velocity.x * velocity.x) + (velocity.y * velocity.y));
CGFloat slideMult = magnitude / 200;
NSLog(#"magnitude: %f, slideMult: %f", magnitude, slideMult);
float slideFactor = 0.1 * slideMult; // Increase for more of a slide
CGPoint finalPoint = CGPointMake(recognizer.view.center.x + (velocity.x * slideFactor),
recognizer.view.center.y + (velocity.y * slideFactor));
finalPoint.x = MIN(MAX(finalPoint.x, 0), self.view.bounds.size.width);
finalPoint.y = MIN(MAX(finalPoint.y, 0), self.view.bounds.size.height);
[UIView animateWithDuration:slideFactor*2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
recognizer.view.center = finalPoint;
} completion:nil];
}
So what I did above in the UIGestureRecognizerStateEnded state is that, i took the final point where the user sent the image. After that, i set the center of the image equal to the point that the image was the last moment. So now the image wont return to the previous point but it will remain where the user will take it.
I have built a small test app to apply pan gesture on a UIButton. I applied the pan gesture successfully and succeeded in moving the button.
But the problem is that I can move the button even outside the screen.
How do I bound it to move only within the iPhone screen?
Here is my code :
- (void)viewDidLoad
{
[super viewDidLoad];
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(pan:)];
[panGesture setMinimumNumberOfTouches:1];
[_shareButton addGestureRecognizer:panGesture];
}
-(IBAction)pan:(UIPanGestureRecognizer *)recognizer
{
CGPoint trans =[recognizer translationInView:self.view];
recognizer.view.center = CGPointMake(recognizer.view.center.x+trans.x, recognizer.view.center.y+trans.y);
[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
}
How do I restrict the button to move out of screen? I am using iOS 7, xcode 5.0.
This will work for you .. But i wrote it in Swift :
func callMe(sender: UIPanGestureRecognizer)
{
let translation = sender.translationInView(self.view)
let newX = sender.view!.center.x + translation.x
let newY = sender.view!.center.y + translation.y
let senderWidth = sender.view!.bounds.width / 2
let senderHight = sender.view!.bounds.height / 2
if newX <= senderWidth
{
sender.view!.center = CGPoint(x: senderWidth, y: sender.view!.center.y + translation.y)
}
else if newX >= self.view.bounds.maxX - senderWidth
{
sender.view!.center = CGPoint(x: self.view.bounds.maxX - senderWidth, y: sender.view!.center.y + translation.y)
}
if newY <= senderHight
{
sender.view!.center = CGPoint(x: sender.view!.center.x + translation.x, y: senderHight)
}
else if newY >= self.view.bounds.maxY - senderHight
{
sender.view!.center = CGPoint(x: sender.view!.center.x + translation.x, y: self.view.bounds.maxY - senderHight)
}
else
{
sender.view!.center = CGPoint(x: sender.view!.center.x + translation.x, y: sender.view!.center.y + translation.y)
}
sender.setTranslation(CGPointZero, inView: self.view)
}
I Hope It helps anyone who's searching for the simplest way to do it.
Try this:
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
[pan setDelegate:self];
[shareButton addGestureRecognizer:pan];
-(void)handlePan:(UIGestureRecognizer*)panGes{
CGPoint point = [panGes locationInView:self.view];
if (point.x >20 && point.x <280 && point.y<400 && point.y>30) {
CGRect newframe = CGRectMake(point.x, point.y, shareButton.frame.size.width, shareButton.frame.size.height);
shareButton.frame = newframe;
}
}
and replace 20,280 & 400,30 with your respective limits.
Edit your code like this:
-(IBAction)pan:(UIPanGestureRecognizer *)recognizer
{
CGPoint trans =[recognizer translationInView:self.view];
if (CGRectContainsPoint([self.view frame], trans))
{
recognizer.view.center = trans;
}
}
Here what you are doing is, you are whether point lies in view's frame or not. If it is. you are moving the center of dragged button.. let me know if this does not solve your issue.
Update 2:
Instead of implementing PanGesture, you can use onDrag event too:
- (IBAction)onButtonDrag:(id)sender forEvent:(UIEvent *)event {
CGPoint point = [[[event allTouches] anyObject] locationInView:sender.view];
UIControl *control = sender;
if (CGRectContainsPoint([self.view frame], point)) {
control.center = point;
[self.view touchesEnded:[event allTouches] withEvent:event];
}
}
Got it. Coded as follows :
-(IBAction)pan:(UIPanGestureRecognizer *)recognizer
{
CGPoint trans =[recognizer translationInView:self.view];
CGFloat sumx = _shareButton.frame.origin.x+_shareButton.frame.size.width+5;
CGFloat sumy = _shareButton.frame.origin.y+_shareButton.frame.size.height+5;
CGFloat sumxm = _shareButton.frame.origin.x;
CGFloat sumym = _shareButton.frame.origin.y;
NSLog(#"position : %f, %f ", _shareButton.frame.origin.x, _shareButton.frame.origin.y);
NSLog(#"screen : %f, %f ", self.view.frame.size.width ,self.view.frame.size.height);
if (sumx > self.view.frame.size.width || sumy > self.view.frame.size.height )
{
CGRect shareButton = _shareButton.frame;
shareButton.origin.y -= 1;
shareButton.origin.x -= 1;
_shareButton.frame = shareButton;
return;
}
else if(sumxm < 0 || sumym < 0) {
CGRect shareButton = _shareButton.frame;
if(sumxm < 0)
{
shareButton.origin.x =0;
}
if(sumym < 0){
shareButton.origin.y =0;
}
_shareButton.frame = shareButton;
NSLog(#"share button : %f, %f", _shareButton.frame.origin.x, _shareButton.frame.origin.y);
return;
}
recognizer.view.center = CGPointMake(recognizer.view.center.x+trans.x, recognizer.view.center.y+trans.y);
[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
}
Bound Limit of your Gesture Frame.It's Simply size of window.width and height.
Below is tutorial for gesture.I know it's for gaming but find your logic into this tutoril.
http://www.raywenderlich.com/2343/cocos2d-tutorial-for-ios-how-to-drag-and-drop-sprites
Disabling Pan Gesture if out of bounds detected
- (CGPoint)boundLayerPos:(CGPoint)newPos {
CGSize winSize = [CCDirector sharedDirector].winSize;
CGPoint retval = newPos;
retval.x = MIN(retval.x, 0);
retval.x = MAX(self.position.x);
retval.y = self.position.y;
return retval;
}
-(void)dragAction:(UIPanGestureRecognizer *)gesture{
UIView *vw = (UIView *)gesture.view;
CGPoint translation = [gesture translationInView:vw];
if (CGRectContainsPoint(vw.frame, [gesture locationInView:vw] )) {
vw.center = CGPointMake(vw.center.x,
vw.center.y);
[gesture setTranslation:CGPointZero inView:vw];
}
else{
vw.center = CGPointMake(vw.center.x,
vw.center.y + translation.y);
[gesture setTranslation:CGPointZero inView:vw];
}
I have a UIPanGestureRecognizer that I use to pull up a view. the view starts at x = 160, y= 817 and when it is flicked up, I want it to go to 160,284. And When it is flicked back down I want it to automatically go back to the starting point. Here is my code so far:
-(IBAction) dragMe: (UIPanGestureRecognizer *)recognizer {
CGPoint translation = [recognizer translationInView:recognizer.view.superview];
recognizer.view.center = CGPointMake(recognizer.view.center.x, + recognizer.view.center.y + translation.y);
[recognizer setTranslation:CGPointMake(0, 0) inView:recognizer.view.superview];
if (recognizer.state == UIGestureRecognizerStateEnded) {
CGPoint velocity = [recognizer velocityInView:recognizer.view.superview];
CGFloat magnitude = sqrtf((velocity.y * velocity.y));
CGFloat slideMult = magnitude / 100;
NSLog(#"magnitude: %f, slideMult: %f", magnitude, slideMult);
float slideFactor = 0.1 * slideMult; // Increase for more of a slide
CGPoint finalPoint = CGPointMake(recognizer.view.center.x,
recognizer.view.center.y + (velocity.y * slideFactor));
finalPoint.x = MIN(MAX(finalPoint.x, 160), recognizer.view.superview.bounds.size.width);
finalPoint.y = MIN(MAX(finalPoint.y, 284), recognizer.view.superview.bounds.size.height);
[UIView animateWithDuration:slideFactor*1 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
recognizer.view.center = finalPoint;
} completion:nil];
}
}
I don't want the user to be able to move it at all horizontally, just vertically.
I am using the following code to move a UIImageView that is present inside of a UIView.
- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer {
CGPoint translation = [recognizer translationInView:self.view];
recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x,
recognizer.view.center.y + translation.y);
[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
}
I would like to make it so that the UIView does not move outside of the parent view. At the minute the image view is able to move across the entire screen.
First get the new frame of your UIImageView and check if it is completely inside its superView using CGRectContainsRect() method. If yes, then set UImageView's frame to new frame.
- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer {
CGPoint translation = [recognizer translationInView:self.view];
CGRect recognizerFrame = recognizer.view.frame;
recognizerFrame.origin.x += translation.x;
recognizerFrame.origin.y += translation.y;
// Check if UIImageView is completely inside its superView
if (CGRectContainsRect(self.view.bounds, recognizerFrame)) {
recognizer.view.frame = recognizerFrame;
}
// Else check if UIImageView is vertically and/or horizontally outside of its
// superView. If yes, then set UImageView's frame accordingly.
// This is required so that when user pans rapidly then it provides smooth translation.
else {
// Check vertically
if (recognizerFrame.origin.y < self.view.bounds.origin.y) {
recognizerFrame.origin.y = 0;
}
else if (recognizerFrame.origin.y + recognizerFrame.size.height > self.view.bounds.size.height) {
recognizerFrame.origin.y = self.view.bounds.size.height - recognizerFrame.size.height;
}
// Check horizantally
if (recognizerFrame.origin.x < self.view.bounds.origin.x) {
recognizerFrame.origin.x = 0;
}
else if (recognizerFrame.origin.x + recognizerFrame.size.width > self.view.bounds.size.width) {
recognizerFrame.origin.x = self.view.bounds.size.width - recognizerFrame.size.width;
}
}
// Reset translation so that on next pan recognition
// we get correct translation value
[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
}
Make sure that you pass bounds of superView and frame of UIImageView so that both CGRects are in same coordinate system.
Try with:
- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer
{
if (gesture.state==UIGestureRecognizerStateChanged || gesture.state == UIGestureRecognizerStateEnded){
UIView *superview = recognizer.view.superview;
CGSize superviewSize = superview.bounds.size;
CGSize thisSize = recognizer.view.size;
CGPoint translation = [recognizer translationInView:self.view];
CGPoint center = CGPointMake(recognizer.view.center.x + translation.x,
recognizer.view.center.y + translation.y);
CGPoint resetTranslation = CGPointMake(translation.x, translation.y);
if(center.x - thisSize.width/2 < 0)
center.x = thisSize.width/2;
else if (center.x + thisSize.width/2 > superviewSize.width)
center.x = superviewSize.width-thisSize.width/2;
else
resetTranslation.x = 0; //Only reset the horizontal translation if the view *did* translate horizontally
if(center.y - thisSize.height/2 < 0)
center.y = thisSize.height/2;
else if(center.y + thisSize.height/2 > superviewSize.height)
center.y = superviewSize.height-thisSize.height/2;
else
resetTranslation.y = 0; //Only reset the vertical translation if the view *did* translate vertically
recognizer.view.center = center;
[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
}
}
This way it won't ever move outside the parent view bounds and it will just "stick" to the edge if you try to move it out of the bounds!
Swift version of micantox answer
let gesture = UIPanGestureRecognizer(target: self, action: #selector(self.wasDragged(gestureRecognizer:)))
imageView.addGestureRecognizer(gesture)
imageView.isUserInteractionEnabled = true
#objc func wasDragged(gestureRecognizer: UIPanGestureRecognizer) {
if gestureRecognizer.state == UIGestureRecognizerState.changed || gestureRecognizer.state == UIGestureRecognizerState.ended {
let superview = gestureRecognizer.view?.superview
let superviewSize = superview?.bounds.size
let thisSize = gestureRecognizer.view?.frame.size
let translation = gestureRecognizer.translation(in: self.view)
var center = CGPoint(x: gestureRecognizer.view!.center.x + translation.x, y: gestureRecognizer.view!.center.y + translation.y)
var resetTranslation = CGPoint(x: translation.x, y: translation.y)
if center.x - (thisSize?.width)!/2 < 0 {
center.x = (thisSize?.width)!/2
} else if center.x + (thisSize?.width)!/2 > (superviewSize?.width)! {
center.x = (superviewSize?.width)!-(thisSize?.width)!/2
} else {
resetTranslation.x = 0 //Only reset the horizontal translation if the view *did* translate horizontally
}
if center.y - (thisSize?.height)!/2 < 0 {
center.y = (thisSize?.height)!/2
} else if center.y + (thisSize?.height)!/2 > (superviewSize?.height)! {
center.y = (superviewSize?.height)!-(thisSize?.height)!/2
} else {
resetTranslation.y = 0 //Only reset the vertical translation if the view *did* translate vertically
}
gestureRecognizer.view?.center = center
gestureRecognizer.setTranslation(CGPoint(x: 0, y: 0), in: self.view)
}
}
You'll have to set the recognizer.view.center to a new value only if its frame is inside the bounds of its parent view. Use CGRectContainsRect on recognizer.view.superview.bounds and recognizer.view.frame to verify that they are contained.
If you want to allow the image view to move outside its parent view until the center point of the view is outside the parent's bounds, you can use the convertPoint:toView method of UIView and verify that the new CGPoint is not outside your parent's bounds.
if (gesture.state==UIGestureRecognizerStateChanged){
CGPoint translation = [recognizer translationInView:self.view];
CGRect rectToCheck=CGRectMake(yourView.frame.origin.x+translation.x, yourView.frame.origin.y+translation.y, CGRectGetWidth(yourView.frame), CGRectGetHeight(yourView.frame));
if(CGRectContainsRect(self.view.bounds,rectToCheck))// check that the rect that is going to form lies within the bounds of self.view
{
yourView.frame=CGRectMake(yourView.frame.origin.x+translation.x, yourView.frame.origin.y+translation.y, CGRectGetWidth(yourView.frame), CGRectGetHeight(yourView.frame));
}
[gesture setTranslation:CGPointZero yourView]; // important to set this
}
P.S. Use the gesture state block to initiate, pan, remove. i.e. UIGestureRecognizerStateBegan
UIGestureRecognizerStateChanged
UIGestureRecognizerStateEnded
I want to know how to know which label the user last touched and how to remove that specific label from the view. I know how to change the properties for all labels, but I don't know how to find out which one was last selected.
This is how I add a label to the view.
myNewLabel.text =textField.text;
numberOfLabels++;
myNewLabel.tag=numberOfLabels;
[self.view addSubview:myNewLabel];
[shirtBackgroundView addSubview:myNewLabel];
[myNewLabel addGestureRecognizer:panGestureRecognizer];
[myNewLabel addGestureRecognizer:rotateGestureRecognizer];
[myNewLabel addGestureRecognizer:PinchGestureRecognizer];
myNewLabel.userInteractionEnabled=YES;
myNewLabel.backgroundColor=[UIColor clearColor];
[arrayForLabels addObject:myNewLabel];
Here is how I change the color of all labels.
for(int i=0;i<numberOfLabels;i++)
{
UILabel *tempLabel = [arrayForLabels objectAtIndex:i];
tempLabel.textColor=[UIColor redColor];
}
-(void)labelMoved:(UIPanGestureRecognizer *)recognizer
{
CGPoint translation = [recognizer translationInView:self.view];
recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x,
recognizer.view.center.y + translation.y);
[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
if (recognizer.state == UIGestureRecognizerStateEnded) {
CGPoint velocity = [recognizer velocityInView:self.view];
CGFloat magnitude = sqrtf((velocity.x * velocity.x) + (velocity.y * velocity.y));
CGFloat slideMult = magnitude / 200;
NSLog(#"magnitude: %f, slideMult: %f", magnitude, slideMult);
float slideFactor = 0.1 * slideMult; // Increase for more of a slide
CGPoint finalPoint = CGPointMake(recognizer.view.center.x + (velocity.x * slideFactor),
recognizer.view.center.y + (velocity.y * slideFactor));
finalPoint.x = MIN(MAX(finalPoint.x, 0), self.view.bounds.size.width);
finalPoint.y = MIN(MAX(finalPoint.y, 0), self.view.bounds.size.height);
[UIView animateWithDuration:slideFactor*2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
recognizer.view.center = finalPoint;
} completion:nil];
}
}
Thanks for any suggestions...
For detect UIlabels to capture taps:
label.userInteractionEnabled = YES;
UIGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapRecieved:)];
[label addGestureRecognizer:tap];
[tap release];
//repeat for each additional label
when you touched
-(void) tapRecieved:(UITapGestureRecognizer *)tap{
currentLabel = (UILabel *) tap.view;
[currentLabel removeFromSuperview];
}
You can declare a property in .h class as UILabel *lastSelectedLabel; and in your recognizer
-(void)labelMoved:(UIPanGestureRecognizer *)recognizer{
if(lastSelectedLabel!=nil){
[lastSelectedLabel removeFromSuperview];
lastSelectedLabel=recognizer.view;
}else
lastSelectedLabel=recognizer.view;
}
I think above should work..
Thanks.