Drag an UIImageView in a restricted range - iphone

How is it possible to drag a UIImageView but only within a certain area of the screen? My code currently looks like this:
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [[event allTouches] anyObject];
touch.view.frame = CGRectMake(104, 171, 113, 49);
if([touch view] == toggle)
{
CGPoint location = [touch locationInView:self.view];
CGPoint newLocation = CGPointMake(toggle.center.x, location.y);
toggle.center = newLocation;
NSLog(#"%f \n",toggle.center.y);
}
}
I want to be able to drag the image only within the frame i have defined.

You can use CGRectContainsRect(rect1, rect2) to check if the first rect is completely inside of the second
bool CGRectContainsRect (
CGRect rect1,
CGRect rect2
);
When you are using UIViews and want to see if one view falls completely within the frame of a second, a related function CGRectContainsRect will do the checking for you. This does not check for an intersection; the union of both rectangles must be equal to the first rectangle for this to return true. The function takes two arguments. The first rectangle is always the surrounding item. The second argument either falls fully inside the first or it does not.
So your code could be something like this
CGPoint location = [touch locationInView:self.view];
CGPoint newLocation = CGPointMake(toggle.center.x, location.y);
CGRect r = CGRectMake(newLocation.x-self.frame.size.width/2,
newLocation.y-self.frame.size.height/2,
self.frame.size.width,
self.frame.size.height);
if(CGRectContainsRect(r, theOtherRect)){
toggle.center = newLocation;
NSLog(#"%f \n",toggle.center.y);
}
Other useful CoreGraphics functions: http://blogs.oreilly.com/iphone/2008/12/useful-core-graphics-functions.html
Another hint:NSLog(#"%#", NSStringFromCGPoint(toggle.center)) makes logging of CGTypes easier. use equivalently: NSStringFromCGRect(rect)

if (newLocation.y > NSMaxY(touch.view.frame)) newLocation.y = NSMaxY(touch.view.frame);
if (newLocation.y < NSMinY(touch.view.frame)) newLocation.y = NSMinY(touch.view.frame);
toggle.center = newLocation;
You can do the same for the x coordinate if you like.

Related

How to connect two buttons( dots) with a line in iOS? [duplicate]

This question already has answers here:
draw line between two points in iphone?
(3 answers)
Closed 9 years ago.
I want to make a project in which I have to touch one dot and connect it with another dot and after connect it to another dot. When I connect one dot with another dot the line will create between them.
Actually when I click/ touch one dot The line will show and When I touch second dot the line will create between the two dots.
I am not able to do this yet, I am trying and searching on the net but unable to find the solution yet.
This is my need Like this one https://play.google.com/store/apps/details?id=zok.android.dots&hl=en
I think this is done by UIGesture Recogniser? Or is this something else? How I can achieve this?
Any Idea or suggestions from experts would be highly welcome.
Modify this code according to your requiements
CGContextRef context = UIGraphicsGetCurrentContext();
UIColor *currentColor = [UIColor blackColor];
CGContextSetStrokeColorWithColor(context, currentColor.CGColor);
CGContextSetLineWidth(context, 2.0);
CGContextBeginPath(context);
CGContextMoveToPoint(context, touchStart.x, touchStart.y);
CGContextAddLineToPoint(context, touchEnd.x, touchEnd.y);
CGContextStrokePath(context);
#Nisha:
Make gloabal instances of CGPoint touchStart and touchEnd and get them like this:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
touchEnd = CGPointZero;
touchStart = CGPointZero;
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:self];
NSLog(#"start point >> %#",NSStringFromCGPoint(point));
touchStart = point;
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:self];
touchEnd = point;
[self setNeedsDisplay];
}
You can store the touched locations in two different CGPoint with the help of the touchedEnded method.
Then, when you have your two points, you can add a new UIView as subview which is aware of the two CGPoint and will draw a line in its drawRect method. Or do it in the current view, by calling [view setNeedsDisplay] to trigger its own drawRect method.
Check out this link.
If it is possible for you please get the coordinates of two button with UI touch methods. You can find the touched locations in two different CGPoint with the help of the touchedEnded method.To find touch location documentation is here
After getting the location of UIButtons on your view you can draw the line between then with this method-
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextSetStrokeColorWithColor(context, [[UIColor blackColor]CGColor]);
CGContextSetLineWidth(context, 1.0);
CGContextMoveToPoint(context, startPoint.x, startPoint.y);
CGContextAddLineToPoint(context, endPoint.x, endPoint.y);
CGContextStrokePath(context);
CGContextRestoreGState(context);
}
Hope this helps
Try below steps.
Create one subclass of UIView. Add your UIButtons on it.
Implement Touches delgates, like touchesBegan, moved, end.
Inside touchesBegan check if touch isinsideview:myButton1 then make a flag true.
EDIT:
UITouch *touch = [[UITouch alloc] init];
touch = [touches anyObject];
CGPoint point = [touch locationInView:self];
if(CGRectContainsPoint(myButton1.frame, point))
NSLog(#"Inside myButton1");
Another way to test if subview is hit by touches is
CGPoint pt = [[touches anyObject] locationInView:self.view];
UIView *touchedView = [self.view hitTest:pt withEvent:event];
inside touches moved check if flag true then drawline()... and keep checking if touches are in insideview:myButton2. call setNeedsDisplay.
Now you will get number of ways and sample code to draw line in UIView. Just apply above logic.

TouchMoved and wrong screen range? or Bug in iOS?

I found interesting bug in iOS, but trying to belive that i'm wrong. You have to do 2 things:
1) Create single-view template for iOS
2) Write small function in ViewController.m :
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch* touch = [touches anyObject];
CGPoint point = [touch locationInView:[touch view]];
NSLog(#"%#", NSStringFromCGPoint(point));
}// so u can detect points of your touch
So if u try to move finger on display from screen's top to bottom (portrait mode) - you get points in range [-5.5 .. 469]... i can't explain this, it happens only on device, in simulator it works fine.
SOME DEBUG INFO:
with status bar and NO wantsFullScreenLayout range is: [-25.5 .. 449]
with status bar and YES wantsFullScreenLayout range is: [-5.5 .. 469]
without status bar and NO/YES FullScreenLayout the range is: [-5.5 .. 469]
with status bar and NO wantsFullScreenLayout view.frame is (0, 20, 320, 460) and view.bounds is (0, 0, 320, 460)
with status bar and YES wantsFullScreenLayout view.frame is (0, 0, 320, 480) and view.bounds is (0, 0, 320, 480)
without status bar and NO/YES FullScreenLayout view.frame is (0, 0, 320, 480) and view.bounds is too (0, 0, 320, 480)
Please, help to explain this stuff, it happens only on devices...
Because the status bar is out of limits of the view. And you gets negative values when you touch on status bar.
Try this:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch* touch = [touches anyObject];
CGPoint point = [touch locationInView:[touch window]];
NSLog(#"%#", NSStringFromCGPoint(point));
}
I found this from one of Apple's tutorials on a finger-painting program:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGRect bounds = [self bounds];
UITouch* touch = [[event touchesForView:self] anyObject];
firstTouch = YES;
// Convert touch point from UIView referential to OpenGL one (upside-down flip)
location = [touch locationInView:self];
location.y = bounds.size.height - location.y;
}
Looks like you need to convert the touch to OpenGL coordinates to get the result you are expecting. Hope this helps.
The view of root viewController always acts like portrait mode. You should insert a new view inside of the root one. And this new view will acts correctly, will give right size and coordinates according to Apple says.
for example ;
UIView *v = self;
while ([[v superview] superview] != NULL) {
v = [v superview];
}
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:v];
touchPoint will be the correct one.

