【发布时间】:2021-10-21 05:25:21
【问题描述】:
这可能很容易,但我真的不知道如何在视图进入后台并使用SceneDelegate 返回时获得通知。如果我有一个 viewController 通过返回主菜单或类似的东西进入后台,我如何通过 sceneWillResignActive 检测到它?
我发现 here 可以这样做:
let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self, selector: #selector(appMovedToBackground), name: UIApplication.willResignActiveNotification, object: nil)
notificationCenter.addObserver(self, selector: #selector(appBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil)
更具体地说,我有这个ViewController.swift:
import Foundation
import UIKit
import AVKit
class IntroViewController : UIViewController {
@IBOutlet weak var videoView: UIView!
@IBOutlet weak var introLabel: UILabel!
var player: AVPlayer?
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
playVideo()
}
override func viewWillDisappear(_ animated: Bool) {
NotificationCenter.default.removeObserver(self)
if let player = player {
player.pause()
}
player = nil
}
private func playVideo() {
if player != nil {
player!.play()
} else {
guard let path = Bundle.main.path(forResource: "intro_video", ofType:"mp4") else {
debugPrint("intro.MP4 not found")
return
}
player = AVPlayer(url: URL(fileURLWithPath: path))
player!.actionAtItemEnd = .none
let playerFrame = CGRect(x: 0, y: 0, width: videoView.frame.width, height: videoView.frame.height)
NotificationCenter.default.addObserver(self,
selector: #selector(playerItemDidReachEnd(notification:)),
name: .AVPlayerItemDidPlayToEndTime,
object: player!.currentItem)
let playerController = AVPlayerViewController()
playerController.player = player
playerController.videoGravity = .resizeAspectFill
playerController.view.frame = playerFrame
playerController.showsPlaybackControls = false
addChild(playerController)
videoView.addSubview(playerController.view)
playerController.didMove(toParent: self)
player!.play()
player!.rate = 1.3
}
}
@objc func playerItemDidReachEnd(notification: Notification) {
let mainViewController = self.storyboard!.instantiateViewController(withIdentifier: "main_view_controller") as! MainViewController
player!.pause()
present(mainViewController, animated:true, completion:nil)
}
@IBAction func skipVideo(_ sender: Any) {
if player != nil {
player?.pause()
player = nil
}
let mainViewController = self.storyboard!.instantiateViewController(withIdentifier: "main_view_controller") as! MainViewController
present(mainViewController, animated:true, completion:nil)
}
}
然后我们有SceneDelegate.swift:
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
guard let _ = (scene as? UIWindowScene) else { return }
}
func sceneDidDisconnect(_ scene: UIScene) {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}
func sceneDidBecomeActive(_ scene: UIScene) {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
func sceneWillResignActive(_ scene: UIScene) {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
func sceneWillEnterForeground(_ scene: UIScene) {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
func sceneDidEnterBackground(_ scene: UIScene) {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}
}
我希望能够在用户离开应用时暂停并重新启动播放器。据我了解,为了启动播放器,应该以某种方式从sceneDidBecomeActive 调用某些东西。我不明白的是如何在sceneDidBecomeActive 中表明应该呈现的视图控制器是我想要的。
sceneDidBecomeActive(当然)每次我回到应用程序时都会被调用,无论我是从哪个ViewController 离开的。
在引用旧方法的链接中,似乎有一些通知程序可以分配一个 lambda。如果我在SceneDelegate 中有对ViewController 的引用,我必须以某种方式检查它是否应该变为活动状态?
我不觉得遵循我找到的关于SceneDelegates 的教程是一件非常简单的事情。他们主要谈论 Appdelegate 之间的差异以及您可以做什么,但从不谈论如何实际去做。
【问题讨论】:
-
您能否定义一下“进入后台”对您意味着什么?当用户点击 iPhone 上的主页按钮或打开其他应用程序并返回时,应用程序作为一个整体进入后台并恢复,这也是
AppDelegate和SceneDelegate通知的内容。但是您所指定的问题似乎更像viewWillDisappear和viewWillAppear,您可以查看ViewController生命周期以获取更多详细信息stackoverflow.com/questions/5562938/…
标签: ios swift uiscenedelegate