117 votes

SwiftUI : Comment faire en sorte que TextField devienne le premier intervenant ?

Voici mon SwiftUI code :

struct ContentView : View {

    @State var showingTextField = false
    @State var text = ""

    var body: some View {
        return VStack {
            if showingTextField {
                TextField($text)
            }
            Button(action: { self.showingTextField.toggle() }) {
                Text ("Show")
            }
        }
    }
}

Ce que je veux, c'est que lorsque le champ de texte devient visible pour que le champ de texte devienne le premier intervenant (c'est-à-dire qu'il reçoive le focus et que le clavier s'affiche).

14 votes

Le fait que quelque chose de basique comme cela ne soit même pas supporté montre à quel point SwiftUI est immature pour le moment. Regardez les solutions ci-dessous, c'est ridicule pour quelque chose qui est censé rendre le codage de l'interface graphique "plus simple".

12voto

Casper Zandbergen Points 607

Chaîne de réponse

J'ai fait ce petit paquet pour gestion multiplateforme des premiers intervenants sans sous-classements de vues ni création de ViewRepresentables personnalisés dans SwiftUI sur iOS 13+.

https://github.com/Amzd/ResponderChain

Comment l'appliquer à votre problème

SceneDelegate.swift

...
// Set the ResponderChain as environmentObject
let rootView = ContentView().environmentObject(ResponderChain(forWindow: window))
...

ContentView.swift

struct ContentView: View {

    @EnvironmentObject var chain: ResponderChain
    @State var showingTextField = false
    @State var text = ""

    var body: some View {
        return VStack {
            if showingTextField {
                TextField($text).responderTag("field1").onAppear {
                    DispatchQueue.main.async {
                        chain.firstResponder = "field1"
                    }
                }
            }
            Button(action: { self.showingTextField.toggle() }) {
                Text ("Show")
            }
        }
    }
}

7voto

David Muller Points 181

Comme d'autres l'ont noté (par exemple @kipelovets commentaire sur la réponse acceptée par exemple La réponse de @Eonil ), je n'ai trouvé aucune des solutions acceptées pour fonctionner sous macOS. J'ai cependant eu un peu de chance en utilisant NSViewControllerRepresentable pour obtenir un NSSearchField pour apparaître comme le premier intervenant dans une vue SwiftUI :

import Cocoa
import SwiftUI

class FirstResponderNSSearchFieldController: NSViewController {

  @Binding var text: String

  init(text: Binding<String>) {
    self._text = text
    super.init(nibName: nil, bundle: nil)
  }

  required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  override func loadView() {
    let searchField = NSSearchField()
    searchField.delegate = self
    self.view = searchField
  }

  override func viewDidAppear() {
    self.view.window?.makeFirstResponder(self.view)
  }
}

extension FirstResponderNSSearchFieldController: NSSearchFieldDelegate {

  func controlTextDidChange(_ obj: Notification) {
    if let textField = obj.object as? NSTextField {
      self.text = textField.stringValue
    }
  }
}

struct FirstResponderNSSearchFieldRepresentable: NSViewControllerRepresentable {

  @Binding var text: String

  func makeNSViewController(
    context: NSViewControllerRepresentableContext<FirstResponderNSSearchFieldRepresentable>
  ) -> FirstResponderNSSearchFieldController {
    return FirstResponderNSSearchFieldController(text: $text)
  }

  func updateNSViewController(
    _ nsViewController: FirstResponderNSSearchFieldController,
    context: NSViewControllerRepresentableContext<FirstResponderNSSearchFieldRepresentable>
  ) {
  }
}

Exemple de vue SwiftUI :

struct ContentView: View {

  @State private var text: String = ""

  var body: some View {
    FirstResponderNSSearchFieldRepresentable(text: $text)
  }
}

5voto

Joanna J. Points 116

Pour combler cette fonctionnalité manquante, vous pouvez installer SwiftUIX à l'aide du gestionnaire de paquets Swift :

  1. Dans Xcode, ouvrez votre projet et naviguez vers File Swift Packages Add Package Dependency...
  2. Collez l'URL du référentiel ( https://github.com/SwiftUIX/SwiftUIX ) et cliquez sur Suivant.
  3. Pour Règles, sélectionnez Branche (avec la branche définie comme maître).
  4. Cliquez sur Terminer.
  5. Ouvrez les paramètres du projet, ajoutez SwiftUI.framework aux cadres et bibliothèques liés, définissez le statut sur Optional.

Plus d'informations : https://github.com/SwiftUIX/SwiftUIX

import SwiftUI
import SwiftUIX

struct ContentView : View {

    @State var showingTextField = false
    @State var text = ""

    var body: some View {
        return VStack {
            if showingTextField {
                CocoaTextField("Placeholder text", text: $text)
                    .isFirstResponder(true)
                    .frame(width: 300, height: 48, alignment: .center)
            }
            Button(action: { self.showingTextField.toggle() }) {
                Text ("Show")
            }
        }
    }
}

3voto

swift code Points 71

Nous avons une solution qui permet de contrôler le premier intervenant sans effort.

https://github.com/mobilinked/MbSwiftUIFirstResponder

TextField("Name", text: $name)
    .firstResponder(id: FirstResponders.name, firstResponder: $firstResponder, resignableUserOperations: .all)

TextEditor(text: $notes)
    .firstResponder(id: FirstResponders.notes, firstResponder: $firstResponder, resignableUserOperations: .all)

2voto

Gregor Brandt Points 5645

C'est un ViewModifier qui fonctionne avec introspecter . Il fonctionne pour AppKit MacOS, Xcode 11.5

    struct SetFirstResponderTextField: ViewModifier {
      @State var isFirstResponderSet = false

      func body(content: Content) -> some View {
         content
            .introspectTextField { textField in
            if self.isFirstResponderSet == false {
               textField.becomeFirstResponder()
               self.isFirstResponderSet = true
            }
         }
      }
   }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X