I figured out a solution. I added a completion block because that is where the view gets properly refresehed, using the coordinator object that is passed into the viewWillTransition() Also added a spring animation in UIView.animate() block, just for fun.
class TestViewController: UIViewController {
lazy var pickButton : UIButton = {
let button = UIButton(frame: CGRect(x: 0,
y: 0,
width: 100,
height: 100))
button.setTitle("Pick", for: .normal)
button.setTitleColor(.black, for: .normal)
//button.addTarget(self, action: #selector(showPicker), for: .touchUpInside)
return button
}()
lazy var resultsButton : UIButton = {
let button = UIButton(frame: CGRect(x: 0,
y: UIScreen.main.bounds.height - 100,
width: UIScreen.main.bounds.width,
height: 100))
button.setTitle("Show selected", for: .normal)
button.setTitleColor(.black, for: .normal)
//button.addTarget(self, action: #selector(showResults), for: .touchUpInside)
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
determineMyDeviceOrientation()
let device = UIDevice.current
device.beginGeneratingDeviceOrientationNotifications()
let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self, selector: #selector(deviceOrientationChanged),
name: Notification.Name("UIDeviceOrientationDidChangeNotification"),
object: nil)
view.addSubview(resultsButton)
view.addSubview(pickButton)
pickButton.center = view.center
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
coordinator.animate(alongsideTransition: { (UIViewControllerTransitionCoordinatorContext) -> Void in
UIView.animate(withDuration: 50.0, animations: {
self.pickButton.center = CGPoint(x: self.view.center.x, y: self.view.center.y - 50)
self.resultsButton.frame = CGRect(x: 0, y: UIScreen.main.bounds.height - 100, width: UIScreen.main.bounds.width, height: 100)
})
let orient = UIDevice.current.orientation
switch orient {
case .portrait:
print("Portrait")
case .landscapeLeft,.landscapeRight :
print("Landscape")
default:
print("Anything But Portrait")
}
}, completion: { (UIViewControllerTransitionCoordinatorContext) -> Void in
//refresh view once rotation is completed not in will transition as it returns incorrect frame size.Refresh here
UIView.animate(withDuration: 2.0, delay: 0.2, usingSpringWithDamping: 0.2, initialSpringVelocity: 0.0, options: [], animations: {
self.pickButton.center = CGPoint(x: self.view.center.x, y: self.view.center.y)
}, completion: nil)
print ("finished")
print ("size \(size)")
print (UIScreen.main.bounds)
})
super.viewWillTransition(to: size, with: coordinator)
}
func determineMyDeviceOrientation() {
let i = UIDevice.current.orientation.isLandscape
print (i)
if i {
print("Device is in landscape mode")
} else {
print("Device is in portrait mode")
}
}
@objc func deviceOrientationChanged() {
print("Orientation changed")
inspectDeviceOrientation()
}
func inspectDeviceOrientation() {
let orientation = UIDevice.current.orientation
switch UIDevice.current.orientation {
case .portrait:
print("portrait")
case .landscapeLeft:
print("landscapeLeft")
case .landscapeRight:
print("landscapeRight")
case .portraitUpsideDown:
print("portraitUpsideDown")
case .faceUp:
print("faceUp")
case .faceDown:
print("faceDown")
default: // .unknown
print("unknown")
}
if orientation.isPortrait { print("isPortrait") }
if orientation.isLandscape { print("isLandscape") }
if orientation.isFlat { print("isFlat") }
}
}
Post
Replies
Boosts
Views
Activity
I found the problem quite by accident. Adding
func collectionView(_ collectionView: UICollectionView, canFocusItemAt indexPath: IndexPath) -> Bool {
return false
}
in the RecipeListViewController UICollectionViewDelegate solved the problem.
This also solved a focus ring issue that had been plaguing the list in the collection view.
After some thought it seems that Catalyst reports this issue when presenting modal windows (such as a sheet) when running on a Mac vs running on iPad/iPhone, where modal windows are much more common. I'm guessing a Mac build is looking for an actual, separate scene (window).
This issue is irritating but seems innocuous, though.
My workaround for this in Mac build (in Swift) was to create a separate window scene that does what the modal window does, and present a normal modal window in iPad/iPhone, but that's only one solution.
You might also work around this in SwiftUI by using something like .overCurrentContext or .fullScreen for modalPresentationStyle if you don't want to mess with a separate scene. I'm not familar with SwiftUI so I'm not sure what you would do in your example.
I have seen "UIScene property of UINSSceneViewController was accessed before it was set" log entry in myMac Catalyst app as well. I have been trying to track it down literally for months. If I find anything I'll post it.