Is there a way to find the endpoint of the screen? Let's say a screen of size (100x100) have the midpoint at (50,) and starting point (0,) and the endpoint as (100,). I can hard code to get the end point based on the device screen size, but that would be a too much work based on assumptions.
I am making a custom UIView animation based on UIBezierPath.
Here is what I am trying to do:
As you can see the animation is stopped after it reaches some point.And I want this point to be the end of the screen,so that UIView is covered whole screen. To be more clear, I drag the UIView to point A, and it animates to point B (end point,so B>A)
I am not sure how to calculate B, so that when I drag UIView to A, it animates to the end of the screen (endpoint of the screen).
Here is the code to get better understanding:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.dragView];
if (touchLocation.x<250) {
if (!startBackSlide) {
_circleDragView.touchdragPoint=touchLocation.y;
_circleDragView.dragToPoint=CGPointMake(touchLocation.x+40, touchLocation.y);
[_circleDragView setNeedsDisplay];
_savedPoint=touchLocation;
}else{
//move the top and bot points backwards along with slide
[self animateCOmpleteBezier:touchLocation];
_circleDragView.touchdragPoint=touchLocation.y;
_circleDragView.dragToPoint=CGPointMake(touchLocation.x+54, touchLocation.y);
[_circleDragView setNeedsDisplay];
_savedPoint=touchLocation;
if (touchLocation.x<20) {
startBackSlide=NO;
snapped=YES;
}
}
}
if (touchLocation.x>=250) {
if (snapped) {
snapped=NO;
//move the top and bottom points to the specified point(In this case the end point)
}
}
}
-(void)animateCOmpleteBezier:(CGPoint) value{
[UIView animateWithDuration:0.01 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
_circleDragView.topWidthPoint=value.x-10;
_circleDragView.botWidthPoint=value.x-10;
[_circleDragView setNeedsDisplay];
} completion:^(BOOL finished) {
}];
}
The endpoint of screen is equal to it's width and height:
CGSize screenSize = [UIScreen mainScreen].bounds.size;
CGPoint endPoint = CGPointMake(screenSize.width, screenSize.height);
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIScreen_Class/#//apple_ref/occ/instp/UIScreen/bounds
Related
I'm thinking about a Google Map street view pin drag and drop system on iOS. The user selects a pin from another view (let's say UINavigationBar) and drag it to a position on map and then drop it.
I'm a bit lost with it. Do you have a workflow for this type of interaction ?
It is quite a complex task but it can be divided into a couple of simple steps.
Make a custom UIView, which after touching will follow the touch movement.
Example
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
_originalPosition = self.view.center;
_touchOffset = CGPointMake(self.view.center.x-position.x,self.view.center.y-position.y);
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint position = [touch locationInView: self.view.superview];
[UIView animateWithDuration:.001
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut
animations:^ {
self.view.center = CGPointMake(position.x+_touchOffset.x, position.y+_touchOffset.y);
}
completion:^(BOOL finished) {}];
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint positionInView = [touch locationInView:self.view];
CGPoint newPosition;
if (CGRectContainsPoint(_desiredView.frame, positionInView)) {
newPosition = positionInView;
// _desiredView is view where the user can drag the view
} else {
newPosition = _originalPosition;
// its outside the desired view so lets move the view back to start position
}
[UIView animateWithDuration:0.4
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut
animations:^ {
self.view.center = newPosition
// to
}
completion:^(BOOL finished) {}];
}
When user releases the finger, you will have to get the location of the touch.
Calculate the touch location in map view coordinates and place the pin.
Hope it points you to the right direction.
I've read all the stuff about drag'n'drop and gestureRecognizer but haven't found the solution.
I got "gamefield" 10x10 and I want to implement drag'n'drop with snap to grid and check if element placed on "gamefield".
I got my 8 "TempButtons" added to UIView buttonsSuperView with action:#selector(imageMoved:withEvent:).
- (IBAction) imageMoved:(id) sender withEvent:(UIEvent *) event
{
UIControl *control = sender;
originalPosition = [self getButton:sender];
UITouch *touch = [[event allTouches] anyObject];
point = [touch locationInView:control];
float step = 31.0; // Grid step size.
CGPoint center = control.center;
center.x += step * floor((point.x / step));
center.y += step * floor((point.y / step));
control.center = center;
}
It works, I can move any button with grid step 31px. I can place it everywhere, but I have to put it on UIView fieldView. If it placed right there it's OK and I can replace it on another tile. But if I place it outside fieldView the button should return on its place. Something like this:
if ([self.fieldView pointInside:point withEvent:nil])
{
control.center = center;
} else {
[UIView animateWithDuration:0.4
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut
animations:^ {
control.center = originalPosition;
// to
}
completion:^(BOOL finished) {}];
}
If this code placed on - (IBAction) imageMoved:(id) sender withEvent:(UIEvent *) event method it makes button get back to its "originalposition" all the time its moving. But I need to check if its placed properly only on 'touchesEnded'. But that's another method and I don't understand how to realize which button pressed and its original coords to get back if placed improperly.
Maybe there's a better way to use 'UIView' instead of 'UIButton' but I still don't understand how to do that.
Thanks in advance.
Kind Regards,
Nick
Since no one answered my question I've spent some time and found working solution.
- (IBAction) imageMoved:(id) sender withEvent:(UIEvent *) event
{
dragObject = sender;
originalPosition = [self getButton:sender];
UITouch *touch = [[event allTouches] anyObject];
point = [touch locationInView:dragObject];
float step = 31.0; // Grid step size.
CGPoint center = dragObject.center;
center.x += step * floor((point.x / step));
center.y += step * floor((point.y / step));
dragObject.center = center;
[sender addTarget:self action:#selector(touchesEnded:withEvent:) forControlEvents:UIControlEventTouchUpInside];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (![fieldView pointInside:dragObject.center withEvent:nil])
{
[UIView animateWithDuration:0.4
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut
animations:^ {
dragObject.center = CGPointMake(originalPosition.x + 15.5, originalPosition.y + 15.5);
}
completion:^(BOOL finished) {}];
}
}
Now it works like charm and I can move along. My buttons moving freely snapped to grid and when pleced outside game field they move back to their original position.
Regards,
Nick
I currently have an application where a user takes a photo or chooses from their library.
On the next controller it will show the image that was selected/taken.
What I would like to do now is show a view of some sort on top of the image view. The view would be translucent round the edges and have a circle which would show the image beneath (not transulcent). Basically this is selected a part of the image.
I then need to save some how where the view is on screen, as it should also be moveable by the user.
What is the best way to approach this?
I need an overlay view which can be moved. The circle would be a fixed size always the inside shows the imageview beneath and the outside would be a 0.5 translucency so you can still see the image but not completely. Then to save the location of the moved around circle?
---- EDIT -----
This is the example image I have created.
I have a view which has a photo as the UIImageView (bottom layer). On top of this I am trying to add a view (like the picture above). Note, the picture above is actually a png as suggested. However, this overlay is moveable. The circle is transparent (0) so you can completely see the photo below it. The outer (grey) is transparent partially (0.5) so you can still see just not completely.
The top view (circle part) would be moved around on the photo to mark a specific point on the photo. In this example if the circle is moved the side (grey) ends on screen, therefore I would need to make a huge image which takes into account the moving of the view -- which is not the best way to do this surely?
EDIT 2 ----
I now have one UIImageView over the top of the photoView (another UIImageView). The overlay is 4 times the screen with a circle in the middle of it.
When the item is moved I have a gesture recognizer that runs:
-(void)handlePan:(UIPanGestureRecognizer *)gesture {
NSLog(#"Pan Gesture");
gesture.view.center = [gesture locationInView:self.view];
}
At present from the above the UIImageView is moved from the middle point, that way the circle is what looks to be moving when the finger moves.
That is all great, but how do I implement the suggested answers into my handlePan method. So I need to check that the middle point is not too close the edge. Ideally I would like a 50 margin around the screen so the circle does not look to go completely (or mostly) off screen?
I understand from the question that you know how to do the movement of the overlay, so what I meant is just that you can simply use image views big enough to make sure that their border isn't visible.
Let's say the UIImageView would be called
UIImageView *photoImageView;
And the overlay with translucent and semi-translucent areas would be
UIImageView *imageOverlayView;
The way I see it, you need 3 different images for that imageOverlayView, depending on the device it's running on - 1 for iPad, 1 for iPhone 5 and 1 for other iPhones.
Width of that image should be equal to (screen width - circle radius) * 2, height should
CGFloat circleRadius; //this would be the radius of translucent circle
So if you set the frame of the overlay properly:
CGRect imageFrame = photoImageView.frame;
imageOverlayView.frame = CGRectMake(circleRadius - imageFrame.size.width/2, circleRadius - imageFrame.size.height/2, (imageFrame.size.width - circleRadius)*2, (imageFrame.size.height - circleRadius)*2); //origin is set to the middle of the image.
you'd never see the edge of the grey area. MZimmerman6's answer for implementation of the movement is good, but you should also make sure you block the circle from getting out of the borders of underlying image.
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint new = [touch locationInView:imageOverlayView];
delX = new.x - prevPoint.x;
delY = new.y - prevPoint.y;
CGRect overFrame = imageOverlayView.frame;
overFrame.origin.x += delX;
if (overFrame.origin.x < -imageFrame.size.width) {
overFrame.origin.x = -imageFrame.size.width;
}
else if (overFrame.origin.x > 0) {
overFrame.origin.x = 0;
}
overFrame.origin.y += delY;
if (overFrame.origin.y < -imageFrame.size.height) {
overFrame.origin.y = -imageFrame.size.height;
}
else if (overFrame.origin.y > 0) {
overFrame.origin.y = 0;
}
[overlayView setFrame:overFrame];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint new = [touch locationInView:imageOverlayView];
delX = new.x - prevPoint.x;
delY = new.y - prevPoint.y;
CGRect overFrame = imageOverlayView.frame;
overFrame.origin.x += delX;
if (overFrame.origin.x < -imageFrame.size.width) {
overFrame.origin.x = -imageFrame.size.width;
}
else if (overFrame.origin.x > 0) {
overFrame.origin.x = 0;
}
overFrame.origin.y += delY;
if (overFrame.origin.y < -imageFrame.size.height) {
overFrame.origin.y = -imageFrame.size.height;
}
else if (overFrame.origin.y > 0) {
overFrame.origin.y = 0;
}
[overlayView setFrame:overFrame];
}
EDIT
With your pan gesture recognizer, checking if you aren't going too far needs a little change to the handlePan: method.
-(void)handlePan:(UIPanGestureRecognizer *)gesture {
CGPoint newCenter = [gesture locationInView:self.view];
if (newCenter.x < 50) {
newCenter.x = 50;
}
else if (newCenter.x > self.view.frame.size.width - 50) {
newCenter.x = self.view.frame.size.width - 50;
}
if (newCenter.y < 50) {
newCenter.y = 50;
}
else if (newCenter.y > self.view.frame.size.height - 50) {
newCenter.y = self.view.frame.size.height - 50;
}
gesture.view.center = newCenter;
}
If that 50 points margin is equal to circle radius, this will make sure your circle able to touch the edges of the screen, but unable to go beyond them.
I would first initialize some UIImageView with a png image in it that will easily handle this moving frame with a hole in the center. You can the add this to your screen. Once this is done, use the touchesBegan, touchesMoved and other touch commands to find whether a user is touching that box and from that determine how far the user has moved from the previous point. Use this difference to then add or subtract values from the images current frame origin or center, and voila you have a moving box.
EDIT
In View.h
CGPoint prevPoint;
float delX;
float delY;
UIView *overlayView;
In View.m
-(void) viewDidLoad {
overlayView = [UIView alloc] initWithFrame:CGRectMake(100,100,100,100)];
[overlayView setBackgroundColor:[UIColor clearColor]];
[self.view addSubview:overlayView];
UIImageView *circImage = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,overlayView.frame.width,overlayView.frame.height)];
[circImage setImage:[UIImage imageNamed:#"SomeImage.png"]];
[overlayView addSubview:circImage];
[self.view setNeedsDisplay];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
prevPoint = [touch locationInView:overlayView];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint new = [touch locationInView:overlayView];
delX = new.x - prevPoint.x;
delY = new.y - prevPoint.y;
CGRect overFrame = overlayView.frame;
overFrame.x += delX;
overFrame.y += delY;
[overlayView setFrame:overFrame];
[self.view setNeedsDisplay];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint new = [touch locationInView:overlayView];
delX = new.x - prevPoint.x;
delY = new.y - prevPoint.y;
CGRect overFrame = overlayView.frame;
overFrame.x += delX;
overFrame.y += delY;
[overlayView setFrame:overFrame];
[self.view setNeedsDisplay];
}
I am trying to create an iOS app with blocks floating down the screen(UIViews). I have them floating down the screen but I also want the user to be able to move them on the x axis as they are falling. I tried to do it with the code below but they just fall and don't move left to right. My problem is I am trying to move it with my finger left to right as it is already moving town the screen. How can I adapt the code below to work?
Note: I was able to move the views left to right without them moving down the screen and I was able to move them down the screen without moving them left to right. The problem arises when I combine both.
ANIMATION FOR Y AXIS
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:letView.speed];
[UIView setAnimationDelay:0.0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
letView.layer.frame = CGRectMake(letView.layer.frame.origin.x, [[UIScreen mainScreen] bounds].size.height, letView.layer.frame.size.width, letView.layer.frame.size.height);
[UIView commitAnimations];
ANIMATION FOR TOUCH
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
//Goes through an array of views to see which one to move
for (LetterView * view in _viewArray) {
if (CGRectContainsPoint(view.frame, touchLocation)) {
dragging = YES;
currentDragView = view;
[currentDragView.layer removeAllAnimations];
}
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
if (dragging) {
CGPoint location = touchLocation;
currentDragView.center = CGPointMake(location.x, currentDragView.center.y);
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
dragging = NO;
[self checkForCorrectWord];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:currentDragView.speed];
[UIView setAnimationDelay:0.0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
currentDragView
.layer.frame = CGRectMake(currentDragView.layer.frame.origin.x, [[UIScreen mainScreen] bounds].size.height, currentDragView.layer.frame.size.width, currentDragView.layer.frame.size.height);
[UIView commitAnimations];
}
I've got a demo project that shows you how to make a "boat" animate down the screen in an s-curve, like this:
The solution I use is to make a keyframe animation (actually it's a keyframe animation that forms part of a grouped animation, but you might not need the rest of the grouped animation: it is the keyframe animation that makes the curved path shape). Perhaps you could adapt what I'm doing, modifying it to your own purposes?
The code is available for download here:
https://github.com/mattneub/Programming-iOS-Book-Examples/tree/master/ch17p501groupedAnimation
It is discussed in detail in my book. Keyframe animations generally:
http://www.apeth.com/iOSBook/ch17.html#_keyframe_animation
This particular example:
http://www.apeth.com/iOSBook/ch17.html#_grouped_animations
I wrote the animation concept in viewDidLoad method i wrote:
scaleFactor=2;
angle=180;
CGRect frame = CGRectMake(10,10,45,45);
UIView *box;
box=[[UIView alloc] initWithFrame:frame];
box.backgroundColor=[UIColor colorWithPatternImage:[UIImage imageNamed:#"images673.png"];
[self.view addSubView:box];
// This code is for the touch event of an object in the screen
// For the object movement i wrote the method which is shown below:
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch=[touches anyObject];
CGPoint location=[touch locationInView:self.view];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDelegate:self];
[UICiew setAnimationDuration:1];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
box.center=location;
[UIView commitAnimations];
}
// And then,now i wrote a button which has to navigate to another class file// General navigation principle i wrote
-(IBAction)settings:(id)sender
{
aScreen *abc=[[aScreen alloc]init];
[self.navigationController pushViewController:abc animated:YES];
[abc release];
}
Now the object is moving where i tap on the screen,but when i tap on the button,the image is not placing on the top of the button.What to do.Please help me.I took an image and then I made some animation for it to move till where I tap in the screen. But at the same time, I took a button and I wrote a button event action in viewcontroller. When I tap the button, the image is not moving onto the button.
What I want to do is if I tap the button, the image has to drop onto the button and it should display the next view controller. Can anyone help me in doing so? How to move to the next screen when the image drops onto when I tap the button?
Im not sure i fully understand the problem without seeing your code but cant you do something like this?
-(ibaction)buttonevent:(id)sender{
cgrect frame = image.frame;
frame.origin.x = button.frame.x;
frame.origin.y = button.frame.y;
image.frame = frame;
image.alpha = 0;
[self pushviewcontroller:newViewcontroller animated:yes];
}
hi try this code i have checked. This is working for me when you check for button and the image you are dragging intersect then fire the method where it moves to next screen
// Handles the continuation of a touch.
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
//NSLog(#"touchesMoved");
UITouch *touch = [touches anyObject];
if ([touch view] == mKey) {
NSUInteger touchCount = 0;
// Enumerates through all touch objects
for (UITouch *touch in touches) {
// Send to the dispatch method, which will make sure the appropriate subview is acted upon
[self dispatchTouchEvent:[touch view] toPosition:[touch locationInView:self.view]];
touchCount++;
}
}
}
// Checks to see which view, or views, the point is in and then sets the center of each moved view to the new postion.
// If views are directly on top of each other, they move together.
-(void)dispatchTouchEvent:(UIView *)theView toPosition:(CGPoint)position
{
// Check to see which view, or views, the point is in and then move to that position.
if (CGRectContainsPoint([mKey frame], position))
{
NSLog(#"touchesMoved");
mKey.center = position;
}
if(CGRectIntersectsRect([mKey frame], [inVisible frame]) && k==0)
{
self.view.userInteractionEnabled=NO;
NSLog(#"thirdPiew frame");
[inVisible setHighlighted:YES];
[inVisible setShowsTouchWhenHighlighted:YES];
k=1;
[self performSelector:#selector(modalPresentationButtonPressed:)];
}
}