[iOS, Swift]で画面回転時のアニメーションを無効化する
iOSのアプリでは、Auto Layoutを使っていたり、適切にlayoutSubviewsでビューの配置を行なっていれば、画面が回転した際に綺麗にアニメーションしてくれます。
しかし、画面の向きによってレイアウトを変えていたり、drawRectを利用していたりと、複雑なレイアウトの場合はうまくアニメーションしてくれません。
そんなときはいっそのこと画面回転のアニメーションを無効化した方が見栄えが良くなります。
アプリ全体で画面回転のアニメーションを無効化する
AppDelegate.swiftのdidFinishLaunchingWithOptionsメソッド内に以下のコードを入れてください。
NotificationCenter.default.addObserver(forName: UIApplication.willChangeStatusBarOrientationNotification, object: nil, queue: nil) { (_) in
UIView.setAnimationsEnabled(false)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: {
UIView.setAnimationsEnabled(true)
})
}
応用
このままのコードだとアプリ全体で回転のアニメーションがオフになってしましますが、適切にif文を入れてやるとアニメーションのオンオフを制御できます。
ViewControllerごとに変える
AppDelegate.swiftのdidFinishLaunchingWithOptionsメソッドあたりを
var preventRotateAnimation = true
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
NotificationCenter.default.addObserver(forName: UIApplication.willChangeStatusBarOrientationNotification, object: nil, queue: nil) { (_) in
if !preventRotateAnimation { return }
UIView.setAnimationsEnabled(false)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: {
UIView.setAnimationsEnabled(true)
})
}
return true
}
こんな感じにして、ViewControllerのviewDidAppearとviewWillDisappearで
(UIApplication.shared.delegate as? AppDelegate)?.preventRotateAnimation = true // 画面回転のアニメーションの無効化
(UIApplication.shared.delegate as? AppDelegate)?.preventRotateAnimation = false // 画面回転のアニメーションの有効化
こんな感じのコードを入れてやれば簡単にオンオフできます。
rootViewControllerのみアニメーションを無効化
上の方で載せているアニメーションは僕が公開しているRPN Anywhereというアプリなのですが、レイアウトが複雑なのは最初に表示される電卓のViewControllerだけで、あとは設定画面のTableViewControllerになります。
今回は、最初のViewControllerだけでアニメーションを無効化し、そこから画面遷移があった場合はアニメーションを有効化したかった。
だけど、上記のように変数を追加してViewControllerも書き換えてってのは面倒だったので、AppDelegateがUIWindowのインスタンスを保持していることをいいことに、
NotificationCenter.default.addObserver(forName: UIApplication.willChangeStatusBarOrientationNotification, object: nil, queue: nil) { (_) in
if self.window?.rootViewController?.presentedViewController != nil { return }
UIView.setAnimationsEnabled(false)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: {
UIView.setAnimationsEnabled(true)
})
}
こんな感じのコードにしています。
コメント