You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iPad横屏分屏模式下viewWillTransition偶发不触发问题咨询

问题

在iPad上(已启用所有默认支持的屏幕方向),以FormSheet样式present UIViewController时出现异常:

  • 竖屏模式下,旋转、切换分屏、调整分屏大小或切换至SlideOver操作均能正常触发viewWillTransition(to:with:)方法;
  • 横屏模式下,分屏状态调整应用大小或切换至SlideOver时,该方法有时无法触发。

已在模拟器和真机上完成测试,演示代码如下:

ViewController 代码

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
        
    }

    @IBAction func button(_ sender: Any) {
        let vc = storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
        if self.traitCollection.userInterfaceIdiom == .phone {
            vc.modalPresentationStyle = .fullScreen
        }
        else {
            vc.modalPresentationStyle = .formSheet
        }
        vc.modalTransitionStyle = .coverVertical
        self.present(vc, animated: true, completion: nil)
    }
    
}

SecondViewController 代码

class SecondViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }
    
    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
        
        DispatchQueue.main.async {
            print("Transition Detected")
        }
    }

}
解决方案

viewWillTransition(to:with:)主要针对设备旋转这类明确的过渡场景,而横屏分屏调整、SlideOver切换时,FormSheet的尺寸变化可能未被系统判定为“过渡”操作,导致回调不触发。可以通过以下两种方法覆盖所有尺寸变化场景:

方法1:监听Trait Collection变化

重写traitCollectionDidChange(_:)方法,跟踪视图尺寸变化:

class SecondViewController: UIViewController {
    private var previousSize: CGSize?

    override func viewDidLoad() {
        super.viewDidLoad()
        previousSize = view.bounds.size
    }
    
    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)
        
        let currentSize = view.bounds.size
        guard let previousSize = previousSize, currentSize != previousSize else { return }
        
        self.previousSize = currentSize
        print("Size changed detected: \(currentSize)")
        // 在此处理尺寸变化逻辑
    }

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
        
        DispatchQueue.main.async {
            print("Transition Detected")
        }
        previousSize = size
    }
}

方法2:监听视图Bounds变化

通过重写viewDidLayoutSubviews()方法检测尺寸变化:

class SecondViewController: UIViewController {
    private var previousBounds: CGRect?

    override func viewDidLoad() {
        super.viewDidLoad()
        previousBounds = view.bounds
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        
        let currentBounds = view.bounds
        guard let previousBounds = previousBounds, currentBounds != previousBounds else { return }
        
        self.previousBounds = currentBounds
        print("Bounds changed detected: \(currentBounds.size)")
        // 在此处理尺寸变化逻辑
    }

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
        
        DispatchQueue.main.async {
            print("Transition Detected")
        }
    }
}

内容的提问来源于stack exchange,提问作者Mel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 22:15:56