4
votes

NSWindow contentView ne couvre pas la taille totale de la fenêtre - macOS et SwiftUI

Je démarre une nouvelle application macOS avec SwiftUI mais j'ai un gros problème. L'application a besoin d'un contentView taille contentView (sous titleBar ) mais je ne peux pas le faire. Sur un nouveau projet, l'utilisation de Storyboards fonctionne bien, mais pas avec SwiftUI.

Mon code: entrez la description de l'image ici

Résultat: entrez la description de l'image ici

Et cela devrait ressembler à ceci: entrez la description de l'image ici

Des idées? Merci!


2 commentaires

Et quel est le problème avec ça? Voulez-vous une fenêtre sans barre de titre?


Oui, j'ai besoin d'une fenêtre sans barre de titre mais avec des boutons de fermeture, de réduction et de redimensionnement. Deux vues (rouge et noir) doivent s'étendre sous la barre de titre et les boutons


3 Réponses :


1
votes

La zone de sécurité ne s'étend pas sous une barre de titre transparente. Vous pouvez utiliser edgesIgnoringSafeArea pour indiquer à vos bords d'affichage de contenu d'ignorer la zone de sécurité. Quelque chose qui ressemble à votre exemple:

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)
  }
}

Mise à jour: Si vous souhaitez utiliser un NavigationView, vous devez également ajouter edgesIgnoringSafeArea à son contenu:

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

Malheureusement, cela affichera initialement une barre de titre pour le moment, apparemment jusqu'à ce que vous forciez une refonte complète de la fenêtre. Une fois que vous déplacez la fenêtre vers un autre affichage ou que vous la masquez et l'affichez à nouveau, la barre de titre disparaît. Donc, je suppose que cela sera corrigé à un moment donné.

À l'heure actuelle, vous pouvez forcer un masque et afficher par programmation en ajoutant

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)
  }
}

après window.makeKeyAndOrderFront(nil) dans applicationDidFinishLaunching . Cela ajoutera cependant une très courte animation. Si cela vous dérange, vous pourrez peut-être désactiver cela avec NSWindow.animationBehavior ou quelque chose comme ça.

Mise à jour 2 : Apparemment, si vous supprimez le window.makeKeyAndOrderFront(nil) initial window.makeKeyAndOrderFront(nil) et le remplacez par la logique de file d'attente de distribution au-dessus, il ne s'animera pas. Donc à la fin vous aurez

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)
  }
}


5 commentaires

La bonne façon est d'utiliser NagivationView. Dans macOS, vous ne devez pas utiliser HStack pour la navigation. Cela fonctionne bien avec votre solution, mais pas avec NavigationView. Je laisse cette réponse en attente en attendant d'autres options. Merci!


Vous n'avez rien dit sur la navigation :) J'ai mis à jour ma réponse.


En quoi est-ce moins précis?


C'est difficile à évaluer. Les deux réponses sont correctes, mais l'autre a moins de code, plus générale, s'applique à tout le contenu de la vue, etc. J'ai beaucoup réfléchi à la meilleure réponse. Si je pouvais, je vous donnerais les points à tous les deux. Je suis désolé... :(


Je peux imaginer, mais je comprends que vous voulez vous bâtir une réputation.



9
votes

Je viens d'utiliser la variante suivante dans AppDelegate , le contenu de ContentView et d'autres peuvent être

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)
}


3 commentaires

Merci, c'est la réponse la plus précise et la plus simple


Il est intéressant de noter que la spécification des bords en dehors de ContentView a un effet différent. C'est soit un bug, soit SwiftUI a plus de problèmes de composition que je ne le pensais. Il est temps pour plus d'expériences :) Merci pour votre réponse!


Pour mémoire: si j'ai un NavigationView à l'intérieur du ContentView j'ai toujours besoin d'un edgesIgnoringSafeArea sur le NavigationView .



1
votes

Juste pour plus d'informations sur le cycle de vie de l'application SwiftUI.

Vous devez définir le style de fenêtre sur HiddenTitleBarWindowStyle:

WindowGroup {
    ContentView()
}.windowStyle(HiddenTitleBarWindowStyle())


0 commentaires