简体   繁体   English

使用 SwiftUI 时无法正确调整 SKScene 的大小

[英]Unable to properly size SKScene when working with SwiftUI

I am attempting to use SpriteKit with a SwiftUI based interface, but have encountered an issue when initializing my SKScene .我正在尝试将SpriteKit与基于SwiftUI的接口一起使用,但在初始化我的SKScene时遇到了问题。

First, my UIViewRepresentable that contains the SKView has been taken from a similar question :首先,包含UIViewRepresentableSKView取自类似问题

struct SpriteKitContainer: UIViewRepresentable {
    let scene: SKScene

    func makeUIView(context: Context) -> SKView {
        return SKView(frame: .zero)
    }
    
    func updateUIView(_ view: SKView, context: Context) {
        view.presentScene(scene)
    }
}

A key piece here is that it requires the SKScene to be initialized prior to SpriteKitContainer being initialized.这里的一个关键部分是它需要在初始化SKScene之前初始化SpriteKitContainer

I currently have the following abbreviated snippet doing this:我目前有以下缩写片段:

import SwiftUI
import SpriteKit

struct GameView: View {
    @State private var isEnabled = true
    
    var body: some View {
        let tapGesture = TapGesture()
            .onEnded { value in }
        
        // This size is obviously wrong
        let size = UIScreen.main.bounds.size
        let scene = Scene(size: size)
        scene.scaleMode = .resizeFill
        
        return SpriteKitContainer(scene: scene)
            .disabled(!isEnabled)
            .frame(maxWidth: .infinity,
                   maxHeight: .infinity,
                   alignment: .center)
            .gesture(tapGesture)
            .padding(.all, 30)
    }
}

I only include the TapGesture to show why the body is structured the way it is.我只包括TapGesture来说明为什么body是这样构造的。 With the code included, everything will work as expected, but the size used for the scene is obviously wrong (it fails to account for the padding, and navigation elements).包含代码后,一切都会按预期工作,但用于场景的大小显然是错误的(它无法考虑填充和导航元素)。

However, I have not found any other way to obtain a size or frame at this point, and sending over a .zero size for the Scene(size:) call will not size it correctly either.但是,此时我还没有找到任何其他方法来获取大小或帧,并且为Scene(size:)调用发送.zero大小也不会正确调整大小。

My assumption is that I am missing some precursor step as I am still ramping up with SwiftUI.我的假设是我缺少一些前导步骤,因为我仍在使用 SwiftUI。 Otherwise, I could calculate a new CGSize given what I know, but that strikes me as the wrong approach here.否则,我可以根据我所知道的计算一个新的CGSize ,但这让我觉得这里的方法是错误的。

In SwiftUI you need to use GeometryReader as a proxy to get the view's current size (this happens every time the view is rebuilt).在 SwiftUI 中,您需要使用GeometryReader作为代理来获取视图的当前大小(每次重建视图时都会发生这种情况)。 You then want to resize your UIViewRepresentable based on the size of its parent only if the size has actually changed .然后,您需要根据其父级的大小调整您的 UIViewRepresentable 的大小,前提是该大小已实际更改 I have a GeometryReader example here: https://github.com/joshuajhomann/SwiftUI-Spirograph我在这里有一个 GeometryReader 示例: https://github.com/joshuajhomann/SwiftUI-Spirograph

SKScene has a didChangeSize method for scenarios like that: SKScene有一个didChangeSize方法用于这样的场景:

override func didChangeSize(_ oldSize: CGSize) {
    self.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame)
}

From Apples Documentation :苹果文档

This method is intended to be overridden in a subclass.此方法旨在在子类中被覆盖。 Typically, you use this method to adjust the positions of nodes in the scene.通常,您使用此方法来调整场景中节点的位置。

You don't need GeometryReader.您不需要 GeometryReader。 Just let SwiftUI itself give the available space to your SpriteView.只需让 SwiftUI 本身为您的 SpriteView 提供可用空间。 An important thing is, that the views size is not automatically the scene size.重要的是,视图大小不会自动成为场景大小。 So, you have to explicitly set the scene size.因此,您必须明确设置场景大小。

import SwiftUI
import SpriteKit

struct ContentView: View {

    var body: some View {
        SpriteView(scene: spriteKitScene)
    }

    private var spriteKitScene : SKScene {
        let scene = SpriteKit_View()
        scene.scaleMode = .aspectFit
        return scene
    }

}

class SpriteKit_View : SKScene {

    override func didMove(to view: SKView) {

       // Set the scene size as you want, in my case 
          equal to the views size

       size = view.frame.size
       // ...
    }
}

The scene size can be completely different from the view size , that's when the scene scaleMode comes into action.场景大小可以与视图大小完全不同,这就是场景 scaleMode 起作用的时候。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM