Perform Multiple UIKit Operations Without Drawing

So I have a series of UIKit changes (these are being done on the main thread, per Apple's requirement). These changes are not being done in an animation. The relevant code snippet is here:


let transitionCenter = self.view!.superview!.convert(self.view!.center, to: fullscreenController!.view)
self.view!.transform = CGAffineTransform(rotationAngle: CGFloat(self.fullscreenAngle))
self.view!.center = transitionCenter
  
// Sometimes the screen is rendered in here, before the view is added
  
self.fullscreenController!.view.addSubview(self.view!) 


Occasionally, the screen is being updated in between some of the changes. This produces a fairly noticeable artifacts. I've tried to use CADisplayLink to make sure that this is being done before the frame is rendered, but with no luck. I've also tried wrapping these lines of code in a explicit CATransaction, but still no luck.


Is there a way that I can force UIKit to not render these changes until all of them are made? I know that I cant stop rendering of the screen, as that is handled by the window server if I understand correctly.

Replies

What happens if you do it in this order:


let transitionCenter = self.view!.superview!.convert(self.view!.center, to: fullscreenController!.view)
self.fullscreenController!.view.addSubview(self.view!)  
self.view!.transform = CGAffineTransform(rotationAngle: CGFloat(self.fullscreenAngle)) 
self.view!.center = transitionCenter


As an aside, I'm not sure if what you'e doing is … I dunno … supported, recommended, something like that. It's unusual to move a view into another controller's view hierarchy (fullscreenController's) without also moving the view's view controller into the controller containment hierarchy of the other controller. (Assuming that 'self' is a view controller in this code.)

The order doesn't seem to matter. It does feel a little odd to move the view into a new view controller. My goal here is to make an inline video player (based off of AVPlayer) fullscreen. The player is then in landscape while the rest of the app remains in portrait. So far, the only way I have been able to achieve this was to move the video player to a new window on top of the other window, which does seem janky.


self is not a view controller in this code snippet, but an object that is responsible for controlling the fullscreen behavior for the video player.

Hmm, well, what kind of artifacts are you seeing? Do they suggest anything about what is causing them?


Is there a solution where you don't have to change the view hierarchy at all? Roughly, I'm thinking of a root view controller that has two child view controllers, one for the non-full-screen content (including an empty placeholder view for where the video goes), and another for the player itself, positioned on top of the placeholder view when not in full screen "mode". That way, going full-screen would just be a transform for the actual player view, with no structural change.


That sort of configuration does seem more normal. The root view controller manages the screen real estate assigned to its child view controllers, and the child view controllers pass their assigned bounds on to the child views.

>The player is then in landscape while the rest of the app remains in portrait.


This forum typically indicates a mac application...what platform are you building for?


If iOS, that would be the cocoa touch forum, I believe.


In that case, I'd start by checking theiOS HIGs. It's one thing to co-mingle orientations, but it's another when one of the elements is a player.

I have accidentally posted this in the wrong forum, I'm trying to make an iOS app. The problem with this design is that the video player's view controller has a landscape orientation, while the background stays in portrait. This creates an effect like in the YouTube app where the player rotates into fullscreen, but the background is still visible.


The artifact that I'm seeing is that the player is absent for a single frame. The code above I posted should result in no visual change to the user (animation is done a bit later). I'm not entirely sure what is causing the artifact, but the screen appears to be updating before all of the operations are complete, and thus the player is missing for a single frame. After some more testing from the OP, it appears that the window is made key but is not rendering for a frame.

You said UIKit, so I knew you were on iOS. 🙂


It does sound like changing the view hierarchy (removing the player view from one place and adding it to another) is going to take it off the screen temporarily.


Rotating the player view shouldn't be a problem, if it has its own view controller, because you can control the orientation at the individual view controller level. You should be able to control what screen real estate this view controller claims/occupies, separately from what the background view controller does.


>> the player rotates into fullscreen, but the background is still visible


That can't be literally true, because a fullscreen player would obscure all of the background (unless the player is partially transparent). Do you mean the player rotates into landscape, which obscures much more of the background than in portrait?

This is the animation I are running: https://gfycat.com/ShortAlarmedKingbird

As you can see, when the animation finishes the screen goes black for a few frames, which I think is actually an issue with UIWindow and would best be asked in the Cocoa Touch forum.