iPad Rotation to Landscape - FloatingPanelSurfaceView height constraint not updated
Short description
On an iPad device, when rotating from portrait to landscape, the FloatingPanelLayout.updateHeight() method is not getting called. This results in an incorrect (based on portrait) height for the FloatingPanelSurfaceView.
Expected behavior
On any rotation on any device, the FloatingPanelSurfaceView's height constraint is updated
Actual behavior
On an iPad device, rotating from portrait to landscape, the FloatingPanelSurfaceView's height constraint is not updating, which can result in issues for the contentViewControllers view.
Steps to reproduce
Steps to Reproduce (using Maps example)
- update floatingPanel(_ vc:, layoutFor newCollection:) -> FloatingPanelLayout? (line 90) to always return the SearchPanelLandscapeLayout()
- in SearchPanelLandscapeLayout declaration: change the supportedPositions to .tip only and change the insetFor(position:) to return 330 for tip. Also comment out the prepareLayout(surfaceView:, in view:) -> [NSLayoutConstraint] method.
- Run the app on an iPad device in portrait mode
- Rotate the app and note the view no longer displays correctly
- If debugging, tap the "Debug View Hierarchy" button and note the height of the FloatingPanelSurfaceView is not large enough and the height constraint is still based off portrait calculation.
Environment
Library version 1.6.5 Installation method
- [ ] CocoaPods
- [x] Carthage
- [ ] Git submodules
iOS version(s) 12.4 Xcode version 10.3
I will investigate this issue. Thank you for your report.
For now you are able to fix this as below.
- Create a subclass of FloatingPanelController
- override
viewWillTransition(to size:with coordinator:)and callupdateLayout()in the method.
And you need to returns a layout object for a transition size in floatingPanel(_:layoutFor:) delegate method.
I will consider this issue in v2.0 because this needs to update floatingPanel(_:layoutFor:) delegate method.
updateLayout() must call in the DispatchQueue.main.async.
Otherwise, problems still occur.
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
DispatchQueue.main.async {
self.updateLayout()
}
}
@SCENEE @powhu This code will not fix the issue , and iPad landscape layout still not updated and if you do not use DispatchQueue.main.async , even the iPhone layout breaked (the Portrait and Landscape reversed )
class FloatingPanelControllerFix:FloatingPanelController{
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
DispatchQueue.main.async {
self.updateLayout()
}
}
}
And seems this func is not called in iPad after rotate the ipad
func floatingPanel(_ vc: FloatingPanelController, layoutFor newCollection: UITraitCollection) -> FloatingPanelLayout? {
print("not print in ipad , but prints in iphone")
print("in both ipad and iphone, this prints 2 times when first run")
return ....
}
layout code in side class FloatingPanelLandscapeLayout: FloatingPanelLayout in iPad, the width is width of device not 200 , but works in iphone
public func prepareLayout(surfaceView: UIView, in view: UIView) -> [NSLayoutConstraint] {
return [
surfaceView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor, constant: 0.0),
surfaceView.widthAnchor.constraint(equalToConstant: 200)
]
}
Since in iPad verticalSizeClass is the same , so willTransition(to newCollection not call for temporary fix : call this when create fpc , and in viewWillTransition(to size
func fixLandscapeLayout(coordinator:UIViewControllerTransitionCoordinator?){
if let cd = coordinator {
self.fpc.willTransition(to: UITraitCollection(verticalSizeClass: AppDelegate.isLandscape ? .compact : .regular), with: cd)
}
}
self.fpc.addPanel(toParent: self)
self.fpc.hide()
self.fixLandscapeLayout(coordinator: self.transitionCoordinator)
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
if UIDevice.current.userInterfaceIdiom == .pad {
self.fixLandscapeLayout(coordinator: coordinator)
}
}
@SCENEE Is this still an issue with version 2.x? This would be quiet a deal breaker for us...
No. I believe this was resolved in v2. Because v2 has floatingPanel(_: FloatingPanelController, layoutFor size: CGSize) delegate method and also since v2 a layout can be updated directly to assign it to FloatingPanelController.layout.
Thank you @SCENEE. We are currently using v. 1.7.6 and have the issue that on iPad the child view controller added to the FloatingPanelSurfaceView is not layouted correctly on rotation changes. See image:
The red area is the FloatingPanelSurfaceViews contentView. This should all be covered by the child view controllers view. Do you have any hint on how to fix this @SCENEE? Also the proposed solution here by subclassing FloatingPanelController does not work. Thank you in advance :)
Hmm.. if the red area is FloatingPanelSurfaceView.contentView this looks an issue of the child view controllers 🤔