作为一般规则...viewWillAppear()不与“视图将再次可见”相同。
viewWillAppear() 是视图控制器生命周期的一部分。最有可能的是,在那里执行不同的(或额外的)代码,而不是在关闭呈现的控制器时。
您可以尝试的一件事是让您的呈现控制器符合UIViewControllerTransitioningDelegate,并实现:
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning?
这是一些示例代码(请注意:它是仅示例代码,而不是“生产就绪”):
class PresentTestViewController: UIViewController, UIViewControllerTransitioningDelegate {
let infoLabel: UILabel = {
let v = UILabel()
v.backgroundColor = .yellow
v.numberOfLines = 0
return v
}()
let presentButton: UIButton = {
let v = UIButton()
v.setTitle("Test Present", for: [])
v.setTitleColor(.white, for: .normal)
v.setTitleColor(.lightGray, for: .highlighted)
v.backgroundColor = .systemRed
return v
}()
var presentCount: Int = 0
var dismissCount: Int = 0
var dismissReason: String = ""
override func viewDidLoad() {
super.viewDidLoad()
[infoLabel, presentButton].forEach { v in
v.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(v)
}
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// put the button at the top
presentButton.topAnchor.constraint(equalTo: g.topAnchor, constant: 8.0),
presentButton.centerXAnchor.constraint(equalTo: g.centerXAnchor),
presentButton.widthAnchor.constraint(equalTo: g.widthAnchor, multiplier: 0.7),
// put the info label below the present button
infoLabel.topAnchor.constraint(equalTo: presentButton.bottomAnchor, constant: 20.0),
infoLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
infoLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
])
presentButton.addTarget(self, action: #selector(doPresent(_:)), for: .touchUpInside)
view.backgroundColor = .white
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// we're probably doing some view setup tasks here
// that we don't want to ALSO do when a
// presented VC is dismissed
// call UI update func
myViewWillAppear()
}
func myViewWillAppear(fromDismiss: Bool = false) -> Void {
if !fromDismiss {
infoLabel.text = "Info Label"
} else {
var str = infoLabel.text ?? ""
str += "\n" + "Dismiss Count: \(dismissCount) Reason: \(dismissReason)"
infoLabel.text = str
}
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
dismissCount += 1
if let vc = dismissed as? PresentMeViewController {
self.dismissReason = vc.dismissReason
}
myViewWillAppear(fromDismiss: true)
return nil
}
@IBAction func doPresent(_ sender: Any) {
presentCount += 1
var str = infoLabel.text ?? ""
str += "\n" + "Present Count: \(presentCount)"
infoLabel.text = str
let vc = PresentMeViewController()
vc.modalPresentationStyle = .automatic
// set transitioningDelegate
vc.transitioningDelegate = self
present(vc, animated: true, completion: nil)
}
}
class PresentMeViewController: UIViewController {
private let containerView: UIView = {
let v = UIView()
v.backgroundColor = .white
v.layer.borderColor = UIColor.blue.cgColor
v.layer.borderWidth = 2
v.layer.cornerRadius = 16
return v
}()
private let stackView: UIStackView = {
let v = UIStackView()
v.axis = .vertical
v.spacing = 80
return v
}()
private let testLabel: UILabel = {
let v = UILabel()
v.backgroundColor = .green
v.textAlignment = .center
v.numberOfLines = 0
v.text = "This is a label in a stack view in the view controller that will be presented."
return v
}()
private let dismissButton: UIButton = {
let v = UIButton()
v.setTitle("Dismiss Me", for: [])
v.setTitleColor(.white, for: .normal)
v.setTitleColor(.lightGray, for: .highlighted)
v.backgroundColor = .systemBlue
return v
}()
private var timer: Timer!
public var dismissReason: String = ""
override func viewDidLoad() {
super.viewDidLoad()
[stackView, containerView].forEach { v in
v.translatesAutoresizingMaskIntoConstraints = false
}
stackView.addArrangedSubview(testLabel)
stackView.addArrangedSubview(dismissButton)
containerView.addSubview(stackView)
view.addSubview(containerView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
containerView.centerXAnchor.constraint(equalTo: g.centerXAnchor),
containerView.centerYAnchor.constraint(equalTo: g.centerYAnchor),
containerView.widthAnchor.constraint(equalTo: g.widthAnchor, multiplier: 0.7),
stackView.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 20.0),
stackView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 20.0),
stackView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -20.0),
stackView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: -20.0),
])
// dismiss if no action after 5 seconds
timer = Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(gotTimeout), userInfo: nil, repeats: false)
// dismiss on button tap
dismissButton.addTarget(self, action: #selector(doDismiss(_:)), for: .touchUpInside)
// transparent / translucent background
if self.presentingViewController != nil {
view.backgroundColor = UIColor.gray.withAlphaComponent(0.25)
} else {
view.backgroundColor = .systemYellow
}
// this will change if Timer times-out or
// Dismiss button is tapped
dismissReason = "Dragged"
}
@objc func gotTimeout() {
dismissReason = "Timeout"
dismiss(animated: true, completion: nil)
}
@objc func doDismiss(_ sender: Any) {
dismissReason = "Button Tap"
dismiss(animated: true, completion: nil)
}
// if the timer is still valid (i.e. has not "timed out")
// cancel the timer
override func viewWillDisappear(_ animated: Bool) {
if timer != nil {
timer.invalidate()
}
super.viewWillDisappear(animated)
}
}
PresentTestViewController 开头是这样的:
每次我们点击“Test Present”按钮时,我们的presentCount 将递增,“信息标签”将更新,我们将创建PresentMeViewController 的一个实例,设置它的.transitioningDelegate,然后展示它:
如果我们“向下拖动”、点击按钮或 5 秒计时器超时,我们将更新 dismissReason 变量并关闭 VC。
回到PresentTestViewController,我们对animationController(forDismissed dismissed: UIViewController)的实现将增加dismissCount,获取解雇的原因,并通过调用myViewWillAppear(fromDismiss: true)更新UI: