AVCaptureVideoPreviewLayer cropping when resizing without animation - swift

Problem: When changing frame of AVCaptureVideoPreviewLayer sometimes can see how image slowly changing it size.
Goal: Resize AVCaptureVideoPreviewLayer without cropping image (When setting the frame, immediately redraw the content, without middle state redrawings).
I created a method for easy resizing without animation and middle state redrawing.
But sometimes it doesn't work and an animation of slowly changing image size appears.
Example of problem:
Initial state Frame is not set yet.
Problem state The frame is set, but the image does not fit in it (I think because of CATransaction).
Result state Image fits within layer boundaries.
By default .videoGravity = .resizeAspectFill
But in this example before I setting frame (calling applyFrameToPreviewView method) I setting .videoGravity = .resize
Thanks

Related

Animate UIView setFrame to force drawRect on each animatable frame

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.

Animation while changing the content mode for fixed view size

I am developing an iPhone application. I have an UIImageView whose size is fixed to 320x480. Initially contentmode is set to AspectFit. When I change the content mode to Aspect Fill, I would like to show the animation (Drawing frame of the image changes, UIImageView frame being fixed). How do I do this?

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.

Changing UIWebView frame without changing content size

I'm trying to animate a UIWebview being removed from the screen. I'm using an animation block to set the frame height to 0. That works fine, the problem is the content size of the web view immediately takes the new frame height. So the content disappears and the background animates off. How can I stop that from happening? Here's my animation block.
// Change frame height.
[UIView animateWithDuration:1.0f
animations:^ {
// Animate the frame to the full height
self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, 0);
}
];
Thanks
So if you want the content to remain where it is, you'll probably have to 'cheat' this.
Apple do this themselves on many transitions - if you go into slow animation mode on the iOS simulator, or on Mac OS you can see how it works. Unfortunately a UIWebView is very limited in scope for customisation...the only property that controls scaling is the scalesToFit value.
A different approach would be to capture the UIWebView as an image, replace the webview with that image (to the user this is seamless), and then perform the animation on the image itself. Since you're just changing the frame of a straight forward image you then won't run into any of these problems (you can also change the animation effect: if you image scales to fit the frame the content will be 'squeezed', or you can just have it cropped).

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.