I have a UITextView that changes it's frame with the animateWithDuration:animations method:
[UIView animateWithDuration:1.5 animations:^{
[_textView setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - keyboardSize.height-25)];
}];
Is there any callback that helps me track the height of the UITextView as it animates?
There is no accurate way.
That's because the frame is just set directly. The animation takes care of the transition, but actually there is no transition.
There are some ways of estimating what is the current frame size and for me, the best is the simple math solution using a timer, when the animation started and the animation duration.
But, again, it's probably for the best if you just go another way, as this is certainly going to impact on your code cost and precision.
It's my first post and I don't really know anything that well, just learning and trying to help.
This depends on what you want to do with this thing.
If you want somehow accurate information about your frame, use the presentationLayer. This is a semi-accurate representation of what's actually on the screen. Note that this is in the coordinates of the view (bounds), so you need to convert it to the superview's coordinate system to get the current frame.
CGRect currentTextViewFrame = [_textView.superview convertRect:[_textView.layer.presentationLayer frame] fromView:_textView];
Note however this will be about one drawing loop or more off. If you are trying to base another animation off this it may be problematic and can cause flickering or other delay-induced effects. Also, at least the official documentation says this may not always be very fast and you may want to make the animation yourself if you need this information often due to performance reasons.
[_textView.layer.presentationLayer frame].size.height;
Credit belongs to this anwser.
Related
Im trying to make an animation of falling object that goes up when you touch the screen. That is not a problem if i want to use a linear velocity for this object, but i would better like it if it accelerated towards ground and when user touches screen it starts accelerating to the opposite direction. So lets suppose we have an object that goes 10px/s towards ground and when user touches screen i want it to have a = -5px/s^2 which means that even after touching screen, the object would still go down for another 2 seconds. Any idea how to do this in a "nice way" (right now im rewriting UIImageViews.frame every time with new CGRect but thats not really good way to do it i guess)?
Thanks
You can always use UIView animations:
[UIView animateWithDuration:1.0
delay:0.0 options:UIViewAnimationCurveEaseIn animations:^{
// put the co-ordinates you want your object to FINISH on in here
}
completion:^(BOOL finished){
}];
Any idea how to do this in a "nice way" (right now im rewriting
UIImageViews.frame every time with new CGRect but thats not really
good way to do it i guess)?
Use Core Animation. It's very easy to get started, and very powerful once you've gotten started. You can specify your own timing function, so you can give the appearance of acceleration. There's no reason for you to redraw your image view manually... Core Animation will do this for you more easily, and better.
Hope there are some GLKViewController experts out there because I have some problems :)
Just a quick description of my app. I have a UINavigationController in which I push different screens.
At some point, I get to my game screen which is a subclass of UINavigationController. In this screen, in viewDidLoad I manually create a EAGLContext, GLKView and instantiate a new GLKViewController (to handle my update&draw calls).
I am setting a preferred fps of 30.
The problem is that the first 3-4 update calls come with the correct DT, but then I have 2-3 frames with 1 second between them. I measure the DT using controller.timeSinceLastUpdate.
So I get like:
dt=0.33
dt=0.33
dt=0.33
dt=1.07
dt=1.05
dt=0.33
dt=0.33
After this, I get valid only DT times. I have no idea why those frames have that kind of delay. I measured the time it takes me in the update & draw method, and it's nowhere near 1 second.
Also, I'm not loading any textures/creating any geometry. Everything is done at loading since it is a rather small game.
Also, if I pop the game screen controller and then push back another instance of the game screen, this new GLKViewController will only call my update method aproximately every 1 second.
Did anybody have a problem with the framerate when using GLKViewController?
Thanks,
The problem is that you don't know what else the device is doing between your refreshes :)
You might only spent 0.1s working on the next frame but if there is a memory warning then other bits of your app will also take time to process. I guess that the gl controller will do it's best to keep to the preferred frame rate but if lots is going on in the background then there's not much it can do about it.
As long as you make sure that your code is rendering as fast as possible and isn't spiking in the same way as the framerate then it's not your render path. From your question it sounds like you've already tested that.
The other thing you might want to do is to watch out for other notifications that might be passed into your app (i.e. memory warnings).
Finally, is there a pattern to the slow frames - do they coincide with a new image being loaded or a file access? Have you done as much as possible beforehand? EDIT - rereading your question makes me think that you've already done this, sorry!
Sorry I can't be any more use :(
Ok, so I finally figured it out. It turns out that it's not even related to the GLKViewController (surprise surprise!).
It had something to do with the way I'm displaying the game screen view controller, like this:
GameAreaViewController* gameController = [[GameAreaViewController alloc] init];
[UIView beginAnimations:#"animation" context:nil];
[self.navigationController pushViewController: gameController animated:NO];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.navigationController.view cache:NO];
[UIView setAnimationDuration:0.7f];
[UIView commitAnimations];
SAFE_DEL(gameController);
If I use an animation duration of 0.3f, then I don't get any lag. At 0.5f sometimes I get it and at 0.7 I was always getting it.
I still don't get it why Apple discourages the old method of doing animations and instead says to use blocks.
I mean, how does one realistically stop using the old way? Aren't blocks iOS > 4.0 only? Is one supposed to fill the code with ifs and make two different implementations based on the current device's system version? And why do so since the old method works just fine? Plus the underlying implementation should be the same, right? Is there any reasoning behind this aside from the fact that begin/commit produces ugly code?
The old method works fine, but I think with blocks you have the option to have a completion block. Where as with the old way, the animation begins and the code immediately resumes execution. So something like the following sets the alpha of the view only after the animation to move the frame has completed (in this case nested animation blocks). Once the alpha animation finishes, it then removes the view from the superview.
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationCurveEaseOut animations:^(void) {
CGRect frame = self.actionView.frame;
self.actionView.frame = CGRectMake(frame.origin.x, 370, frame.size.width, frame.size.height);
}
completion:^(BOOL finished) {
[UIView animateWithDuration:0.2 delay:0 options:0 animations:^(void) {
[self.blockingView setAlpha:0];
} completion:^(BOOL finished) {
[self.actionView removeFromSuperview];
[self.blockingView removeFromSuperview];
}];
}];
you would have to use [respondsToSelector] to determine if the UIView supports the block method, if not use the old way, and you'd probably have to be creative with timing to reproduce nested animations.
I still don't get it why Apple
discourages the old method of doing
animations and instead says to use
blocks.
Apple wants you to use the latest and greatest techniques. Apple will optimize all it's new iOS releases for the block based animations and probably will add new possibilities only to the blocks based animations. So thats why Apple is pushing you to the block based animations.
I mean, how does one realistically stop using the old way? Aren't blocks iOS > 4.0 only?
Yes, blocks are iOS > 4.0 only. So if your App is designed for iOS 4.0+ only you can use block based animations. Or you could check for the availability of blocks and add the specific animation only for the iOS 4.0+ devices.
Completely stop animating the old way is only realistic if you drop support for iOS 3.
Is one supposed to fill the code with ifs and make two different implementations based on the current device's system version? And why do so since the old method works just fine? Plus the underlying implementation should be the same, right? Is there any reasoning behind this aside from the fact that begin/commit produces ugly code?
Well, if the old method is okay for you and you want to support older (iOS 3) devices. Just use the old way of animating. There's nothing wrong with it, don't put unnecessary if-statements in your code. It only makes things complicated and you win nothing by doing it.
If your App is iOS 4 go with blocks, it's shorter and somewhat cleaned. It also should be easier to maintain, because Apple will not keep updating the old way of animating.
(You always can add the if-statements somewhere in the future if there will be animations you only can do with blocks, and then fallback to another less complex animation with the old methods. But thats something for the future.)
I would love if someone could give me a short breakdown on what's the best way in terms of memory usage for animating UIImageViews (translation, without sprites).
More specifically, I need to animate multiple objects on screen at the same time (let's say up to 15-20);
Also, I have to be able to interrupt the animation due to collision between some of these objects.
The kind of animation I need is a simple translation. If it's possible, I would concat this translation with rotations and scalings (secondary).
I'd prefer not to use OpenGL because I think that this kind ow work doesn't require it.
Thanks guys.
CoreAnimation can do this handily. The code below will animate the translation of a view. It's also possible to stop the animation half-way and get its current state for feeding into your collision detection algorithm, but you'll have to read up a bit on Core Animation for that.
[UIView beginAnimations:nil context:nil];
view.center = CGPointMake (view.center.x + 50, view.center.y);
[UIView commitAnimations];
I have a block of UIView animation code that looks like this:
[UIView beginAnimations:#"pushView" context:nil];
[UIView setAnimationDelay:0];
[UIView setAnimationDuration:.5];
[UIView setAnimationDelegate:self];
[UIView setAnimationWillStartSelector:#selector(animationWillStart)];
view.frame = CGRectMake(0, 0, 320, 416);
[UIView commitAnimations];
The code basically mimics the animation of a ModalView presentation and is tied to a button on my interface. When the button is pressed, I get a long (.5 sec) delay (on iPod Touch...twice as fast on iPhone 3GS) before the animationWillStart: actually gets called. My app has lots going on besides this, but I've timed various points of my code and the delay definitely occurs at this block. In other words, a timestamp immediately before this code block and a timestamp when animationWillStart: gets called shows a .5 sec difference.
I'm not too experienced with Core Animation and I'm just trying to figure out what the cause of the delay is...Memory use is stable when the animation starts and CoreAnimation FPS seems to be fine in Instruments. The view that gets animated does have upwards of 20 total subviews, but if that were the issue wouldn't it cause choppiness after the animation starts, rather than before? Any ideas?
Try it with a single subview or with no subviews at all to make sure the delay is not caused by so many children.
Profile the code in Instruments to see where exactly the code lags. You might get down to some internal Core Animation function call that will hint you what’s going on.
Try the code without the “lot that’s going on” to make sure you’re not stepping on Core Animation’s toes with your other code.
Or, in short: experiment and measure, because conjectures seldom work when optimizing.
In your pasted block, you specify the selector animationWillStart (no colon), but later in your question, you refer to animationWillStart: (with colon). These selectors are not equivalent, so is it possible that your intended selector is never being called on account of this animation, and is being called 0.5 seconds later on account of some other animation?