Adding UIImageView Objects in UIView to NSMutableArray

I believe I may be dealing with some view issues which are not allowing me to detect and add UIImageView objects to an array. I could really use some suggestions.
I've got a number of UIImageViews with images linked to a UIView that sits on top of a UIViewController (the UIView was added to help with drawRect and some additional advantages). So, when I touch an image and 'drag and drop' it, I want to add that image to an array upon being dropped.
My touchesBegan gets the location of the touch and checks UIImageView is being touched and then centers on that view as follows:
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:self]; //can't use self.view in a UIView, this may be causing issues?
startLocation = location; // for reference as needed
NSLog(#"Image x coord: %f", location.x);
NSLog(#"Image y coord: %f", location.y);
if ([touch view] == obiWan_Block)
{obiWan_Block.center = location;}
else if ([touch view] == r2d2_Block)
{r2d2_Block.center = location;}
else if ([touch view] == you_Block)
{you_Block.center = location;}
}
Then, I drag the UIImageView around with touchesMoved and finally, 'drop' the image with touchesEnded. When the UIImageView is drop in a certain area of the screen, I 'snap' it to a specific location. It's at this point I want to place this UIImageView into an array, but I'm having no luck. I believe I'm getting confused on the various views being touched and what's getting added via addObject to my NSMutableArray. Or, I could be missing something completely. Here's my touchedEnded method:
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:self];
UIView *temp = [touch view];
UIImageView *currentImageView = (UIImageView *)[touch view]; //DON'T THINK THIS IS RIGHT
NSLog(#"Current Image View is: %#", currentImageView);
if ((location.x > dropZone.origin.x) && (location.y >= dropZone.origin.y) && ([touch view] != NULL))
{
CGRect frame = temp.frame;
if (touchCount == 0) {
frame.origin.x = 15;
frame.origin.y = 180;
temp.frame = frame;
[quoteArray addObject: currentImageView];
touchCount++;
}
else if (touchCount == 1) {
frame.origin.x = 70;
frame.origin.y = 180;
temp.frame = frame;
[quoteArray addObject: currentImageView];
touchCount++;
}
....
I have an NSLog statement to check if addObject is working as follows:
NSLog(#"the quote array contains %d items. Contents = %#",[quoteArray count], quoteArray);
The log always says:
the quote array contains 0 items. Contents = (null)
Please advise and thanks!
Your last part of code shows that you have uninitialized quoteArray. Check code when you create it, I guess you missed something in your init method. Because if array was correct then NSLog should show below:
NSArray *quoteArray = [NSArray array];
NSLog(#"%#", quoteArray);
2011-11-17 17:37:00.506 TestApp[1382:207] ( )

How to draw a resizable polygon in iPhone?

I have drawn the polygon by using the Core Graphics. But I can't able to resize the polygon. I used UIBezierPath to draw Polygon. This is my code
CGPoint gestureStartPoint,currentPosition;
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
currentPath = [[UIBezierPath alloc]init];
currentPath.lineWidth=1;
xx1 = 30;
yy1 = 30;
xx = 30;
yy = 30;
CGPoint gestureStartPoint,currentPosition;
}
return self;
}
- (void)drawRect:(CGRect)rect {
if(drawColor==nil){
[[UIColor redColor]setStroke];
[currentPath stroke];
}
else {
[drawColor setStroke];
[currentPath stroke];
}
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
gestureStartPoint = [touch locationInView:self];
currentPosition.x = xx;
currentPosition.y = yy;
xx = gestureStartPoint.x;
yy = gestureStartPoint.y;
[currentPath moveToPoint:(currentPosition)];
[currentPath addLineToPoint:(gestureStartPoint)];
[self setNeedsDisplay];
}
This is the link of the sample resizable Polygon. How to draw the polygon with the resizable property like this? I don't know where to start to make a resizable polygon.
This is more complicated than simply invoking some CoreGraphics magic.
To simply duplicate the logic on the site you linked to, I'd start by breaking down the problem:
Two types of gestures are recognized: taps, and tap-hold-drag.
Tap should add an x,y (point) to a list of points you are storing and redraw.
Tap-hold-drag should use the x,y location of the user's tap to determine the closest vertex - and you should probably do some max distance check as well. Once you've determined which vertex the user is "dragging", you can manipulate that point in your list and redraw.

Setting anchor point for UIView layer

I have a UIView subclass that I want to be able to move around within it's superview. When the user touches the UIView somewhere outside self.center but within self.bounds it "jumps" because I add the new location to self.center to achieve the actual move. To avoid this behavior I'm trying to set an anchor point that lets the user grab and drag the view anywhere within it's bounds.
My problem is that when I calculate the new anchor point (as shown in the code below) nothing happens, the view doesn't change position at all. On the other hand, if I set the anchor point to a precalculated point I can move the view (but then of course it "jumps" to the precalculated point). How come this doesn't work as expected?
Thanks.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
// Only support single touches, anyObject retrieves only one touch
UITouch *touch = [touches anyObject];
CGPoint locationInView = [touch locationInView:self];
// New location is somewhere within the superview
CGPoint locationInSuperview = [touch locationInView:self.superview];
// Set an anchorpoint that acts as starting point for the move
// Doesn't work!
self.layer.anchorPoint = CGPointMake(locationInView.x / self.bounds.size.width, locationInView.y / self.bounds.size.height);
// Does work!
self.layer.anchorPoint = CGPointMake(0.01, 0.0181818);
// Move to new location
self.center = locationInSuperview;
}
As Kris Van Bael pointed out, your going to need to do the anchor point calculations in the touchsBegan:withEvent: method in order not to negate the movement. Additionally, since changing the layer's anchorPoint will move the view's initial position, you have to add an offset to the view's center point to avoid a 'jump' after the first touch.
You can do this by calculating (and adding to your view's center point) the offset based on the difference between the initial and final anchorPoints (multiplied by your view's width/height) or you could set the view's center to the initial touch point.
Something like this perhaps:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint locationInView = [touch locationInView:self];
CGPoint locationInSuperview = [touch locationInView:self.superview];
self.layer.anchorPoint = CGPointMake(locationInView.x / self.frame.size.width, locationInView.y / self.frame.size.height);
self.center = locationInSuperview;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint locationInSuperview = [touch locationInView:self.superview];
self.center = locationInSuperview;
}
More info on anchorPoint's from apple's docs here and a similar SO question I referenced here.
You should update the anchorpoint only on TouchBegin. If you recalculate it all the time (TouchMoved), it is logical that the subview doesn't move.