web-dev-qa-db-ja.com

NSWindow contentViewがフルウィンドウサイズをカバーしない-macOSとSwiftUI

SwiftUIで新しいmacOSアプリを起動していますが、大きな問題があります。アプリにはフルサイズのcontentViewtitleBarの下)が必要ですが、実現できません。ストーリーボードを使用する新しいプロジェクトでは問題なく機能しますが、SwiftUIでは機能しません。

私のコード: enter image description here

結果: enter image description here

そして、次のようになります。 enter image description here

何か案は?ありがとう!

4
mhergon

AppDelegateで次のバリアントを使用したところ、ContentViewなどのコンテンツは

func applicationDidFinishLaunching(_ aNotification: Notification) {
    // Create the SwiftUI view that provides the window contents.
    let contentView = ContentView()
        .edgesIgnoringSafeArea(.top) // to extend entire content under titlebar 

    // Create the window and set the content view. 
    window = NSWindow(
        contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
        styleMask: [.titled, .closable, .miniaturizable, .texturedBackground, .resizable, .fullSizeContentView],
        backing: .buffered, defer: false)
    window.center()
    window.setFrameAutosaveName("Main Window")

    window.titlebarAppearsTransparent = true // as stated
    window.titleVisibility = .hidden         // no title - all in content

    window.contentView = NSHostingView(rootView: contentView)
    window.makeKeyAndOrderFront(nil)
}
4
Asperi

安全領域は、透明なタイトルバーの下に広がりません。 edgesIgnoringSafeAreaを使用して、コンテンツビューのエッジに安全領域を無視するように指示できます。あなたの例に似たもの:

_struct ContentView: View {
  var body: some View {
    HStack(spacing: 0) {
      Text("Hello, World!")
        .frame(maxWidth: 200, maxHeight: .infinity)
        .background(Color.red)
      Text("Hello, World!")
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.black)
    }.edgesIgnoringSafeArea(.all)
  }
}
_

pdate: NavigationViewを使用する場合は、その内容にedgesIgnoringSafeAreaも追加する必要があります。

_struct ContentView: View {
  var body: some View {
    NavigationView {
      Text("Hello, World!")
        .frame(maxWidth: 200, maxHeight: .infinity)
        .background(Color.red)
        .edgesIgnoringSafeArea(.all)

      Text("Hello, World!")
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.black)
        .edgesIgnoringSafeArea(.all)

    }.edgesIgnoringSafeArea(.all)
  }
}
_

残念ながら、これは現時点で最初はタイトルバーを表示しますが、ウィンドウ全体を強制的に再描画するまで表示されます。ウィンドウを別のディスプレイに移動するか、非表示にして再度表示すると、タイトルバーが非表示になります。したがって、これはいつか修正されると思います。

現在、プログラムで非表示と表示を強制的に追加できます。

_DispatchQueue.main.async {
  self.window.orderOut(nil)
  self.window.makeKeyAndOrderFront(nil)
}
_

applicationDidFinishLaunchingwindow.makeKeyAndOrderFront(nil)の後。ただし、非常に短いアニメーションが追加されます。気になる場合は、_NSWindow.animationBehavior_などでオフにできる場合があります。

pdate 2:どうやら、最初のwindow.makeKeyAndOrderFront(nil)を削除して、上記のディスパッチキューロジックで置き換えると、アニメーション化されません。つまり、最終的には

_func applicationDidFinishLaunching(_ aNotification: Notification) {
  let contentView = ContentView()

  window = NSWindow(
      contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
      styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView, .texturedBackground],
      backing: .buffered, defer: false)
  window.titlebarAppearsTransparent = true
  window.center()
  window.setFrameAutosaveName("Main Window")
  window.contentView = NSHostingView(rootView: contentView)
  // window.makeKeyAndOrderFront(self) <- don't call it here
  DispatchQueue.main.async {
    self.window.orderOut(nil)
    self.window.makeKeyAndOrderFront(nil)
  }
}
_
1
ingoem