How can I determine if two uiviewimages intersect. I want to do an auto snap feature. When the small image intersects with the big image or close to it (Lets says the distance<=x), I want the small image automatically snap(connect) to the big image at the point where they intersect.
CGRect bigframe = CGRectInset(bigView.frame, -padding.x, -padding.y);
BOOL isIntersecting = CGRectIntersectsRect(smallView.frame, bigFrame);
The previous two posters have been on the right track with CGRectIntersectsRect.
BOOL isIntersecting = CGRectIntersectsRect(smallImage.frame, largeImage.frame);
if(isIntersecting){
//Animate the Auto-Snap
[UIView beginAnimation:#"animation" context:nil];
[UIView setAnimationDuration:0.5];
smallImage.frame = largeImage.frame;
[UIView commitAnimations];
}
Basically what this says that if the two images are intersecting, the small image frame snap to the larger image over 0.5 seconds.
You don't have to animate it though; you could just make it instantaneous by removing all code except for smallImage.frame = largeImage.frame;. However, I recommend the animation way.
Hope this helps.
-------EDIT--------
You could use the code:
BOOL isIntersecting = CGRectIntersectsRect(smallImage.frame, largeImage.frame);
if(isIntersecting){
//Animation
[UIView beginAnimation:#"animation" context:nil];
[UIView setAnimationDuration:0.5];
smallImage.center = CGPointMake(largeImage.center.x, largeImage.center.y);
//If you want to make it like a branch, you'll have to rotate the small image
smallImage.transform = CGAffineTransformMakeRotation(30);
//The 30 is the number of degrees to rotate. You can change that.
[UIView commitAnimations];
}
Hope this fixed your problem. Remember to up vote and pick as the answer if this helped.
-------EDIT---------
One last thing. I said that the "30" in CGAffineTransformMakeRotation(30) stood for 30 degrees, but that is incorrect. The CGAffineTransformMakeRotation function takes its parameter in radians, so if you wanted 30 degrees you could do this:
#define PI 3.14159265
CGAffineTransformMakeRotation(PI/6);
You can use the CGRectIntersectsRect method to check for frames:
if (CGRectIntersectsRect(myImageView1.frame, myImageView2.frame))
{
NSLog(#"intersected")
}
Related
I have an image that I am animating in order to make it look as if it is "breathing".
Currently I have the image moving in a decent manner with the following code below: (I am animating a UIView that contains a few UIImageView's, which all move as one)
- (IBAction)animateButton:(id)sender {
[UIView animateWithDuration:0.64
delay:0
options:UIViewAnimationOptionAutoreverse | UIViewAnimationOptionRepeat
animations:^{
_testView.transform = CGAffineTransformMakeScale(1.08f, 1.02f);
} completion:nil];
}
HOWEVER, I can not seem to figure out how to animate stretching the image in the x at a different rate as the y. The point of this is to appear as if the image is actually alive without appearing to cycle through a clear repetitive motion.
I tried by attempting to anchor the center of the UIView to a specific location, then add some number to the width, through an animation of lets say 1.0 seconds.
I then tried to simultaneously call another animation that does the same animation only to the height, with a different amount added, for about 1.3 seconds. I could not get these two to perform at the same time though, as one would take precedence over the other.
If someone could lead me in the right direction as to animating a repetitive stretch of the width and height at different rates I would be most appreciative. Thanks!
Consider that two changes overlapping in time look like this:
|---- change x ---|
|---- change y ----|
If the two intervals are arbitrary and overlapping, the can be represented by three animations: one changing one dimension individually, one changing both dimensions together, and another changing one dimension individually.
You can see that there's numerous ways to specify this, but lets try a straight-forward one. To avoid the arithmetic of compounding scales, lets specify a dimension, a pixel change and a duration. For example...
#[ #{#"dimension":#"width", #"delta":#10, #"duration":0.2},
#{#"dimension":#"both", #"delta":#40, #"duration":0.8},
#{#"dimension":#"width", #"delta":#10, #"duration":0.2} ]
... means a longer change in width straddling a shorter change in height. You can see how this can be a pretty complete language to get done what you want.
We need an animation method that will perform the changes serially. A simple way to do this is to treat the array of actions as a to-do list. The recursive algorithm says: to do a list of things, do the first one, then do the rest....
- (void)animateView:(UIView *)view actions:(NSArray *)actions completion:(void (^)(BOOL))completion {
if (actions.count == 0) return completion(YES);
NSDictionary *action = actions[0];
NSArray *remainingActions = [actions subarrayWithRange:NSMakeRange(1, actions.count-1)];
[self animateView:view action:action completion:^(BOOL finished) {
[self animateView:view actions:remainingActions completion:completion];
}];
}
For the animation, you probably want to use a linear timing curve for the intermediate animations, though I can see you getting more elaborate and change the timing curve at the start and end of the list.
- (void)animateView:(UIView *)view action:(NSDictionary *)action completion:(void (^)(BOOL))completion {
NSString *dimension = action[#"dimension"];
CGFloat delta = [action[#"delta"] floatValue];
NSTimeInterval duration = [action[#"duration"] floatValue];
CGRect frame = view.frame;
if ([dimension isEqualToString:#"width"]) {
frame = CGRectInset(frame, -delta, 0);
} else if ([dimension isEqualToString:#"height"]) {
frame = CGRectInset(frame, 0, -delta);
} else {
frame = CGRectInset(frame, -delta, -delta);
}
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
view.frame = frame;
} completion:completion];
}
If the array of dictionaries is too clumsy to specify (and it is rather general), you could add some convenience methods on top that provide some simpler scheme to the caller and builds the array of more general representation.
I am looking to have an animation in my iOS app which is almost identical to the animation you see when you use Siri when it is displaying possible questions you can ask it.
The effect is an upward scroll of text replaced by more than come from below but the effect is one in a way where not all the questions move as one together, they seem to be independent and follow each other.
I like this animation and would like to emulate it in my app - but I haven't the first idea how to go around this. My only involvement with animations within my apps so far are ones such as CrossDissolve, FlipFromLeft, etc.
Does anyone know of a tutorial which teaches an effect like this, or can point me in the right direction to start?
Thanks to all in advance.
Having a quick look it looks fairly straight forward.
The animation can be broken down into several stages.
First, there are 5 UILabels animated separately. Each with a very short delay on the previous label.
Each label is animated like this...
Set the frame of the label to be low down on the screen and set alpha to 0.0.
Animate the frame of the label to around 300 points higher on the screen and alpha of 1.0 over a duration of around 0.2 seconds.
Animate the frame of the label to about 30 points higher on the screen over about 2 or 3 seconds.
Animate the frame of the label another 300 points higher on the screen and alpha back to 0.0 over about 0.2 seconds again.
Change text on the label and repeat.
I think the easiest way to do this would be with the method...
+ (void)animateKeyframesWithDuration:(NSTimeInterval)duration
delay:(NSTimeInterval)delay
options:(UIViewKeyframeAnimationOptions)options
animations:(void (^)(void))animations
completion:(void (^)(BOOL finished))completion
Lemme give this a try in actual code and get back to you. Code completion helps a lot.
OK, here goes
Darn, I just installed Yosemite and don't have Xcode. OK, I'll give it a try here...
- (void)animateLabels:(NSArray *)labels
{
CGFloat firstLabelStartTop = 600;
[labels enumerateObjectsUsingBlock:^(UILabel *label, NSUInteger idx, BOOL *stop) {
CGFloat delay = 0.1 * idx;
label.frame = CGRectMake(0, firstLabelStartTop + 30 * idx, 320, 21);
label.alpha = 0.0;
[UIView animateKeyFramesWithDuration:2.4
delay:delay
options:0
animations:^{
[UIView addKeyframeWithRelativeStartTime:0.0
relativeDuration:0.1
animations:^{
label.alpha = 1.0;
label.frame = CGRectOffset(label.frame, 0, -200);
}];
[UIView addKeyframeWithRelativeStartTime:0.1
relativeDuration:0.9
animations:^{
label.frame = CGRectOffset(label.frame, 0, -30);
}];
[UIView addKeyframeWithRelativeStartTime:0.9
relativeDuration:0.1
animations:^{
label.alpha = 0.0;
label.frame = CGRectOffset(label.frame, 0, -200);
}];
}
completion:nil];
}];
}
This is a first attempt without Xcode to check my code and without being able to run it at all so it might not be perfect but it should give you an idea of where to go from here.
EDIT
From #WilliamGeorges comment it looks like they used a combination of completely separate animations using the method I detailed in my blog.
You would have to do 3 separate animations on each label but its still a similar idea to what I put in this answer.
I am trying to understand how to get the bookcover open and close animation going in ios. Google search resulted this:
coverimage.layer.anchorPoint=CGPointMake(0, .5);
coverimage.center = CGPointMake(coverimage.center.x - coverimage.bounds.size.width/2.0f, coverimage.center.y);
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1];
[UIView setAnimationDelay:0.1];
coverimage.transform = CGAffineTransformMakeTranslation(0,0);
CATransform3D _3Dt = CATransform3DIdentity;
_3Dt = CATransform3DMakeRotation(3.141f/2.0f,0.0f,-1.0f,0.0f);
_3Dt.m34 = 0.001f;
_3Dt.m14 = -0.0015f;
coverimage.layer.transform =_3Dt;
[UIView commitAnimations];
It works great, but I am finding it hard to understand how it does the CATransform3DMakeRotation. If any direction or resources you have come across please let me know. My main motive is find a way so it reverses the action (Close the cover of the book). I have tried changing the code but didn't work. Thanks in advance.
Download the sample and follow the simple execution of the desired output from library -
Flip Animation
Above library supports 3 interaction modes:
Triggered: as in a tap to flip
Auto: as in a revolving flip that loops through data
Controlled: as in a pan gesture that moves the flip layer according to touch
I've subclassed a UIView as an avatar-object, which contains an icon (UIImageView), name (UILabel) and ID (UILabel). Depending on the orientation X,Y coordinates, I want the icon to be rotated. For example, say orientation.X = 1 and orientation.Y = 1 would give 45 degrees angle. X and Y could be anything between -1 and 1.
I'm not sure how it is calculated mathematically nor the cocoa API calls for it. Any ideas where to start?
for smoothness i added an animation:
- (void)rotateView:(UIView *)view withDuration:(NSTimeInterval)duration andRadians:(CGFloat)radians
{
// Setup the animation
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:duration];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
[UIView setAnimationBeginsFromCurrentState:YES];
// The transform matrix
CGAffineTransform transform = CGAffineTransformMakeRotation(radians);
view.transform = transform;
// Commit the changes
[UIView commitAnimations];
}
EDIT:
for other angles you need to create your own rotation matrix.
How rotation matrix works
Read here how to create a custom affine transformation in Objective-c
Hope this helps.
You need to look into the trigonometric functions - specifically acos and asin.
This article may be helpful.
I have a problem with a UIView-subclass object that I am rotating using Core Animation in response to a UISwipeGesture.
To describe the context: I have a round dial that I have drawn in CG and added to the main view as a subview.
In response to swipe gestures I am instructing it to rotate 15 degrees in either direction dependent on whether it;s a left or right swipe.
The problem that it will only rotate each way once. Subsequent gestures are recognised (evident from other actions that are triggered) but the animation does not repeat. I can go left once then right once. But trying to go in either direction multiple times doesn't work. Here's the relevant code, let me know your thoughts...
- (IBAction)handleLeftSwipe:(UISwipeGestureRecognizer *)sender
{
if ([control1 pointInside:[sender locationInView:control1] withEvent:nil])
{
//updates the display value
testDisplay.displayValue = testDisplay.displayValue + 0.1;
[testDisplay setNeedsDisplay];
//rotates the dial
[UIView animateWithDuration:0.25 animations:^{
CGAffineTransform xform = CGAffineTransformMakeRotation(radians(+15));
control1.transform = xform;
[control1 setNeedsDisplay];
}];
}
CGAffineTransform xform = CGAffineTransformMakeRotation(radians(+15));
Do you keep a total of how far the rotation is. CGAffineTransformMakeRotation are not additive. Only the most recent is used. So you are setting it to 15 each time, not 15 more each time.
Here's a super simple example of rotating a view cumulatively. This rotates the view by 180 degrees each button press.
- (IBAction) onRotateMyView: (id) sender
{
[UIView animateWithDuration:0.3 animations:^{
myView.transform = CGAffineTransformMakeRotation(M_PI/2*rotationCounter);
} completion:^(BOOL finished){
//No nothing
}];
++rotationCounter;
}