在iOS 9中,是否可以检测应用程序是否运行在iOS 9的滑动重叠或分屏视图模式下?
我已经尝试阅读了苹果关于iOS 9多任务处理的文档,但是没有找到实现方法...
我提问这个问题是因为当应用程序在滑动重叠模式下打开时,我想禁用应用程序中的某个功能。
在iOS 9中,是否可以检测应用程序是否运行在iOS 9的滑动重叠或分屏视图模式下?
我已经尝试阅读了苹果关于iOS 9多任务处理的文档,但是没有找到实现方法...
我提问这个问题是因为当应用程序在滑动重叠模式下打开时,我想禁用应用程序中的某个功能。
只需检查您的窗口是否占据整个屏幕:
BOOL isRunningInFullScreen = CGRectEqualToRect([UIApplication sharedApplication].delegate.window.frame, [UIApplication sharedApplication].delegate.window.screen.bounds);
如果这是假的,那么您正在拆分视图或幻灯片浏览中运行。-(void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
{
// simply create a property of 'BOOL' type
isRunningInFullScreen = CGRectEqualToRect([UIApplication sharedApplication].delegate.window.frame, [UIApplication sharedApplication].delegate.window.screen.bounds);
}
只是另一种重新打包所有这些的方式
extension UIApplication {
public var isSplitOrSlideOver: Bool {
guard let w = self.delegate?.window, let window = w else { return false }
return !window.frame.equalTo(window.screen.bounds)
}
}
那么你只需使用以下代码:
UIApplication.shared.isSplitOrSlideOver
(Swift)UIApplication.sharedApplication.isSplitOrSlideOver
(Objective-C)请注意,在Swift中,window
对象是一个双重可选项... 令人困惑!
对于iOS 13+(请注意,我尚未亲自测试过iOS 13代码)
extension UIApplication {
public var isSplitOrSlideOver: Bool {
guard let window = self.windows.filter({ $0.isKeyWindow }).first else { return false }
return !(window.frame.width == window.screen.bounds.width)
}
}
CGRectEqualsRect
这个东西。所以大部分代码只是确保正确处理可选项。你也可以通过在Swift中使用!
并做出一些真正的运行时假设来轻松处理所有这些。谢谢! - Dan Rosenstark虽然我来晚了,但如果你想要一个独立于方向的属性,可以尝试这个:
extension UIApplication
{
func isRunningInFullScreen() -> Bool
{
if let w = self.keyWindow
{
let maxScreenSize = max(UIScreen.mainScreen().bounds.size.width, UIScreen.mainScreen().bounds.size.height)
let minScreenSize = min(UIScreen.mainScreen().bounds.size.width, UIScreen.mainScreen().bounds.size.height)
let maxAppSize = max(w.bounds.size.width, w.bounds.size.height)
let minAppSize = min(w.bounds.size.width, w.bounds.size.height)
return maxScreenSize == maxAppSize && minScreenSize == minAppSize
}
return true
}
}
像Dan Rosenstark的解决方案一样,但改为适用于新iPad Pro,因为它们似乎会根据通过Xcode直接运行还是通过TestFlight或App Store编译和发布而报告不同的帧和screen.bounds高度。当通过AS或TF传递时,高度将返回980,而不是像在Xcode中一样应该返回1024,这使得无法返回true。
extension UIApplication {
public var isSplitOrSlideOver: Bool {
guard let w = self.delegate?.window, let window = w else { return false }
return !(window.frame.width == window.screen.bounds.width)
}
}
最近,我需要确定一个应用程序的显示样式,这不仅包括它是否改变为分屏视图或滑动视图,还包括屏幕的哪个部分被用于该应用程序(全屏、1/3、1/2、2/3)。将此功能添加到ViewController子类中可以解决该问题。
/// Dismisses this ViewController with animation from a modal state.
func dismissFormSheet () {
dismissViewControllerAnimated(true, completion: nil)
}
private func deviceOrientation () -> UIDeviceOrientation {
return UIDevice.currentDevice().orientation
}
private func getScreenSize () -> (description:String, size:CGRect) {
let size = UIScreen.mainScreen().bounds
let str = "SCREEN SIZE:\nwidth: \(size.width)\nheight: \(size.height)"
return (str, size)
}
private func getApplicationSize () -> (description:String, size:CGRect) {
let size = UIApplication.sharedApplication().windows[0].bounds
let str = "\n\nAPPLICATION SIZE:\nwidth: \(size.width)\nheight: \(size.height)"
return (str, size)
}
func respondToSizeChange (layoutStyle:LayoutStyle) {
// Respond accordingly to the change in size.
}
enum LayoutStyle: String {
case iPadFullscreen = "iPad Full Screen"
case iPadHalfScreen = "iPad 1/2 Screen"
case iPadTwoThirdScreeen = "iPad 2/3 Screen"
case iPadOneThirdScreen = "iPad 1/3 Screen"
case iPhoneFullScreen = "iPhone"
}
private func determineLayout () -> LayoutStyle {
if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
return .iPhoneFullScreen
}
let screenSize = getScreenSize().size
let appSize = getApplicationSize().size
let screenWidth = screenSize.width
let appWidth = appSize.width
if screenSize == appSize {
return .iPadFullscreen
}
// Set a range in case there is some mathematical inconsistency or other outside influence that results in the application width being less than exactly 1/3, 1/2 or 2/3.
let lowRange = screenWidth - 15
let highRange = screenWidth + 15
if lowRange / 2 <= appWidth && appWidth <= highRange / 2 {
return .iPadHalfScreen
} else if appWidth <= highRange / 3 {
return .iPadOneThirdScreen
} else {
return .iPadTwoThirdScreeen
}
}
override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
respondToSizeChange(determineLayout())
}
这是一种更简单、更健壮的方法,没有常量,在我开发的一个iPhone/iPad iOS应用中使用。
此代码还区分了Slide Over和Split View。
为了清晰起见,我在此返回String值,你也可以自由地使用枚举值并根据你的应用合并全屏的两种情况。
func windowMode() -> String {
let screenRect = UIScreen.main.bounds
let appRect = UIApplication.shared.windows[0].bounds
if (UIDevice.current.userInterfaceIdiom == .phone) {
return "iPhone fullscreen"
} else if (screenRect == appRect) {
return "iPad fullscreen"
} else if (appRect.size.height < screenRect.size.height) {
return "iPad slide over"
} else {
return "iPad split view"
}
}
你可以观察-willTransitionToTraitCollection:withTransitionCoordinator:方法,它与大小类有关,以及viewWillTransitionToSize:withTransitionCoordinator:方法,它与你的视图大小(CGSize)有关。但是建议不要硬编码尺寸值。
extension UIApplication {
func isRunningInFullScreen() -> Bool {
if let w = UIApplication.shared.connectedScenes
.filter({$0.activationState == .foregroundActive})
.compactMap({$0 as? UIWindowScene})
.first?.windows
.filter({$0.isKeyWindow}).first {
let maxScreenSize = max(UIScreen.main.bounds.size.width, UIScreen.main.bounds.size.height)
let minScreenSize = min(UIScreen.main.bounds.size.width, UIScreen.main.bounds.size.height)
let maxAppSize = max(w.bounds.size.width, w.bounds.size.height)
let minAppSize = min(w.bounds.size.width, w.bounds.size.height)
return maxScreenSize == maxAppSize && minScreenSize == minAppSize
}
return true
}
}
当处于滑动或33%分屏模式时,水平尺寸类将变为紧凑型。但我认为一旦进入50%或66%模式,您就无法检测到了。
determineLayout()
即可获取当前的layoutStyle
。private func getScreenSize() -> CGRect {
let size = UIScreen.main.bounds
return size
}
private func getApplicationSize() -> CGRect {
let size = UIApplication.shared.windows[0].bounds
return size
}
enum LayoutStyle: String {
case iPadFullscreen = "iPad Full Screen"
case iPadHalfScreen = "iPad 1/2 Screen"
case iPadTwoThirdScreeen = "iPad 2/3 Screen"
case iPadOneThirdScreen = "iPad 1/3 Screen"
case iPhoneFullScreen = "iPhone"
}
func determineLayout() -> LayoutStyle {
if UIDevice.current.userInterfaceIdiom == .phone {
return .iPhoneFullScreen
}
let screenSize = getScreenSize().size
let appSize = getApplicationSize().size
let screenWidth = screenSize.width
let appWidth = appSize.width
if screenSize == appSize {
// full screen
return .iPadFullscreen
}
let persent = CGFloat(appWidth / screenWidth) * 100.0
if persent <= 55.0 && persent >= 45.0 {
// The view persent between 45-55 that's mean it's half screen
return .iPadHalfScreen
} else if persent > 55.0 {
// more than 55% that's mean it's 2/3
return .iPadTwoThirdScreeen
} else {
// less than 45% it's 1/3
return .iPadOneThirdScreen
}
}
window.frame
仍显示为1024x768,因此未被视为处于分屏视图中... - cleardemonwindow.frame
的应用程序生命周期的哪个部分? - Tamás ZaholaapplicationDidBecomeActive:
)中查询此内容。您认为这样做太早了吗? - cleardemonapplicationDidBecomeActive:
,然后调用根视图控制器上的滑动大小的viewWillTransitionToSize:
,然后在窗口上使用滑动大小调用setFrame:
。因此,我建议要么重写根VC上的viewWillTransitionToSize:
方法,要么重写窗口的setFrame:
方法并适当地对传递的大小做出反应。请注意,在其他情况下,窗口框架已正确设置在applicationDidBecomeActive:
中...奇怪。 - Tamás ZaholasetFrame:
对我有用。感谢您的帮助 :) - cleardemon