UICollectionView clipping on rotation, fixed as soon as you scroll - ios

I’m using a UICollectionView to display three cells vertically, which each contain a UIView. It looks something like this:
If I rotate the device, it ends up looking like this:
I’m using AutoLayout to rotate the collection view, everything seems to be working properly, but when I rotate (this can be from portrait to landscape, or landscape to portrait), the collection view seems to clip its cells. If I turn on the view debugger at this point, it renders it perfectly there, like this:
As soon as I touch the collection view (i.e. scroll it slightly), the issue is fixed, and from then on it renders properly until I rotate again.
The issue occurs on both simulator and device, and when changing from any orientation to any other. It only clips until the collection view is touched, at which point it fixes itself.
I’ve tried lots of things already, replacing the YouTube views here with regular UIViews, manually calling scrollViewDidScroll: on the collection view after I rotate (and before), telling the collection view to reload its data, reload items, turning off clip or mask to bounds, invalidating the auto-resizing constraints, just about everything obvious that I can think of.
What’s puzzling me the most is the view debugger – everything there is perfect, it’s just when it renders out on-screen that it’s clipping. This issue occurs across the board, on all devices, phone and pad. There’s nothing in the view debugger hierarchy that looks like it’s overlapping them. Everything’s where it’s supposed to be, even if I break at the broken point and print frames, etc., it’s just clipping when it renders somehow.
Anyone have any suggestions?

Related

How to correctly animate change of size of a paged UICollectionView

I have an iPad app similar to the iPad Keynote with a narrow overview on the left and a paged UICollectionView of my "slides" on the right. The collection view is using the default FlowLayout. Some of these slides are standard PDFs and some are embedded UIViewControllers that have been scaled (with a CGAffineTransform) and embedded in the cell. I'd like to smoothly animate the overview sidebar offscreen and zoom the current page cell to fullscreen. The collection view should allow paged swiping at whatever size. I'm using storyboards and autolayout.
I think I need to simultaneously animate about three things:
The collection view constraints (to the sidebar) to enlarge/shrink it
The flow layout's sizeForItemAt: value
The CGAffineTransform on the embedded view controller.
I have some pieces working (a single embedded View Controller "slide" that scales correctly) but cannot get the collectionView/cell resize dance to work correctly. The cell resize animation is jerky, or ends up with the wrong offset, or works for the leftmost cell but not for other cells.
I've tried most of the suggestions in the answers to this question but with no convincing success. I can't believe it's impossible but at this point I'm considering the smoke and mirrors approach of animating a static slide and hiding it after the animation completes. The attached video - ignoring the glitches - illustrates the kind of effect I'm after:
It's worth noting, on close inspection, that Keynote cheats somewhat when it comes to swiping between slides in edit mode, and manually manages the next slide sliding onscreen, so probably doesn't use a UICollectionView.
Has anyone done anything similar, or have any suggestions for things to try?
I managed to solve this. There's a proof-of-concept GitHub repo here.
There are a few moving parts:
There are two pieces of UIView scaling code. I suspect these could be combined with suitable delegate references as the nested view controllers are embedded. The first piece scales (statically) correctly when the Collection View cell is created. The second is an animated scale/translate when the sidebar size is changed.
I added a FlowLayout subclass to remove flicker as the collection's layout is invalidated during scaling.
The sidebar-related transform in the top-level VC uses most of the tricks in the book - invalidateLayout(), performBatchUpdates(...), layoutIfNeeded() etc. as well as animating the contentOffset to the correct value. Some manual tracking of the correct page/slide is required.
There's still a slight flicker occasionally at the start of resizing. This may not be an issue with my particular colour-scheme which will be black on dark gray. Bonus points if anyone can suggest how to track this down or alleviate it.

UITextView after CATransform3D: scrolling all out of whack

So I have a UITextView, and in viewDidLoad I rotate its layer so it appears to be slanted back into the screen (sort of like the Star Wars opening crawl).
The problem is that scrolling is all messed up. Dragging up will scroll for a bit, then jump backward or similar; on the simulator it will even crash sometimes with an error about a coordinate containing NaN.
Similarly, when I try to automatically scroll the UITextView via [UIView animateWithDuration:...] I also get unexpected skips, jerks, etc.
I assume this has something to do with the fact that I've manipulated the layer, but the touch events as well as the animations are registered on the view... Or something like that?
Anyway, I'm pretty stumped.
Are you using constraints to position the text view? There seem to be issues with using transformations and constraints together. A common workaround seems to be to wrap the offending item in another view. The big issues are on iOS7, but some applies to iOS8 as well. This link discusses the issues which may be your issue:
How do I adjust the anchor point of a CALayer, when Auto Layout is being used?

Finer grained UIView rotation in a UIViewController

