How to limit a view panning just inside an other View? - ios

I have a subview (the red bar) laid inside a view. I want to limit the panning area inside the parent view and only absolutely horizontal or vertical. And, of course not outside of the parent view.
I did try some code that handle the panning event, but sometime I can drag the red bar out. Any suggestion?
-(void)handleMoveLineView:(UIPanGestureRecognizer *)recognizer{
CGPoint sPoint= [recognizer locationInView:self.groundView];
CGPoint newCenter = [recognizer translationInView:self.groundView];
NSLog(#"X0 = %f, Y0 = %f", newCenter.x, newCenter.y);
if([recognizer state] == UIGestureRecognizerStateBegan) {
beginX = recognizer.view.center.x;
beginY = recognizer.view.center.y;
}
for (UIView *view in viewArrayGroundView) {
if (CGRectContainsPoint(view.frame, sPoint)) {
//Limit not out side parent view
if (beginX + newCenter.x != view.frame.size.width /2) {
newCenter = CGPointMake(view.frame.size.width /2, beginY + newCenter.y);
}
//Limit top - since the redbar height is 3
else if((beginY + newCenter.y < view.frame.origin.y + 3)){
newCenter.y = view.frame.origin.y + 3;
}
//Limit bottom
else if((beginY + newCenter.y > view.frame.size.height - 3)){
newCenter.y = view.frame.origin.y - 3;
}
}
}
[recognizer.view setCenter:newCenter];
NSLog(#"X = %f, Y = %f", newCenter.x, newCenter.y);
}

Related

How to pinch google map when it set in UIScrollView in iOS Objective C

I set Google Map in view in UIScrollView. everything OK but i can not pinch my map. How to fix it?
Salaam Reza jaan.
In your case you can use something like this. Cheers.
Edit: this is a better way to do it. Behbakht shid, direh inja :P
- (void) scaleSelfWith:(UIPinchGestureRecognizer *)gestureRecognizer{
if ([gestureRecognizer numberOfTouches] >1) {
//getting width and height between gestureCenter and one of my finger
float x = [gestureRecognizer locationInView:self].x - [gestureRecognizer locationOfTouch:1 inView:self].x;
if (x<0) {
x *= -1;
}
float y = [gestureRecognizer locationInView:self].y - [gestureRecognizer locationOfTouch:1 inView:self].y;
if (y<0) {
y *= -1;
}
//set Border
if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
xDis = self.bounds.size.width - x*2;
yDis = self.bounds.size.height - y*2;
}
//double size cause x and y is just the way from the middle to my finger
float width = x*2+xDis;
if (width < 1) {
width = 1;
}
float height = y*2+yDis;
if (height < 1) {
height = 1;
}
self.bounds = CGRectMake(self.bounds.origin.x , self.bounds.origin.y , width, height);
[gestureRecognizer setScale:1];
[[self layer] setBorderWidth:2.f];
}
}

Add boundaries to a UIPangesture

I have a UILabel in a subview and I have a panGesture and pinchGesture on the UILabel. As of right now I can move the UILabel crossed all views. I want this UILabel do stay within the area of the subView. How would I accomplish this?
- (void)handlePanGesture:(UIPanGestureRecognizer *)panGesture {
CGPoint translation = [panGesture translationInView:panGesture.view.superview];
if (UIGestureRecognizerStateBegan == panGesture.state ||UIGestureRecognizerStateChanged == panGesture.state) {
panGesture.view.center = CGPointMake(panGesture.view.center.x + translation.x,
panGesture.view.center.y + translation.y);
[panGesture setTranslation:CGPointZero inView:self.view];
}
}
In this line,
CGPoint translation = [panGesture translationInView:panGesture.view.superview];
It is setting it to the superView and I am trying to set it to my subView but I can't seem to figure it out.
Here is my code to handle draggable button and restrict it to the main view boundary
I hope this code will help you
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:CGPointZero inView:self.view];

how to add vertical gesture in xcode 5

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.

UIButton PanGesture goes out of screen

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];
}

Moving UIView within Parent UIView (UIPanGestureRecognizer)

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

Resources