I have a UIView which is attached to a UICollisionBehavior. I'm trying to animate its center when a new location is tapped on the screen, but it appears using this block of code is not the way to do it:
[UIView animateWithDuration:0.7f
delay:0.0f
options:UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionBeginFromCurrentState
animations:^{
[self.mainCharacter setCenter:location];
}
completion:nil];
Can anyone suggest a more UIKitDynamics friendly way of doing this?
Thanks.
UPDATE
So the first part of my question was similar to the one posted and a possible duplicate, however, although technically it solved the issue in the first part of this question, it does seem to interfere with how collision testing in UICollisionBehavior.
The second part of this question was to ask if there was a better way of doing this. I assumed it would be possible to accelerate a UIDynamicItem at a speed over a given time using UIPushBehavior but it seems to be constant.
Can anyone recommend how to use a UIPushBehavior to do the above?
In UIKit Dynamics, when you want to animate changing the center, you'd add a UISnapBehavior to your UIDynamicAnimator (removing any prior snap behavior first). For example, create a property for the UISnapBehavior, and then your tap gesture recognizer can snap it to that point (honoring your UICollisionBehavior), like so:
- (void)handleTap:(UITapGestureRecognizer *)gesture
{
if (self.snap)
[self.animator removeBehavior:self.snap];
CGPoint point = [gesture locationInView:gesture.view];
UISnapBehavior *snap = [[UISnapBehavior alloc] initWithItem:self.viewToAnimate snapToPoint:point];
[self.animator addBehavior:snap];
self.snap = snap;
}
You can control the "bounciness" by adjusting the damping property of the UISnapBehavior. If you don't like it rotating the view as it's snapping, you can also add a UIDynamicItemBehavior with allowsRotation set to NO.
Related
I am trying to develop something similar. If you are familiar of Facebook Paper, how does it actually achieve this behavior? Specifically, in its main view, there is a UIScrollView located at the bottom which contains lots of UIView of user posts, when you swipe it up, the UIScrollView can take to full screen mode.
I have tried with the following code but it doesn't seem to work well:
- (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer
{
_scaleValue += 1.0f;
CGAffineTransform transform = CGAffineTransformMakeScale(1, _scaleValue);
[UIView beginAnimations:#"whatever" context:nil];
_scrollView.transform = transform;
[UIView commitAnimations];
}
Found it here, it does exactly what I wanted to do.
How would I create a program so a dot starts in the center, and when I click the screen the dot follows where I clicked? Not as in teleports to it, I mean like changes it's coordinates towards it slightly every click. I get how I could do it in theory, as in like
if (mouseIsClicked) {
[mouseX moveX];
[mouseY moveY];
}
And make the class that mouseX and mouseY are have some methods to move closer to where the mouse is, but I just don't know any specifics to actually make it happen. Heck, I don't even know how to generate a dot in the first place! None of those guides are helping at all. I really want to learn this language though. I've been sitting at my mac messing around trying to get anything to work, but nothing's working anywhere near how I want it to.
Thanks for helping a total newbie like me.
If you are going to subclass UIView, you can use the touchesBegan/touchesMoved/touchesEnded methods to accomplish this. Something like:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:self];
//slightly update location of your object with p.x and p.y cgpoints
[self setNeedsDisplay];
}
-(void)drawRect{
//draw your object with updated coordinates
}
You can create a dot and move it around based on taps all within your UIViewController subclass.
Make your dot by creating a UIView configured to draw the way you want - look into CALayer and setting dotview.layer.cornerRadius to make it be round (alternately you can make a UIView subclass that overrides drawRect: to make the right CoreGraphics calls to draw what you want). Set dotview.center to position it.
Create a UITapGestureRecognizer with an action method in your view controller that updates dotview.center as desired. If you want it animated, simply set the property within a view animation call & animation block like this:
[UIView animateWithDuration:0.3 animations:^{
dotview.center = newposition;
}];
You can download the sample code here that will show you general iOS gestures. In particular it has a sample that shows how to drag and drop UIViews or how to swipe them around. The sample code includes both driven and fire-n-forget animations. Check it out, its commented and I'd be happy to answer any specific questions you have after reviewing the code.
Generating a simple circle
// Above Implementation
#import <QuartzCore/QuartzCore.h>
// In viewDidLoad or somewhere
UIView *circleView = [[UIView alloc] initWithFrame:CGRectMake(32.0, 32.0, 64.0, 64.0)];
[circleView setBackgroundColor:[UIColor redColor]];
[circleView.layer setCornerRadius:32.0];
self.view addSubview:circleView];
What I wish to do is to fade-in and fade-out some custom annotation views. In order to do this I need to have the pointers to those views. Have been thinking of collecting these pointers in mapView:viewForAnnotation. But I am not sure if this is the right way.
The reason is since annotation views are set up to be recycled, I worry that they can be detached from their annotations once they are moved out of the screen. So my thinking is, view pointers collected in mapView:viewForAnnotation, may not be reliable since we don't know if they are still on the screen or not.
Hope somebody can suggest a proper way to keep track of these view pointers. Or suggest some other standard or reliable way of fading in and out the annotation views.
Update :
Just found out that viewForAnnotation does work. And I don't really need to keep track of the annotations (at least in this case) if they are on screen or not.
Try this where you get to the zoom that you want to animate the annotationViews:
for (MyAnnotation *annotation in myMapView.annotations)
{
MKAnnotationView *annotationView = [myMapView viewForAnnotation:annotation];
//Do your animation to the annotationView
//Example for fadeOut - fadeIn
[UIView animateWithDuration:0.5 animations:^{
annotationView.alpha = 0.2;
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.5 animations:^{
annotationView.alpha = 1;
}];
}];
}
If you have all kinds of annotationView types and you want to animate just part of them, then you will need to check the type before the animation.
I've searched and saw this question asked before but still haven't found an answer sufficient for my needs.
I have an some UIImageViews in my view. They are stored in a NSMutableArray property called viewArray. However, when I run the following animation code, the UIImageViews just skip to their final state, without any animation. If I change the duration to 10.0, the animation works fine, but that's too long for my purpose.
[UIView animateWithDuration:1.0
animations:^{
for (UIImageView *view in viewArray) {
view.transform = CGAffineTransformScale(view.transform, 1.5, 1.5);
}
}];
These UIImageViews are already in the view since I saw some answers that addSubview is not instantaneous so that's not the problem.
What exactly is going on? Is there something I need to keep in mind in designing animations?
I'm working on a drawing app.
I want the user to be able to "drop" a shape on the screen and then move, resize or rotate it as desired.
The problem is with the rotation. I have the moving and resizing working fine.
I did this before with a rather complex and memory/processor-intensive process, which I am now trying to improve.
I've searched and searched but haven't found an answer similar to what I'm trying to do.
Basically, let's say the user drops a square on the "surface". Then, they tap it and get some handles. They can touch anywhere and pan to move the square around (working already), touch and drag on a resize handle to resize the square (working already), or grab the rotation handle to have the square rotate around its center.
I've looked into drawing the square using UIBezierPath or just having it be a subclass of UIView that I fill.
In either case, I'm trying to rotate the UIView itself, not some contents inside. Every time I try to rotate the view, either nothing happens, the view vacates the screen or it rotates just a little bit and stops.
Here's some of the code I've tried (this doesn't work, and I've tried a lot of different approaches to this):
- (void) rotateByAngle:(CGFloat)angle
{
CGPoint cntr = [self center];
CGAffineTransform move = CGAffineTransformMakeTranslation(-1 * cntr.x, -1 * cntr.y);
[[self path] applyTransform:move];
CGAffineTransform rotate = CGAffineTransformMakeRotation(angle * M_PI / 180.0);
[[self path] applyTransform:rotate];
[self setNeedsDisplay];
CGAffineTransform moveback = CGAffineTransformMakeTranslation(cntr.x, cntr.y);
[[self path] applyTransform:moveback];
}
In case it isn't obvious, the thinking here it to move the view to the origin (0,0), rotate around that point and then move it back.
In case you're wondering, "angle" is calculated correctly. I've also wrapped the code above in a [UIView beginAnimations:nil context:NULL]/[UIView commitAnimations] block.
Is it possible to rotate a UIView a "custom" amount? I've seen/done it before where I animate a control to spin, but in those examples, the control always ended up "square" (i.e., it rotated 1 or more full circles and came back to its starting orientation).
Is it possible to perform this rotation "real-time" in response to UITouches? Do I need to draw the square as an item in the layer of the UIView and rotate the layer instead?
Just so you know, what I had working before was a shape drawn by a set of lines or UIBezierPaths. I would apply a CGAffineTransform to the data and then call the drawRect: method, which would re-draw the object inside of a custom UIView. This UIView would host quite a number of these items, all of which would need to be re-drawn anytime one of them needed it.
So, I'm trying to make the app more performant by creating a bunch of UIView subclasses, which will only get a command to re-draw when the user does something with them. Apple's Keynote for the iPad seems to accomplish this using UIGestureRecognizers, since you have to use two fingers to rotate an added shape. Is this the way to go?
Thoughts?
Thanks!
-(void)rotate{
CGAffineTransform transform;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
[UIView setAnimationCurve:UIViewAnimationOptionBeginFromCurrentState];
myView.alpha = 1;
transform = CGAffineTransformRotate(myView.transform,0.5*M_PI);
[myView setUserInteractionEnabled:YES];
myView.transform = transform;
[UIView commitAnimations];
}
This might help.
for just simple rotation you might leave out the Animation:
-(void)rotate:(CGFloat)angle
{
CGAffineTransform transform = CGAffineTransformRotate( myView.transform, angle * M_PI / 180.0 );
myView.transform = transform;
}
I use a simple NSTimer to control a animation.