Animate UIView setFrame to force drawRect on each animatable frame - iphone

I've got a UIView with a UILabel on top. I have the UILabel's content mode set to 'UIContentModeLeft'. As expected, when I animate the frame of the UIView to be smaller than the original size, the label 'jumps' to the final frame without animating nicely.
As far as I can see, UIContentModeRedraw does not force 'drawRect' to be called on every 'animated frame'. I've tried using a custom CALayer as well but can't seem to cause the frame to resize smoothly.
Is there any way to do this? The animation as it stands is extremely glitchy. UIContentModes are not useful and I can't use a frame for contentStretch as well as none of the edges of the label can be stretched. What I really need is a 'refresh' of the label every time the parent view resizes.

There's no way of doing this unfortunately, so I've learnt. The only other way is to actually run a timer that updates the frame every time it's invoked. This results in a very jerky animation given a resize of a complex view is time consuming. I ended up achieving the same thing with some pre-rendered onscreen elements and a whole lotta 'magical effects' behind the scene.

Related

Using drawRect stretches during orientation change

I have a tableView. Instead of having multiple subviews in each tableViewCell , i have added one main subview which draws each of the other subviews in its drawRect method.
(I have read somewhere that this makes scroll animation look better. Also apple has a sample project CustomTableViewCell).
First , problem is when i changes the orientation of device, then drawRect does not call automatically. And each tableviewcell appears to be stretced.
I solved this by using
mainView.contentMode = UIViewContentModeRedraw
This solves the problem. Now when the orientation change is done, drawRect is called automatically .
But during the orientation change, the animation of rotating view still shows each tableview cell stretched. It is a very small thing, but still it is noticeable. Can anyone suggest something on this ?????
You can't redraw during animation (not easily, anyway).
Split the table cell into components again and setup autoresizing correctly. The animation will then animate only component positions and it will look fine.
Where did you read drawRect: would make scroll animation better? Did you have some problems with scrolling animation?
Edit:
IMHO There is no way how to fix resizing animations and keep the performance increase from using drawRect: instead of subviews.

Synchronizing EAGLView presentation with frame resize on iPhone

I have an EAGLView which I am resizing in an animation, with the animation driven by an NSTimer that calls a draw function. As I resize the EAGLView, I need to adjust the projection for the view to maintain the aspect ratio of the contents. The draw function looks like this:
gameView.frame = newFrame;
[gameView setFramebuffer];
[self updateProjection];
/* Drawing to the EAGLView, gameView, here, then... */
[gameView presentFramebuffer];
Run like this, though, the contents of the EAGLView appear to "stair-step" down the animation. When I record it and look at it frame by frame, it's clear that the projection is adjusted, then the view is resized a very short time later (less than one animation frame).
I suspect that the reason is that the change in the frame of gameView is being deferred, and that in the meantime the updated framebuffer is making its way to the screen. I've tried using CATransactions to get the frame update to take effect immediately, but as I kind of expected for a UIView change, that did nothing. I suppose I could modify the viewport and leave the EAGLView full-frame, but I worry that that might just leave me with synchronization issues elsewhere (say, with updates to any overlaid CALayers).
Does this seem like a reasonable assessment of the problem? How can I prevent it -- that is, how can I best ensure that the framebuffer presentation coincides with the change in the actual frame of the EAGLView (and other CA elements)?
Thanks!
I encountered a similar issue with a custom EAGLView I wrote. The problem was that when changing orientation, the view got resized and the contents stretched, and only after the animation, the scene with the right proportions was displayed.
I think yours is the same problem, and I don't think you can force CoreAnimation to wait for your view to update before rendering an animation frame, because of the way it works (CA isn't aware of the drawing mechanism of the view or the layer on which operates).
But you can easily bypass the problem: open you xib file containing the view, switch to the attributes inspector on the right. Select your EAGLView (the same applies to GLKView), and under the section View there's the Mode attribute. If you're creating the view programmatically, set the contentModeproperty.
This value describes how the view contents are managed during an animation. Until the buffer is displayed, the old scene gets resized according to that mode; perhaps you can find a mode that fits the animation you need to achieve.
If you're worried about proportions, the center content mode may work, but the part of scene that hasn't been rendered yet will appear empty during the animation.
Unfortunately the redraw mode won't necessarely make your EAGLView refresh: the view is actually redrawn, but potentially with the old contents of the color buffer. It's a problem of getting the buffer filled at the right time.
You could try to resize and prerender a frame big enough to cover the whole animation before starting it; or you could try to render a frame to an UIImage, replace the view on the fly, animate it, the place the EAGLView back, but this may seriously affect performance.
The way I solved my issue was making simply the EAGLView big enough.
Regarding the blending of other CALayers, as far as I tried, I encountered no synchronization issue; the EAGLView updates when it can, and the other layers too. Just set the right properties to CAEAGLLayer if you're using alpha channel, and rememeber that blending the layers every time OpenGL updates your scene may be expensive in terms of performance.

