Objective-C: Issue with CGRect .frame intersect/contains - objective-c

I have two UIImageViews located about center of a horizontal screen and when the user clicks a button another UIImageView, located off screen, slides in from the right. I'm am just trying to detect when the view being brought onto the screen collides with the two static views. The problem is when I run my code and check the CGRect frames they are returned from where the views start, not end, regardless of where I place the frame calls in my method or even if I place them outside the method in a separate one. I'm a bit new to Obj-C and I understand that Core Animation runs on a separate thread and I am guessing that is why I am getting the starting values. (Correct me if I am wrong here).
So, I guess the question here is how do I detect collisions when one item is static and another is animated. Here's my code (feel free to clean it up):
- (IBAction)movegirl
{
//disabling button
self.movegirlbtn.enabled = NO;
//getting graphics center points
CGPoint pos = bushidogirl.center;
CGPoint box1 = topbox.center;
CGPoint box2 = bottombox.center;
//firing up animation
[UIView beginAnimations: nil context: NULL];
//setting animation speed
[UIView setAnimationDuration:2.0 ];
//setting final position of bushidogirl, then resetting her center position
pos.x = 260;
bushidogirl.center = pos;
//running animations
[UIView commitAnimations];
//playing gong sound
[self.audioplayer play];
//enabling button
self.movegirlbtn.enabled = YES;
[self collisiondetection: bushidogirl : topbox];
}
- (void)collisiondetection:(UIImageView *)item1 : (UIImageView *)item2
{
CGRect item1frame = item1.frame;
CGRect item2frame = item2.frame;
NSLog(#"Item1 frame = %d and Item 2 frame = %d", item1frame, item2frame);
}

How about:
if (CGRectIntersectsRect(item1frame, item2frame))
{
// collision!!
}

Related

iOS 8.0.2 : UIView frame animation not working when UINavigationController contained inside RootViewController

I've created a RootViewController / RootView that:
Handles the content layout for the app
Exposes and interface for performing application level behaviors, like presenting the "hamburger" menu or overlay views with CAKeyframe animations.
This is in accordance with good practice.
The Problem:
When the main content view presents a form, there's a utility to animate the frame of that view, when a field is selected that would otherwise be obscured by the keyboard. This has been working fine all the way up until iOS 8.0.2
On iOS 8.0.2 the frame for the form will no longer animate if you set a negative value for origin.y. Instead of going from the current origin.y to the required origin.y it jerks down by the amount it was supposed to move, then animates back to 0.
If I present the form outside of the RootVC it works correctly.
What I've tried:
Checked that RootView is not doing anything in layout subviews to prevent the animation. (In iOS8.0 it was. I removed this and problem was solved. Only to return in iOS8.0.2)
Checked the BeginFromCurrentState flags.
Instead of animating the form view, animate [UIScreen mainScreen].keyWindow. Works but causes some other side effects that I don't want.
Question:
What has changed with animation of UIViewControllers that are contained in another view in iOS8.0.2. It seems to be something very fundamental.
The code that animates frame to move input fields out the keyboard's way:
Looks something like this:
- (void)scrollToAccommodateField:(UIView *)view
{
UIView *rootView = [UIApplication sharedApplication].keyWindow.rootViewController.view;
CGPoint position = [view convertPoint:view.bounds.origin toView:rootView];
CGFloat y = position.y;
CGFloat scrollAmount = 0;
CGFloat margin = 25;
CGSize screenSize = [self screenSizeWithOrientation:[UIApplication sharedApplication].statusBarOrientation];
CGSize accessorySize = CGSizeMake(_view.width, 44);
CGFloat maxVisibleY = screenSize.height - [self keyboardSize].height - accessorySize.height - margin;
if (y > maxVisibleY)
{
scrollAmount = maxVisibleY - y;
CGFloat scrollDelta = scrollAmount - _currentScrollAmount;
_currentScrollAmount = scrollAmount;
[self scrollByAmount:scrollDelta];
}
else
{
if (_currentScrollAmount != 0)
{
_currentScrollAmount = 0;
[UIView transitionWithView:_view duration:0.30
options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseOut animations:^
{
_view.frame = [_view bounds];
} completion:nil];
}
}
}
Update:
I've since installed TPKeyboardAvoiding pod and its working very well. . leaving this open, in case its of interest to others.

UIView animation not working with addSubview

I have an iPad app that is displaying a "note" (subclassed UILabel) with text on it. In order to navigate to the next note, I'd like it to slide it off the screen to the left while having the next one slide in from the right. I can get either animation to work, but not both at the same time.
Here's the code in my controller:
- (void)slideOutLeft {
// create the new note
flSlidingNote *newNote = [[flSlidingNote alloc] init];
newNote.text = #"blah blah";
CGRect newFrame = CGRectMake(1000, 70, 637, 297); // off the right
newNote.frame = newFrame;
[self.view addSubview:newNote];
// slide off the current one
CGRect currentFrameEnd = noteLabel.frame; // noteLabel is the existing note
currentFrameEnd.origin.x = 0 - noteLabel.frame.size.width; // off the left
[UIView animateWithDuration:1.0 animations:^{
noteLabel.frame = currentFrameEnd;
} completion:nil];
}
noteLabel does not animate at all. If I comment out the addSubview:newNote part it does. I'm still relatively new at this, so it's probably just something simple.
The problem happens whether newNote is animated or not (not animated in the code snippet).
You want to put the animation for both your views and the addSubview call for your new view in one animation block, like so:
// layout the new label like the old, but 300px offscreen right
UILabel * newNote = [[UILabel alloc] initWithFrame:CGRectOffset(self.noteLabelView.frame, 300, 0)];
newNote.text = #"NEW NOTE";
[UIView animateWithDuration:2.0f
delay:0
options:UIViewAnimationCurveEaseInOut
animations:^{
// animate the old label left 300px to offscreen left
self.noteLabelView.center = CGPointMake(self.noteLabelView.center.x-300, self.noteLabelView.center.y);
// add the new label to the view hierarchy
[self.view addSubview:newNote];
// animate the new label left 300px into the old one's spot
newNote.center = CGPointMake(newNote.center.x-300, newNote.center.y);
}
completion:^(BOOL finished) {
// remove the old label from the view hierarchy
[self.noteLabelView removeFromSuperview];
// set the property to point to the new label
self.noteLabelView = newNote;
}];
In this snippet above, I'm assuming the old label is addressable via the property self.noteLabelView.
(Also have a look at https://github.com/algal/SlidingNotes , though I can't promise that will stay there long so maybe SO isn't the right format for such a link? )
Adding to what Gabriele Petronella commented, here is a good resource on KeyFrames and AnimationGroup, with a sample GitHub project linked:
http://blog.corywiles.com/using-caanimationgroup-for-view-animations
This really helped me understand animations better.
not sure but i've seen other code that loops through subviews and performs animations, you may want to try the following:
for(UIView *view in self.subviews)
{
// perform animations
}

Animate center point of a view along a quadratic curve

I have an app that stores user events in history. The events are added on one controller and are displayed in a controller within a different tab.
I would like to add a visual confirmation that an event has been recorded when a user taps "save button". I'm thinking of animating an interface element to move towards a tab bar controller that is responsible for showing records to the user.
In order to do so, I'm thinking of animating the center point of one of my interface elements. I know how to animate the center point, but it does so in a straight line. How can I animate the center point in a more "curved" way? Is there some way to accomplish this?
CGPoint center = self.ratingReticle.center;
[UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationCurveEaseIn animations:^{
//move the element offscreen
self.ratingReticle.center = CGPointMake(260,500);
} completion:^(BOOL finished) {
//hide the interace element once it is offscreen
self.ratingReticle.alpha = 0;
//restore the position of the interface element
self.ratingReticle.center = center;
[ UIView animateWithDuration:0.4 animations:^{
//fade the element back at the original position
self.ratingReticle.alpha = 1;
} completion:^(BOOL finished) {
}];
}];
You could that using Core Animation to move your object along a Bezier curve using CAKeyFrameAnimation.
-(void)animate
{
CAKeyframeAnimation *posAnim = [CAKeyframeAnimation animationWithKeyPath:#"position"];
posAnim.path = [self bezierPath];
[image.layer addAnimation:posAnim forKey:#"posAnim"];
}
where bezierPath returns a CGPathRef that suits your case.

Programmatically resize NSView

I have a main view that is supposed to display several subviews. Those subviews are directly above and below one another (in the z axis) and will drop down (in the y axis) and move up using this code:
if (!CGRectIsNull(rectIntersection)) {
CGRect newFrame = CGRectOffset (rectIntersection, 0, -2);
[backgroundView setFrame:newFrame];
} else{
[viewsUpdater invalidate];
viewsUpdater = nil;
}
rectIntersection is used to tell when the view has entirely moved down and is no longer behind the front one (when they no longer overlap rectIntersection is null), it moves down by 2 pixels at a time because this is all inside a repeating timer. I want my main view, the one that contains these two other views, to resize downward so that it expands just as the view in the background is being lowered. This is the code I'm trying for that:
CGRect mainViewFrame = [mainView frame];
if (!CGRectContainsRect(mainViewFrame, backgroundFrame)) {
CGRect newMainViewFrame = CGRectMake(0,
0,
mainViewFrame.size.width,
(mainViewFrame.size.height + 2));
[mainView setFrame:newMainViewFrame];
}
The idea is to check if the mainView contains this background view. When the backgroundView is lowered, the main view no longer contains it, and it (should) expand downward by 2 pixels. This would happen until the background view stopped moving and the mainView finally contains backgroundView.
The problem is that the mainView is not resizing at all. the background view is being lowered, and I can see it until it disappears off the bottom of the mainView. mainView should have resized but it does not change in any direction. I tried using setFrame and setBounds (with and without setNeedsDisplay) but nothing worked.
I'm really just looking for a way to programmatically change the size of the main view.
I think I understood, what the problem is. I read carefuly the code.
if (!CGRectIsNull(rectIntersection)) {
// here you set the wrong frame
//CGRect newFrame = CGRectOffset (rectIntersection, 0, -2);
CGRect newFrame = CGRectOffset (backgroundView.frame, 0, -2);
[backgroundView setFrame:newFrame];
} else{
[viewsUpdater invalidate];
viewsUpdater = nil;
}
rectIntersection is actually the intersection of the two views, that overlap, and as the backgroundView is moved downward, that rect's height decreases.
That way the mainView gets resized only one time.
To add on this, here is a simple solution using block syntax, to animate your views, this code would typically take place in your custom view controller.
// eventually a control action method, pass nil for direct call
-(void)performBackgroundViewAnimation:(id)sender {
// first, double the mainView's frame height
CGFrame newFrame = CGRectMake(mainView.frame.origin.x,
mainView.frame.origin.y,
mainView.frame.size.width,
mainView.frame.size.height*2);
// then get the backgroundView's destination rect
CGFrame newBVFrame = CGRectOffset(backgroundView.frame,
0,
-(backgroundView.frame.size.height));
// run the animation
[UIView animateWithDuration:1.0
animations:^{
mainView.frame = newFrame;
backgroundView.frame = newBVFrame;
}
];
}

iOS/Objective-C: transitionWithView custom animation block resizes view immediately, not over duration

The following code is a method I created inside a UIViewController to popup/down a "reader" overlay on top of the controller's own view. The intention is for the reader to begin as transparent, size zero, at a specific point. "Popup" is then animated as increasing in opacity and size, and shifts towards an application frame central position. "Popdown" is subsequently animated as the reverse, shrinking back whilst moving toward a specified location, fading out.
The popup code works exactly as desired. However, the popdown version (i.e. code executed if isPopup == NO) immediately changes the bounds rather than doing so gradually. Thus the popdown animation shows from the beginning a 1 pixel square view moving towards its destination and fading out.
-(void)popupReader:(BOOL)isPopup from:(CGPoint)loc {
CGFloat newAlpha = 0.0f;
CGPoint newCenter = CGPointZero;
CGRect newBounds = CGRectZero;
CGRect appFrame = [UIScreen mainScreen].applicationFrame;
CGSize readerSize = [self viewSize];
if (isPopup) {
newAlpha = 1.0f;
newCenter = CGPointMake(appFrame.origin.x+appFrame.size.width/2,
appFrame.origin.y+appFrame.size.height/2);
newBounds = CGRectMake(0,0,readerSize.width,readerSize.height);
[self.view setAlpha:0.0f];
[self.view setCenter:loc];
[self.view setBounds:CGRectMake(0, 0, 0, 0)];
} else {
newCenter = loc;
newBounds = CGRectMake(0,0,1,1);
}
const CGFloat animDur = 0.3f;
[UIView transitionWithView:self.view
duration:animDur
options:UIViewAnimationOptionTransitionNone|UIViewAnimationOptionCurveEaseOut
animations:^{
self.view.alpha = newAlpha;
self.view.center = newCenter;
self.view.bounds = newBounds;
}
completion:nil];
}
I've already tried animating just the frame, rather than bounds and center, but the result was identical.
Does anyone know why this is happening, and how I can overcome this problem?
Many thanks for your time.
from the docs:
UIViewAnimationOptionTransitionNone -
An option for specifying that no transition should occur.
try one of:
UIViewAnimationOptionTransitionFlipFromLeft
UIViewAnimationOptionTransitionFlipFromRight
UIViewAnimationOptionTransitionCurlUp
UIViewAnimationOptionTransitionCurlDown
Edit:
Or if you're just looking to animate those values, try
[UIView animateWithDuration:(NSTimeInterval)duration
animations:(void (^)(void))animations
completion:(void (^)(BOOL finished))completion];