Pobleme mit NavigationView in SwiftUI

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Pobleme mit NavigationView in SwiftUI

    Hallo zusammen!

    Nach einigen sehr hilfreichen Tipps in diesem Forum mache ich weitere "erste" Schritte in Swift UI. Nun habe ich folgendes Problem: Der vorliegende Code erzeugt wunderbar einen Button, der sich auch super an die Größe eines jeden Bildschirms anpasst... bis ich eine Navigation View hinzufüge (im Beispiel unten noch ohne Link etc.) - ab dann erscheint der Button noch korrekt wenn ich den Code auf iPhones Simuliere. Sobald ich jedoch ein iPad auswähle, sehe ich nur noch ein weißes Feld mit dem Pfeil zurück - also im Prinzip die nächste Ansicht. Scheint etwas mit der Größe des Displays zu tun zu haben. Wie läßt sich das lösen?

    Quellcode

    1. struct ContentView: View {
    2. var body: some View {
    3. NavigationView {
    4. VStack {
    5. GeometryReader { geo in
    6. Button(action: {
    7. print("OK")
    8. }, label: {
    9. Text("Verbindung erfolgreich")
    10. })
    11. .font(.largeTitle)
    12. .frame(width: geo.size.width * 0.9, height: geo.frame(in: .global).midY * 0.1)
    13. .foregroundColor(.white)
    14. .background(LinearGradient(gradient: Gradient(colors: [.red, .yellow]), startPoint: .topLeading, endPoint: .bottomTrailing))
    15. .cornerRadius(10)
    16. .padding(1)
    17. .position(x: geo.frame(in: .global).midX, y: 100)
    18. }
    19. }
    20. }
    21. }
    22. }
    Alles anzeigen
  • Weil sie hier noch nicht verknüpft wurden. Da hast du Prinzipiell Recht. Das Grafische Problem ist davon unabhängig. Mit NavigationLink und allem was dazugehört würde es so aussehen:

    Quellcode

    1. NavigationLink(destination: menu(), isActive: self.$login_pushed) {
    2. Text("")
    3. }
    4. .navigationBarTitle(Text("Willkommen"))
    5. Button(action: {
    6. print("Leite weiter zum Hauptmenu")
    7. self.login_pushed = true
    8. }, label: {
    9. HStack {
    10. Text("Klicke hier")
    11. }
    12. .font(.largeTitle)
    13. .frame(minWidth: 0, maxWidth: .infinity)
    14. .foregroundColor(.white)
    15. .background(Color.orange)
    16. })
    Alles anzeigen
  • Hey,

    versuch es doch mal ohne dem VStack. Den benötigst du bei einem Objekt ja nicht. Und falls doch aus anderen Gründen, dann lege die Position des VStacks fest, nicht die des Buttons.

    Aber grundsätzlich denke ich ist es ohnehin "best practice", auf absolutes Positioning wie in deinem Beispiel zu verzichten, wo es nur geht. Klar manchmal braucht man es, aber es führt eben genau zu solchen non-responsive und Device-abhängigen Problemen.

    In deinem Beispiel - wofür genau benötigst du das absolute Positioning bzw. wo möchtest du den Button haben? Schon mal mit Padding oder Spacer gearbeitet? Denke damit wirst du glücklicher!

    LG
  • Doch ich brauche sehr wohl den VStack - hier habe ich mein Problem nur an einem sehr vereinfachten Beispiel gezeigt. Der volle Quellcode von zwei Ansichten siejht wie folgt aus, zuerst die erste Ansicht:

    Quellcode

    1. import SwiftUI
    2. let Signed_Up = SignedUp()
    3. let registriert = Signed_Up.lese_Zugriffscode()
    4. struct ContentView: View {
    5. @State var zugangscode: String = "" // Zugangscode zum Koppeln
    6. @State private var login_pushed: Bool = false // Zustand der LogInTaste nach dem Koppeln
    7. var body: some View {
    8. NavigationView {
    9. VStack {
    10. Text("TABITA")
    11. .font(.custom("AppleSDGothicNeo-Thin", size: 90))
    12. Text("für Eltern außergewöhnlicher Kinder")
    13. .font(.custom("GillSans", size: 22))
    14. Image("FloriUndTabita")
    15. .clipShape(Circle())
    16. .overlay(Circle().stroke(Color.white, lineWidth: 5))
    17. .shadow(radius: 10)
    18. if registriert == 1 {
    19. NavigationLink(destination: menu(), isActive: self.$login_pushed) {
    20. Text("")
    21. }
    22. .navigationBarTitle(Text("Willkommen"))
    23. Button(action: {
    24. print("Leite weiter zum Hauptmenu")
    25. self.login_pushed = true
    26. }, label: {
    27. HStack {
    28. Text("Klicke hier")
    29. }
    30. .font(.largeTitle)
    31. .frame(minWidth: 0, maxWidth: .infinity)
    32. .foregroundColor(.white)
    33. .background(Color.orange)
    34. })
    35. } else {
    36. Text("Geben Sie bitte hier den Zugangscode ein,")
    37. Text("den Sie von Ihrem Dienst der ")
    38. Text ("Offenen Hilfen erhalten haben:")
    39. TextField("Hier tippen", text: $zugangscode)
    40. .frame(width: 100)
    41. Button(action: {
    42. print("Ok")
    43. }, label: {
    44. HStack {
    45. Text("Registriere mein iPhone")
    46. }
    47. .font(.largeTitle)
    48. .frame(minWidth: 0, maxWidth: .infinity)
    49. .foregroundColor(.white)
    50. .background(Color.blue)
    51. })
    52. }
    53. Spacer(minLength: 100)
    54. }
    55. }
    56. }
    57. }
    Alles anzeigen

    und hier die zweite:


    Quellcode

    1. import SwiftUI
    2. struct menu: View {
    3. @State private var finanzen_pushed: Bool = false
    4. @State private var fed_pushed: Bool = false
    5. @State private var haushaltshilfe_pushed: Bool = false
    6. @State private var veranstaltungen_pushed: Bool = false
    7. var body: some View {
    8. NavigationView {
    9. VStack {
    10. Image("Tabita")
    11. .clipShape(Circle())
    12. .overlay(Circle().stroke(Color.white, lineWidth: 5))
    13. .shadow(radius: 10)
    14. Button(action: {
    15. self.finanzen_pushed = true
    16. }, label: {
    17. Text("Finanzen")
    18. })
    19. .font(.largeTitle)
    20. .frame(minWidth: 0, maxWidth: .infinity)
    21. //.position(x: geo.size.width / 2, y: 100)
    22. .foregroundColor(.white)
    23. .background(LinearGradient(gradient: Gradient(colors: [.red, .yellow]), startPoint: .topLeading, endPoint: .bottomTrailing))
    24. .cornerRadius(10)
    25. .padding(10)
    26. Button(action: {
    27. print("FED")
    28. }, label: {
    29. Text("Familienentlastender Dienst")
    30. })
    31. .font(.largeTitle)
    32. .frame(minWidth: 0, maxWidth: .infinity)
    33. .foregroundColor(.white)
    34. .background(LinearGradient(gradient: Gradient(colors: [.red, .yellow]), startPoint: .topLeading, endPoint: .bottomTrailing))
    35. .cornerRadius(10)
    36. .padding(10)
    37. Button(action: {
    38. print("Haushaltshilfe")
    39. }, label: {
    40. Text("Haushaltshilfe")
    41. })
    42. .font(.largeTitle)
    43. .frame(minWidth: 0, maxWidth: .infinity)
    44. .foregroundColor(.white)
    45. .background(LinearGradient(gradient: Gradient(colors: [.red, .yellow]), startPoint: .topLeading, endPoint: .bottomTrailing))
    46. .cornerRadius(10)
    47. .padding(10)
    48. Button(action: {
    49. print("Veranstaltungen")
    50. }, label: {
    51. Text("Veranstaltungen")
    52. })
    53. .font(.largeTitle)
    54. .frame(minWidth: 0, maxWidth: .infinity)
    55. .foregroundColor(.white)
    56. .background(LinearGradient(gradient: Gradient(colors: [.red, .yellow]), startPoint: .topLeading, endPoint: .bottomTrailing))
    57. .cornerRadius(10)
    58. .padding(10)
    59. Text("Kontaktdaten des Dienstes")
    60. }
    61. }
    62. }
    63. }
    Alles anzeigen
    Das ganze findest du auch auf Github - dann kannst du gerne versuchen am eigentlichen Projektentwurf das Problem zu lösen.

    Nun ist es so, dass das ganze auf dem iPhone noch vernünftig aussieht, lediglich wenn das iPhone horizontal gedreht wird, sehe ich plötzlich zwei Ansichten (wegen der NavigationView):

    [Blockierte Grafik: http://www.flori-software.de/iphone1.PNG]

    [Blockierte Grafik: http://www.flori-software.de/iphone2.PNG]

    [Blockierte Grafik: http://www.flori-software.de/iphone3.PNG]


    Sobald das ganze jedeoch auf dem iPad gestartet wird, produziert die Navigation View zuerst einen leren Bildschirm mit einem Rückwärtspfeil, über den ich erst zu den anderen Ansichten komme, die jedoch sehr schmal sind:

    [Blockierte Grafik: http://www.flori-software.de/ipad1.PNG]




    [Blockierte Grafik: http://www.flori-software.de/ipad2.PNG]



    [Blockierte Grafik: http://www.flori-software.de/ipad3.PNG]


    Wird die NavigationView jedoch auskommentiert, nehmen die Elemente auch auf dem ipad die gesamte Bildschirmbreite ein bzw. werden vernünftig zentriert:

    [Blockierte Grafik: http://www.flori-software.de/ipad4.PNG]

    Es scheint also mit der Bildschirmbreite und der NavigatioView zusammenzuhängen. Sobald das iPhone gedreht wird oder das Gerät vom Anfang an eine hohe Bildschirmbreite hat (iPad) werden mehrere Views angezeigt bzw. irgendwie durcheinandergrebracht. Kennt jemand die Lösung?

    Im Übrigen soll die App die Kommunikation zwischen Eltern von Kindern mit Behinderungen und Diensten der sog. "Offenen Hilfen", die Familien mit Angehörigen mit Behinderungen ambulant unterstützen, erleichtern. Verschiedene Leistungen sollen hier über die App gebucht werden können, Restbudgets bei den Pflegekassen bzw. bisher vom Dienst ertsellte Rechnungen eingesehen werden können etc. - indem die App mit der Datenbank einer komplexeren Anwendung kommuniziert, die von den Diensten der Offenen Hilfen verwendet wird.
  • flori-software schrieb:

    Es scheint also mit der Bildschirmbreite und der NavigatioView zusammenzuhängen.
    Wenn genügend Platz ist, dann hat man zwei Teile:
    - links: Die Navigation
    - rechts: Der Inhalt

    Also so wie ich das verstehe.

    Apple schrieb:

    A view for presenting a stack of views representing a visible path in a navigation hierarchy.

    Aber wie gesagt, mit meinen Unwissen und nur kurz drüberkucken, kommt es mir so vor, als ob Du den Inhalt in der Navigation anzeigen möchtest.
  • Ja, das stimmt - der Inhalt ist komplett in der Navigation View - da ich nach dem Klicken des Button zu einer völlig neuen Ansicht wechseln möchte - wie beim Klicken eines Links auf einer Website. In der ersten Ansicht kommt später noch ein Passwortfeld hinzu - das wird die sog. LogIn-Seite. Nach dem Login soll die vollständig verschwinden und eine andere Ansicht angezeigt werden. Wenn die Navigation View aber auf einen kleinerren Bereich beschränkt wird, z.B. nur auf den Button, erscheint auch nur in diesem Ausschnitt der Gesamtview die neue Ansicht:

    [Blockierte Grafik: http://www.flori-software.de/ipad5.png]

    Es muss doch irgendwie realisierbar sein, dass man zwischen zwei Ansichten vollständig wechseln kann?
  • Vielleicht ist für den LogIn-Bereich die Navigation View auch die falsche Lösung - ich weiß es nicht, dazu bin ich noch zu unerfahren. Evtl. wäre es sinnvoller nach erfolgreicher Überprüfung des Passworts (bzw. jetzt erstmal einfach nach dem Anklicken des "Klick hier") die bisher sichtbaren Elemente auszublenden und andere Elemente, die bisher ausgeblendet waren, einzublenden - statt zu einer neuen View zu navigieren? Bei einer Webanwendung würde ich die CSS-Eigenschaft "display" verändern. Kann ich etwas ähnliches auch hier realisieren? Oder wäre auch das der falsche Weg?
  • Ok - ich denke, Navigation View ist tatsächlich nur dann gut, wenn ich es bei großem Display beabsichtige an der Seite eine Art Navigationsmenu zu haben. Sonst kommt dem, was ich möchte, der .sheet-Modifier schon näher, damit könnte ich mich sogar anfreunden:


    Quellcode

    1. struct ContentView: View {
    2. @State private var showingSheet = false
    3. var body: some View {
    4. Button("Show Sheet") {
    5. self.showingSheet.toggle()
    6. }
    7. .sheet(isPresented: $showingSheet) {
    8. SecondView(name: "ArekPaluszek")
    9. }
    10. }
    11. }
    12. struct SecondView: View {
    13. var name: String
    14. var body: some View {
    15. Text("Mein Name ist \(name)")
    16. }
    17. }
    Alles anzeigen
    Die erste View ist nun vollständig durch die neue verdeckt bis auf einen kleinen Rand oben (am iPhone), der noch anzeigt, dass sich dahinter eine andere View verdeckt. Somit kann ich die erste aber immer noch runterschieben und zur ersten zurückkommen. Ein sehr schöner Effekt. Wenn noch jemand weiß, wie ich die erste View vollständig ausblenden kann, also es keine Rückkehrmöglichkeit gibt? Wäre interessant. Brauche ich aber nicht unbedingt.
  • Wenn Du vom Phone auf das Pad wechselst, gehst du automatisch auf den doubleColomNavigationStyle. Wenn Du das unterbinden möchtest, musst du das deiner Navigationview beibringen, z.B. über:

    Quellcode

    1. NavigationView {
    2. ...
    3. }
    4. .navigationViewStyle(StackNavigationViewStyle())


    Dann sieht es wieder aus wie gewohnt

    Schöne Grüsse
    Wolf
  • Wenn ich allerdings das ganze in eine ScrollView packen möchte:


    Quellcode

    1. ScrollView {
    2. NavigationView{
    3. // Code.. Code... Code...
    4. }
    5. .navigationViewStyle(StackNavigationViewStyle())
    6. }
    ... wird die NavigationView wieder optisch geteilt. Mache ich etwas falsch oder ist es halt einfach so?...