How do you create an animation like the iBooks app's moving bookmark?

When you tap the bookmark, it slides down or up smoothly. As it slides up, it disappears as if behind the view directly above it. I know how to animate changing the frame of a view, but I don't know how to make it disappear like that. (I don't want to resize the UIImage, just slide the UIImageView up and out of sight.)
I figure I need an invisible button to toggle the animation, and an UIImageView to animate. Do I need to change the bounds of the UIImageView, or should I use the frame? I thought I could just change the height from X to 0, but it didn't seem to resize the UIImageView. I had a little luck with settings the bounds with clipping subview's enabled, but I wasn't quite there.
I don't think I understand the relationship between the bounds and the frame.
I ended up adding a parent UIView to contain the UIImageView. It has the dimensions in which I want the UIImageView to be viewable in, and then I just animate the frame so the Y dimension is equal to the negative height and it slides up nicely.
I was on the wrong track with the bounds.

Border image on UIView

I want to have a UIView subclass that has a border image, but I don't want or care about this 'new' frame/bounds around the border image itself.
What I wanted to do was just use drawRect and draw outside of the rect but all drawing is clipped and I don't see a way to not clip drawing outside of this context rect.
So now I have added a sublayer to the views layer, set [self clipsToBounds] on the view and override setFrame to control my sublayers frame and always keep it at the proper size (spilling over the views frame by 40px).
The problem with this is that setFrame on a uiview by default has no animation but seTFrame on a calayer does.
I cant just disable the animations on the calayers setFrame because if I were to call setFrame on the uiview inside a uiview animation block the calayer would still have its animation disabled.
The obvious solution is to look up the current animationDuration on the uiview animation and set a matching animation on the sublayer, but I don't know if this value is available. And even if it is, I'm afraid that calling an animation from within another animation is wrong.
Unfortunately the best solution is to not use a calayer at all and just add a uiview as a subview and draw into that just like I am drawing into my layer, and hope that with autoresizingMask set to height and width that everything will 'just work'. Just seems like unnecessary overhead for such a simple task.
My solution would be to override the initWithFrame: to add the surrounding border pixels and contain the content in a subview. It probably is unneccesary overhead but definietly the "cocoa" route. It's probably going to be easier in the end too since a subview structure will allow you to edit the content seperatly from the border so you dont have to redraw the border when you redraw the content. And keeping them seperate simply makes sense from a OOP perspective.
The clipsToBounds route is probably the easiest route besides the subview structure but managing the border and content in one drawing cycle and in one object will probably be a lot more work so it'll be worth the overhead.
Excuse any typos, typed this from my iPhone.

How can I stop the iPhone from displaying a transform change until after the screen is redrawn

I have found the UIScrollView's zooming mechanism to be clunk and essentially unusable. So instead, I'm rolling my own. I have a UIView that resizes itself with the pinch-zoom, and that's working fine. When the zoom is complete, the view needs to reset its transform and redraw the images.
The zoom works essentially in the same way the UIScrollView does. It sets the transform property of the UIView until complete. Then, when the zoom finishes, I want to reset the transform to CGAffineTransformIdentity, resize the frame to be the size it was before, and tell the view to redraw itself at the new size.
It all works pretty well, except when I change the transform to identity then redraw the image, there is a slight flicker before the image completely redraws. This is due to the fact that I'm using a subclass of CATiledLayer, since the view can be of arbitrary size.
I've overridden the fadeDuration to be zero, but there is still a flicker while the transform is reset before the redraw is finished. Is there any simple way to overcome this without creating another view to draw with then replacing it?
Problem solved using a lower-level approach to layers.