Automatically update preferredContentSize upon rotation - ios

I am looking for a way to enforce a UIPopoverPresentationController automatically resize to fill most of the screen, minus say 50 units of padding.
I first tried settings the preferredContentSize in viewDidLoad, and then detect when rotation occurs and update that CGSize to the new size I could calculate. But for some reason, this isn't working in my context. I was using UIDeviceOrientationDidChangeNotification which normally calls the method, but it's not called when the popover exists within a photo editing extension.
I am wondering if there's any other way to change the popover size besides manually updating the preferredContentSize after detecting a size change? If not, is there a way to detect rotation from within this popover in this context?

Try this:
func isLandscape() -> Bool {
// your logical here
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
let myNewSize = isLandscape() ? mySizeLandscape : mySizePortrait
self.preferredContentSize = myNewSize
super.viewWillTransition(to: myNewSize, with: coordinator)
}

Related

How to calculate iOS 11 size in different orientation?

I calculate itemSize dependent on safe area for UICollectionView with horizontal scroll and custom layout.
But for iPhone X safe area has different size for different orientation. My question is how should I calculate safe area size for landscape orientation in viewWillTransition function? Or how is it possible to do without this calculation?
EDIT
To get safe area size without creating any additional views, use this:
view.safeAreaLayoutGuide.layoutFrame.size
If you want to use viewWillTransition method you can use this:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
// Before rotation
print(view.safeAreaLayoutGuide.layoutFrame.size)
coordinator.animate(alongsideTransition: { (context) in
// During rotation
}) { (context) in
// After rotation
print(self.view.safeAreaLayoutGuide.layoutFrame.size)
}
}
In the completion block you will get your desired size, note however, that this code will be called after the rotation.
Original answer
Solution using additional UIView:
What I did was to create a UIView and pin it with constant 0 to Safe Area Guides, so that it always matches size of Safe Area:
I created an #IBOutlet of that UIView and in viewDidLayoutSubviews() check the size:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
print(containerView.frame.size)
}
After rotation I also get the updated size of that UIView.
Use UICollectionViewDelegateFlowLayout's collectionView(_:layout:sizeForItemAt:). Works like a charm.
Setting the size in the completion block of coordinator.animate(alongsideTransition:completion:) in viewWillTransition(to:with:) didn't work for me because the size animation occurs after the orientation animation ends, which looks weird.

How to use new method in IOS 8 to find screenwidth when view size changes

There is the following method in IOS 8 that is supposed to be used when a view's orientation changes:
override func viewWillTransitionToSize(size: CGSize,
withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
}
How can I use this to find the new width of the screen (I am making a keyboard app) when the screen rotates?
you get the size passed as a parameter...

How to set Notification if view size changed when using multitasking | Swift

When testing my app on an iPad using multitasking and I change the app size on the app, the collection view cells need to be resized or else they don't fit in the view window.
I have took some measures such as
detecting device to change the size of the cells
measure view size to make sure cells fit within the window
Add an observer if user changes device orientation
This is all great but however when actually changing the window size when using multitasking, or going back to the full screen app, the cell sizes don't change and look out of place. This is until forced by switching orientation or switching view controllers so viewWillLoad or viewDidLoad gets executed again.
So how can I set a notification if the view.frame size changes ?
I think the right function to override is viewWillTransition(to:, with:). It is called whenever the container size is about to change.
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
self.collectionView?.collectionViewLayout.invalidateLayout()
}
I think you are over complicating the issue, just use the following so when the device is rotated or resized the collection view also changes accordingly.
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
guard let collectionLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else {
return
}
if UIApplication.shared.statusBarOrientation == UIInterfaceOrientation.landscapeLeft ||
UIApplication.shared.statusBarOrientation == UIInterfaceOrientation.landscapeRight {
//here you can do the logic for the cell size if phone is in landscape
} else {
//logic if not landscape
}
collectionLayout.invalidateLayout()
}
I tried RileyDev answer but the app entered in an infinite loop.
There is no delegate that is executed just when the App's window bounds change, so I've made my own version of the viewWillTransition(to size and traitCollectionDidChange.
With the code below you can detect the window bounds resizing change even if the traits don't change, and resize your collection view cells accordingly invalidating the collection view layout.
var previousWindowBounds: CGRect?
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
if let currentBounds = view.window?.bounds,
let previousWindowBounds = previousWindowBounds, currentBounds != previousWindowBounds {
collectionView?.collectionViewLayout.invalidateLayout()
}
previousWindowBounds = view.window?.bounds
}

How can I get the height of a view after screen rotation in swift?

There is a view, which I add constraints in storyboard so it will change its size after screen rotation, then how can I get its height and width after screen rotation? I tried this in a rotation event function like this:
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
{
println("h:\(view.bounds.size.height)")
println("w:\(view.frame.size.width)")
}
but it only give me the size before rotation happen. I would like to get something like:
"now is landscape, height is...width is..."
"now is portrait, height is ...width is..."
in a rotation event function
The function you are using says "Will transition", that means the transition is not completed, so you can not fetch the new size.
You need to use :
dispatch_async(dispatch_get_main_queue()) {
println("h:\(view.bounds.size.height)")
println("w:\(view.frame.size.width)")
}
This code will be executed after the rotation was completed (in the main queue) and the new sizes are available.
Regards.
Swift 3
crom87 answer updated for Swift 3:
override func viewWillTransition( to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator ) {
DispatchQueue.main.async() {
print( "h:\(self.view.bounds.size.height)" )
print( "w:\(self.view.frame.size.width)" )
}
}

Resize UICollectionView after view transition

I've built detail view in Interface Builder showing informations and photos about some object. Because lenght of informations and number of photos will vary, all is nested in UIScrollView.
Photos are shown in UICollectionView, but I need to always show all contained photos, so I disabled scrolling and dynamically changing Height constraint of UICollectionView by this function (called when finishing rendering cells):
func resizePhotosCollectionView() {
photosCollectionViewHeightConstraint.constant = photosCollectionView.collectionViewLayout.collectionViewContentSize()
}
It works great until this UICollectionView needs resize (typically by device orientation change). I am trying to use UIViewControllerTransitionCoordinator in function:
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
coordinator.animateAlongsideTransition(nil) { context in
self.resizePhotosCollectionView()
}
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
}
but result is jerky because Height constraint changed after transition is complete.
Is there any way how to automatically resize UICollectionView after view transition? If not, how to animate Height constraint change during transition?
Using Xcode 6.1 for target IOS 8.
If I recall correctly, you need to layout the view immediately.
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
coordinator.animateAlongsideTransition(nil) { context in
self.resizePhotosCollectionView()
self.view.setNeedsLayout()
self.view.layoutIfNeeded()
}
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
}
Have you tried wrapping your constraint update into a view animation?
photosCollectionViewHeightConstraint.constant =
photosCollectionView.collectionViewLayout.collectionViewContentSize()
photosCollectionView.setNeedsUpdateConstraints()
UIView.animateWithDuration(0.3, animations: { () -> Void in
photosCollectionView.layoutIfNeeded()
})

Resources