如何更改 "MENU" 按钮行为以不终止应用程序
How to change "MENU" button behaviour to not terminate App
刚开始:我不想改变Apple用户体验指南的用户体验,我实际上想把它带回我的应用程序,所以问题来了:
"MENU" 按钮应该返回导航层次结构中的一个级别,如果没有级别,则终止应用程序。
我的第一个导航屏幕也有一个最初隐藏的全屏视图(例如视频播放器)。从第一个导航屏幕,用户可以进入更深层次。 "MENU" 按钮有其正确的标准行为。
最深的导航级别然后显示隐藏的全屏视图。当用户按下 "MENU" 时,导航应该返回到最后一级,但它会终止应用程序。
如何仅针对此单个视图更改 "MENU" 按钮的行为?
真正导致您的应用程序退出的是,如果按下菜单按钮的 pressesEnded:withEvent:
一直沿着响应链向上到达 UIApplication
。因此,如果您阻止这种情况发生,应用程序将不会退出。
有两种方法可以做到这一点:响应者链中的某个人需要覆盖该方法并且不调用super
,或者响应者链中的某个人需要有一个识别按钮按下的手势识别器。
UINavigationController
,例如,使用后者。如果导航堆栈位于其根部,它也会禁用手势;这样,尝试弹出最后一个视图控制器实际上会退出应用程序。
实现起来并不难。只需确保显示给用户的初始屏幕不是根视图。
我会把堆栈放在这里。
根视图包含两个视图,即
VideoContainerView 和
MainContainerView。
VideoContainerView 将有一个 UIViewController,它有 menuHandler 按钮侦听器。此 VC 在按下按钮时在 RootView 顶部显示另一个视图。
MainContainerView 将有 UIViewController,它没有任何 menuHandler。 MainContainerView 显示在 VideoContainerView 之上。
堆栈
MainContainerView(顶部)
VideoContainerView
根目录ViewController
RootView -> VideoContainerView(包含 VideoScreenController 的视图)
RootView -> MainContainerView(包含 MainViewController 的视图)
RootView -> VideoContainerView -> VideoScreen(初始屏幕,确保这是使用 ContainerView 显示在 FirstView 之上的视图控制器)。
在 VideoScreenController 中,按下菜单按钮 将显示 RootView 的 MainContainerView,它一直隐藏在该 VideoContainerView 的顶部。
按下“下一个菜单”按钮时,应用程序将进入后台,因为“主”ViewController 不处理任何菜单按钮按下。
永远不要听 RootView 的 topView 上的任何 MenuButton 按下。
可以使用
轻松控制首选焦点流
override var preferredFocusEnvironments: [UIFocusEnvironment] {
if topView.isHidden {
return [VideoContainerView]
} else {
return [MainContainerView]
}
}
同样,在每个 ViewController 中都有 preferredFocusEnvironments 来处理初始首选焦点,以便系统知道当前焦点是什么。
上面的代码,帮助系统知道哪个视图应该在启动时或在每次焦点更改时聚焦。
刚开始:我不想改变Apple用户体验指南的用户体验,我实际上想把它带回我的应用程序,所以问题来了:
"MENU" 按钮应该返回导航层次结构中的一个级别,如果没有级别,则终止应用程序。
我的第一个导航屏幕也有一个最初隐藏的全屏视图(例如视频播放器)。从第一个导航屏幕,用户可以进入更深层次。 "MENU" 按钮有其正确的标准行为。
最深的导航级别然后显示隐藏的全屏视图。当用户按下 "MENU" 时,导航应该返回到最后一级,但它会终止应用程序。
如何仅针对此单个视图更改 "MENU" 按钮的行为?
真正导致您的应用程序退出的是,如果按下菜单按钮的 pressesEnded:withEvent:
一直沿着响应链向上到达 UIApplication
。因此,如果您阻止这种情况发生,应用程序将不会退出。
有两种方法可以做到这一点:响应者链中的某个人需要覆盖该方法并且不调用super
,或者响应者链中的某个人需要有一个识别按钮按下的手势识别器。
UINavigationController
,例如,使用后者。如果导航堆栈位于其根部,它也会禁用手势;这样,尝试弹出最后一个视图控制器实际上会退出应用程序。
实现起来并不难。只需确保显示给用户的初始屏幕不是根视图。
我会把堆栈放在这里。 根视图包含两个视图,即
VideoContainerView 和
MainContainerView。
VideoContainerView 将有一个 UIViewController,它有 menuHandler 按钮侦听器。此 VC 在按下按钮时在 RootView 顶部显示另一个视图。
MainContainerView 将有 UIViewController,它没有任何 menuHandler。 MainContainerView 显示在 VideoContainerView 之上。
堆栈
MainContainerView(顶部)
VideoContainerView
根目录ViewController
RootView -> VideoContainerView(包含 VideoScreenController 的视图) RootView -> MainContainerView(包含 MainViewController 的视图)
RootView -> VideoContainerView -> VideoScreen(初始屏幕,确保这是使用 ContainerView 显示在 FirstView 之上的视图控制器)。
在 VideoScreenController 中,按下菜单按钮 将显示 RootView 的 MainContainerView,它一直隐藏在该 VideoContainerView 的顶部。
按下“下一个菜单”按钮时,应用程序将进入后台,因为“主”ViewController 不处理任何菜单按钮按下。
永远不要听 RootView 的 topView 上的任何 MenuButton 按下。
可以使用
轻松控制首选焦点流override var preferredFocusEnvironments: [UIFocusEnvironment] {
if topView.isHidden {
return [VideoContainerView]
} else {
return [MainContainerView]
}
}
同样,在每个 ViewController 中都有 preferredFocusEnvironments 来处理初始首选焦点,以便系统知道当前焦点是什么。
上面的代码,帮助系统知道哪个视图应该在启动时或在每次焦点更改时聚焦。