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

SpriteKit场景侧边模态呈现ViewController后变形问题排查求助

Fix SpriteKit Scene Distortion After Dismissing Side Modal on iOS 11+

Looks like you've run into a layout quirk specific to iOS 11 and later when working with SpriteKit and modal view controllers. Let's break down why this is happening and walk through actionable fixes:

Why This Happens

iOS 11 introduced Safe Area layout guides, which changed how view frames are calculated during modal transitions. When you dismiss your side-presented modal, the main view's bounds might adjust, but your hardcoded SKView frame and static SKScene size aren't updating automatically. The fact that scrolling fixes it tells us your scroll handler is triggering a layout correction—we just need to replicate that fix for modal dismissals.

Step-by-Step Fixes

1. Use Auto Layout for SKView Instead of Hardcoded Frames

Right now you're initializing SKView with self.view.frame, which doesn't update when the view's bounds change (like after a modal dismiss). Switch to Auto Layout to ensure the SKView always matches the main view's size:

Replace this code:

let skView = SKView(frame: self.view.frame)
skView.isUserInteractionEnabled = false
skView.backgroundColor = .clear
view.insertSubview(skView, belowSubview: collectionView)

With this:

let skView = SKView()
skView.isUserInteractionEnabled = false
skView.backgroundColor = .clear
skView.translatesAutoresizingMaskIntoConstraints = false // Disable auto-resizing mask
view.insertSubview(skView, belowSubview: collectionView)

// Pin SKView to all edges of the main view
NSLayoutConstraint.activate([
    skView.topAnchor.constraint(equalTo: view.topAnchor),
    skView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
    skView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
    skView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])

2. Set SKScene's Scale Mode to .resizeFill

Your WScene is initialized with the view's frame size, but without setting a scale mode, it won't adapt to size changes. Add .resizeFill to ensure the scene always matches the SKView's bounds:

wScene = WScene(size: view.bounds.size)
wScene.scaleMode = .resizeFill // Critical for dynamic size updates
wScene.backgroundColor = .clear

3. Sync Scene Size and Obstacle Position on Layout Changes

Add viewDidLayoutSubviews to your view controller to update the scene size and reposition the obstacle node whenever the view's layout changes (like after a modal dismiss):

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    
    guard let skView = view.subviews.first(where: { $0 is SKView }) as? SKView,
          let scene = skView.scene as? WScene else { return }
    
    // Update scene size if it doesn't match the SKView's current bounds
    if scene.size != skView.bounds.size {
        scene.size = skView.bounds.size
        
        // Reposition the obstacle node since the scene size changed
        if let buttonsObstacle = doubleButton?.buttonsView {
            let obstacleSize = buttonsObstacle.frame.size
            let convertedOrigin = view.convert(buttonsObstacle.center, from: buttonsObstacle.superview)
            let skConvertedOrigin = skView.convert(convertedOrigin, to: scene)
            scene.childNode(withName: WScene.obstacleNodeName)?.position = skConvertedOrigin
        }
    }
}

4. Force Layout Update When Modal Dismisses

If you still see issues, explicitly trigger a layout update when the side modal is dismissed. Add a completion handler to your modal presentation:

// When presenting your side modal view controller
let sideModalVC = YourSideModalViewController()
sideModalVC.dismissCompletion = { [weak self] in
    guard let self = self else { return }
    self.view.setNeedsLayout()
    self.view.layoutIfNeeded()
}
present(sideModalVC, animated: true)

(Don't forget to add a dismissCompletion closure property to your side modal view controller and call it in viewWillDisappear or when the dismiss action is triggered.)

Why This Works

  • Auto Layout ensures the SKView always matches the main view's bounds, even after modal transitions.
  • .resizeFill makes the SKScene automatically adjust its size to fit the SKView.
  • viewDidLayoutSubviews catches any layout changes (like after a modal dismiss) and syncs the scene size and obstacle position.
  • The explicit layout update on modal dismiss guarantees the fix runs at the right time.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:09:30