I have a full-screen UIView. When I rotate the phone the view shrinks a little (and you see the black background) and then expands again to be full-screen. It basically animates as expected.
The other views on the screen also animate accordingly.
Can I prevent this from happening for one specific view?
I would like the full-screen view to just stay full-screen without animation revealing the black background, but maintain that the other views animate their rotation.
Kind of like how Apple does it in the camera app. The "viewfinder" does not animate its rotation, but the buttons do.
I have the following code in my ViewController. liveView is the the full-screen UIView mentioned.
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animateAlongsideTransition(in: self.liveView, animation: { (context) in
if let connection = (self.liveView.layer as! AVCaptureVideoPreviewLayer).connection {
connection.videoOrientation = AVCaptureVideoOrientation(ui: UIApplication.shared.statusBarOrientation)
}
}, completion: nil)
}
AVCaptureVideoOrentation is an extension which basically translates UIInterfaceOrientation to AVCaptureVideoOrientation with a switch statement.
Thanks
- Joseph
Did you try self.liveView.layer.removeAllAnimations():
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animateAlongsideTransition(in: self.liveView, animation: { (context) in
if let connection = (self.liveView.layer as! AVCaptureVideoPreviewLayer).connection {
connection.videoOrientation = AVCaptureVideoOrientation(ui: UIApplication.shared.statusBarOrientation)
}
self.liveView.layer.removeAllAnimations()
}, completion: nil)
}
Related
Using Swift 5, I am creating gradient backgrounds for the views in a UIPageControl:
var pageControl = UIPageControl()
func configurePageControl() {
self.view.applyGradient(colors: [UIColor.HL.PurpleStart,UIColor.HL.PurpleEnd])
}
Works great...all the pages have this purple gradient background. But when you rotate a device, the gradient rotates but keeps it's original size which is the device frame size in the previous orientation.
So I just want to redraw the gradient when the device is rotated. I use the following method which successfully executes after the device rotation is complete:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(alongsideTransition: nil, completion: { _ in
self.view.applyGradient(colors: [UIColor.HL.PurpleStart,UIColor.HL.PurpleEnd])
})
}
But this adds a new gradient background underneath the existing one. self.view.applyGradient() is a more current method of applying gradient backgrounds than other examples on SO, so the other solutions don't seem to apply. So how do you remove/replace the existing gradient when using self.view.applyGradient()?
I've implemented the iOS 11 feature prefersLargeTitles and it works just fine. Portrait mode is working as expected:
I understand the large title will always stay collapsed (small) in landscape mode and that's fine to me. The problem is when I try to change to landscape and then again to portrait, the large title should be expanded (big) by default back in portrait mode, but it won't until I scroll down a bit:
My code looks quite simple:
if #available(iOS 11.0, *) {
navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.largeTitleDisplayMode = .always
}
I also tried using different values on tableView.contentInsetAdjustmentBehavior, nothing changed. I'm kind of solving it by now scrolling down the table programmatically after orientation changes, but I think that's just a (not very nice) workaround.
Is that supposed to be working as expected? Is it something left in my implementation? Is there a better workaround to this?
I faced the same issue. This worked for me.
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
navigationItem.largeTitleDisplayMode = .always
coordinator.animate(alongsideTransition: { (_) in
self.coordinator?.navigationController.navigationBar.sizeToFit()
}, completion: nil)
}
One approach could be save the maximum navigation bar height, and set it during rotation.
Something like this:
var maximumHeight: CGFloat = 0
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
guard let navigationController = navigationController else {
return
}
if maximumHeight < navigationController.navigationBar.frame.height {
maximumHeight = navigationController.navigationBar.frame.height
}
coordinator.animate(alongsideTransition: { (_) in
navigationController.navigationBar.frame.size.height = self.maximumHeight
}, completion: nil)
}
In landscape, the system knows that it must change its size, so you don't have to worry about it.
#rassar #twofish
iOS 16
First set the PrefersLargeTitles to true either on ViewDidLoad() or on the NavigationBar in the storyboard.
Then on the Navigation Controller's rootController add this:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate { (_) in
self.navigationController?.navigationBar.sizeToFit()
}
}
I created a blurred view on top of a scroll view (from a collection view) who is displaying on all the screen when user go to the settings but when orientation change when this blurview is active, it doesn't cover all the screen. I implemented the same function to update the frame size and origin when orientation change is catched but it still doesn't work.
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
self.detailBlurView.removeFromSuperview()
if UIDevice.current.orientation.isLandscape {
print("Landscape")
detailBlurView.frame = myCollectionView.bounds
self.myCollectionView.addSubview(detailBlurView)
} else {
print("Portrait")
detailBlurView.frame = myCollectionView.bounds
self.myCollectionView.addSubview(detailBlurView)
}
saveToCoreData()
myCollectionView.reloadData()
loadData()
}
I tried to remove the view from the superview and add it again after changing orientation but still not work.
Someone can tell me why it doesn't update the blurview frame and how to fix it please ?
I need to make below table like structure in one of the apps I am developing. I am creating this table using UITableView & I need my table column width to change based on the screen orientation. I have set constraints for column width & I will assign values to these using the screen width in my viewDidLoad().
However, I am not able to figure out how to re-align these constraints when screen orientation changes. I figured out that viewWillTransition() will be called when orientation is changed & I recalculated the constraints inside that & called setNeedsLayout() for the table view. However, I am not able to make my table view to reset the table column width when screen orientation is changed. I am new to IOS platform and any help will be greatly appreciated.
HDR_parName/HDR_parValue/HDR_minValue/HDR_maxValue
Para1/value1/minvalue1/maxvalue1
Para2/value2/minvalue2/maxvalue2
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
let animationHandler: ((UIViewControllerTransitionCoordinatorContext) -> Void) = { [weak self] (context) in
// This block will be called several times during rotation,
// so if you want your tableView change more smooth reload it here too.
self?.tableView.reloadData()
}
let completionHandler: ((UIViewControllerTransitionCoordinatorContext) -> Void) = { [weak self] (context) in
// This block will be called when rotation will be completed
self?.tableView.reloadData()
}
coordinator.animateAlongsideTransition(animationHandler, completion: completionHandler)
}
Then tableView datasource and delegate methods will be called, where you can setup elements size according to tableView frame size.
Swift 4
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
let animationHandler: ((UIViewControllerTransitionCoordinatorContext) -> Void) = { [weak self] (context) in
// This block will be called several times during rotation,
// so if you want your tableView change more smooth reload it here too.
self?.yourTable.reloadData()
}
let completionHandler: ((UIViewControllerTransitionCoordinatorContext) -> Void) = { [weak self] (context) in
// This block will be called when rotation will be completed
self?.yourTable.reloadData()
}
coordinator.animate(alongsideTransition: animationHandler, completion: completionHandler)
}
It is quite simple solution, what you are doing is wrong.
Consider you want full width as your row width.
You don't have to set any constraint to cell width, instead set trailing constraint to your tableview. It will handle all.
If you still face similar issue then try
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
self.view.layoutIfNeeded()
}
let me know if you are still facing the issue.
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()
})