使用单个 ViewController 动态切换设备方向
Dynamically switching device orientation with single ViewController
我目前正在开发一个应用程序,它有一个 ViewController 和一个 WKWebView 对象,充当网络应用程序的客户端。它使用 JavaScript 通信和注入以允许本机 Swift 中的对象与 WebView 交互。
我的Objective
我有一个函数 urlDidChange(_ url: String)
,它会在 WKWebView 的原始 URL 值发生变化时触发。我正在尝试根据上述新 url
的值动态设置方向限制,并在满足条件后强制旋转设备以适应这些限制。
我不确定这个额外的信息是否重要,但我认为无论如何我都会包括它:UIViewController 也嵌入在 UINavigationController 中。本机 NavBar 确实帮助客户感觉更像本机应用程序。我没有为它设置任何自定义 类,只是一直在使用 let navBar = navigationController?.navigationBar
.
所需示例用法
func urlDidChange(_ url: String) {
if url.contains("/dashboard") {
UIInterfaceOrientationMask = .portrait
} else if url.contains("/builder") {
UIInterfaceOrientationMask = [.portrait, .landscapeRight]
} else {
UIInterfaceOrientationMask = .all
}
// Set new orientation properties
// Force device rotation based on newly set properties
UIViewController.attemptRotationToDeviceOrientation()
}
当前代码
这是我当前的设置。我尝试了以下操作,但没有成功:
enum Page {
var orientation: UIInterfaceOrientationMask {
switch self {
case .login: return getDeviceOrientation()
case .dashboard: return getDeviceOrientation()
case .newProject: return getDeviceOrientation()
case .builder: return getDeviceOrientation()
case .other: return getDeviceOrientation()
}
}
func getDeviceOrientation() -> UIInterfaceOrientationMask {
let phone = Device.isPhone()
switch self {
case .login:
if phone { return .portrait }
else { return .all }
case .dashboard:
if phone { return .portrait }
else { return .all }
case .newProject:
if phone { return .portrait }
else { return .all }
case .builder:
if phone { return [.portrait, .landscapeRight] }
else { return .all }
case .other:
if phone { return .portrait }
else { return .all }
}
}
ViewController
最后,为了应用新的方向属性,我使用了这个:
func urlDidChange(_ url: String) {
let page = Page.get(forURL: url) // Returns Page case for current URL
UIDevice.current.setValue(page.orientation.rawValue, forKey: "orientation")
UIViewController.attemptRotationToDeviceOrientation()
}
奖金问题
是否有更有效的方法使用枚举将设备属性与我的页面枚举结合起来(即 case .builder
具有不同的 return 值,当 Device.isPhone
或 Device.isPad
)?
如您在上面的代码中所见,我只是使用 if 语句来确定现在提供哪个输出:
case .builder:
if phone { return [.portrait, .landscapeRight] }
else { return .all }
如果您的 ViewController 在 UINavigationController 中,这可能就是原因。您可以尝试使用自定义 UINavigationController,它可以从您的 ViewController 检索方向吗?像这样:
struct OrientationConfig {
let phone: UIInterfaceOrientationMask
let pad: UIInterfaceOrientationMask
static let defaultConfig = OrientationConfig(phone: .portrait, pad: .all)
}
enum Page {
case login
case dashboard
case newProject
case builder
case other
static let orientationConfigs: [Page:OrientationConfig] = [
.login: OrientationConfig.defaultConfig,
.dashboard: OrientationConfig.defaultConfig,
.newProject: OrientationConfig.defaultConfig,
.builder: OrientationConfig(phone: [.portrait, .landscapeRight],
pad: .all),
.other: OrientationConfig.defaultConfig
]
}
class MyViewController: UIViewController {
var page: Page = .login
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if let config = Page.orientationConfigs[page] {
return Device.isPhone ? config.phone : config.pad
}
return super.supportedInterfaceOrientations
}
}
class MyNavigationController: UINavigationController {
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if let viewController = topViewController as? MyViewController {
return viewController.supportedInterfaceOrientations
}
return super.supportedInterfaceOrientations
}
}
我目前正在开发一个应用程序,它有一个 ViewController 和一个 WKWebView 对象,充当网络应用程序的客户端。它使用 JavaScript 通信和注入以允许本机 Swift 中的对象与 WebView 交互。
我的Objective
我有一个函数 urlDidChange(_ url: String)
,它会在 WKWebView 的原始 URL 值发生变化时触发。我正在尝试根据上述新 url
的值动态设置方向限制,并在满足条件后强制旋转设备以适应这些限制。
我不确定这个额外的信息是否重要,但我认为无论如何我都会包括它:UIViewController 也嵌入在 UINavigationController 中。本机 NavBar 确实帮助客户感觉更像本机应用程序。我没有为它设置任何自定义 类,只是一直在使用 let navBar = navigationController?.navigationBar
.
所需示例用法
func urlDidChange(_ url: String) {
if url.contains("/dashboard") {
UIInterfaceOrientationMask = .portrait
} else if url.contains("/builder") {
UIInterfaceOrientationMask = [.portrait, .landscapeRight]
} else {
UIInterfaceOrientationMask = .all
}
// Set new orientation properties
// Force device rotation based on newly set properties
UIViewController.attemptRotationToDeviceOrientation()
}
当前代码
这是我当前的设置。我尝试了以下操作,但没有成功:
enum Page {
var orientation: UIInterfaceOrientationMask {
switch self {
case .login: return getDeviceOrientation()
case .dashboard: return getDeviceOrientation()
case .newProject: return getDeviceOrientation()
case .builder: return getDeviceOrientation()
case .other: return getDeviceOrientation()
}
}
func getDeviceOrientation() -> UIInterfaceOrientationMask {
let phone = Device.isPhone()
switch self {
case .login:
if phone { return .portrait }
else { return .all }
case .dashboard:
if phone { return .portrait }
else { return .all }
case .newProject:
if phone { return .portrait }
else { return .all }
case .builder:
if phone { return [.portrait, .landscapeRight] }
else { return .all }
case .other:
if phone { return .portrait }
else { return .all }
}
}
ViewController
最后,为了应用新的方向属性,我使用了这个:
func urlDidChange(_ url: String) {
let page = Page.get(forURL: url) // Returns Page case for current URL
UIDevice.current.setValue(page.orientation.rawValue, forKey: "orientation")
UIViewController.attemptRotationToDeviceOrientation()
}
奖金问题
是否有更有效的方法使用枚举将设备属性与我的页面枚举结合起来(即 case .builder
具有不同的 return 值,当 Device.isPhone
或 Device.isPad
)?
如您在上面的代码中所见,我只是使用 if 语句来确定现在提供哪个输出:
case .builder:
if phone { return [.portrait, .landscapeRight] }
else { return .all }
如果您的 ViewController 在 UINavigationController 中,这可能就是原因。您可以尝试使用自定义 UINavigationController,它可以从您的 ViewController 检索方向吗?像这样:
struct OrientationConfig {
let phone: UIInterfaceOrientationMask
let pad: UIInterfaceOrientationMask
static let defaultConfig = OrientationConfig(phone: .portrait, pad: .all)
}
enum Page {
case login
case dashboard
case newProject
case builder
case other
static let orientationConfigs: [Page:OrientationConfig] = [
.login: OrientationConfig.defaultConfig,
.dashboard: OrientationConfig.defaultConfig,
.newProject: OrientationConfig.defaultConfig,
.builder: OrientationConfig(phone: [.portrait, .landscapeRight],
pad: .all),
.other: OrientationConfig.defaultConfig
]
}
class MyViewController: UIViewController {
var page: Page = .login
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if let config = Page.orientationConfigs[page] {
return Device.isPhone ? config.phone : config.pad
}
return super.supportedInterfaceOrientations
}
}
class MyNavigationController: UINavigationController {
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if let viewController = topViewController as? MyViewController {
return viewController.supportedInterfaceOrientations
}
return super.supportedInterfaceOrientations
}
}