I have a UIViewController that overlays controls on a view presenting what the camera sees. I have a couple of scenarios I would like to allow.
For the iPad, I want to keep the controls on the right most edge of the device, by your right thumb, no matter what the device's rotation. The controls should rotate their content so that their top is always upwards (away from the ground). I don't want the camera view to rotate at all, because that would just be silly – its position & size should stay the same and its contents shouldn't rotate either.
For the iPhones, I want to keep the controls at the bottom of the device's screen, by to the home button, wherever the home button actually is. The controls should rotate their content so that up is always pointing upwards. Again, I don't want the camera view's frame or content to take part in any view rotation animation at all.
I'm using auto-layout.
I'm wondering if there is any way to describe some or all of this in a storyboard. In particular, it'd be great to be able to describe that some view positions need to autorotate (ie, the controls, on iPad), but that other views don't (the camera view).
A question from 2011 indicates this wasn't possible at the time, but perhaps things have moved on since then? If it's not directly supported, can you suggest an approach and are there some sensible places to be hooking in to autorotation to achieve this?
Ok, this isn't quite a complete answer, but I tried a few things which look promising.
First, you can create a separate set of constraints for portrait vs. landscape using the size specifiers: landscape is w Regular, h Any; portrait is w Any, h Regular (I think -- double-check these) This is accessible via the pop-up control in the bottom-center of the storyboard view. By installing different constraints for portrait and landscape, it should be possible to scale the width and height of your controls' container view so it appears to be in a constant position w.r.t. device orientation; in other words, the container doesn't actually counter-rotate -- it scales so it effectively looks like it has counter-rotated.
I got this close to working. It looks like it's doing the correct thing in the storyboard view, but when I actually run it, I get debug messages about conflicting constraints. Not sure how to fix this, but maybe play with the constraint priorities? That sometimes helps.
A second thing I (partially) tried was creating a custom container view class which counter-rotates itself to the correct position based on the device orientation (in the UIDevice class). You implement this by overriding layoutSubviews. For each orientation, you define a transform which puts it in the correct position, and set the view's transform property.
Another possible solution is to override updateConstraints in your view controller and add/remove constraints to position/scale your container to the correct place for each orientation.
For all of these, the idea is that you "force" the container to be in the correct place, but leave the subviews (the actual controls) alone. The controls should do the right thing if their constraints are independent of the specific orientation of the container view.
So, those are some ideas anyway... if they lead you to an actual solution, could you post it? I anticipate having a need for this myself.

Problems rotating in the middle of a pan with UIViewPageController-based slide show

I have an image slide-show viewer that uses a UIPageViewController to present the images.
The image-view viewer ViewController is pretty simple -- a top-level view containing a UIScrollView containing a UIImageView. On initial image presentation or when the device is rotated the image is aspect-fitted to the view dimensions and centered. It works fine except for a problem which happens on both iOS 7 and iOS 6.
If I am in the middle of panning to change images and two images are on the screen and I then rotate the device it sometimes (maybe always?) messes up the display of one or more images. The previously-centered image appears in the wrong place on the screen and this persists when rotated and zoomed.
The only thing I can find wrong when this happens is that the center property of the UIImageView is not, in fact, the center of the frame. If I change the center property of the UIImageView in viewDidAppear to be the center of the possibly-scaled UIImageView then the images seem to display correctly in all cases.
Does this sound like the effect of some familiar mistake that I'm making?
Edit to respond to the question:
I don't do anything in the willRotate or didRotate methods.
In viewDidLayoutSubviews I aspect-fit the image into the current UIScrollView bounds (which is the full top-level view which is the full screen) and center it. This takes care of both the initial presentation and rotations. I don't see any problems in "normal" rotation situations. The problem occurs only when I rotate with two of the pageViewController's children views both partly onscreen at once. I can "fix" the problem in all cases but surely I'm doing something wrong.
Edit 2
I've discovered another anomaly that occurs less frequently when rotating the device while panning with 2 images onscreen. Best explained by an example:
The page view controller is being used to display one image in a sequence of images from left to right of A B C. Image B is onscreen. During a pan to the left you see part of both images A and B. If the pan to image A is nearly complete, i.e. B is nearly offscreen, and you rotate the device then image B normally ends up onscreen (it never rotates still showing the partial pan), but sometimes image C ends up being displayed -- as though you had panned in the other direction. Anybody else see this kind of behavior?
What are you doing in your UIViewController to prepare for the rotation?
– willRotateToInterfaceOrientation:duration:
And then how do you recover once the rotation has finished?
- didRotateFromInterfaceOrientation
These calls are provided specifically so you have a chance to get ready for a rotation, and then to put everything back to normal once it completes.

Artifacts after orientation change

My app consists of 2 screen (main and settings) both are filled with scrollview completely. Each has one view controller and is supposed to support landscape and portrait orientations. I'm using Autosizing to achieve that and it works fairly well (all elements are where they should be, size is also correct) but I'm getting strange artifacts when the screen is rotated e.g. picker frame remains the same when the actual "drum" area inside is resized properly, text field is partially overlapped by background, landscape graph remains in place and is overlapped by portrait graph.
All are just basic elements without modifications, there are no images or anything special (graph is exception, I'm reloading it in didRotateFromInterfaceOrientation:). Any ideas why would that happen, why aren't the basic elements redrawn properly?
Figured it out myself in the end. Had to implement workaround as iOS apparently can't do it itself.
1) Artefacts after automatic view resize. Solution here was to hide the view before changing orientation, reload the graph and show it again after orientation was changed. Doesn't look perfect but much better than before.
2) Other problems were caused by the pickerview. Autoresize apparently doesn't work at all. The solution here was create UIView instead of the picker which resizes without problem and again recreate the pickerview every time the orientation changes.

Resources