-2

I'm a newbie, using XCode 13.0 to create a very basic app that needs to have a Settings view. I'd like to navigate to the Settings view on tapping a label. To do that, it seemed sensible to use a NavigationView with a NavigationLink.

Unfortunately, I'm encountering a formatting issue that creates a mess of the HStack in which the Setting label (gear icon) resides, as show below:

This is what I want, a result of the following code:

      HStack(spacing: 25) {

        ... other labels

        Label ("", systemImage: "gear")
          .foregroundColor(.gray)
         .font(.title)
          .onTapGesture(perform: {
            // Set a state variable that triggers an extension
            //  that brings up the SettingsView
          })
      }

This is what I want

This is what happens when NavigationView encapsulates the gear icon label. Note the vertical and horizontal white space around it.

   HStack(spacing: 25) {

      ... other labels

      NavigationView {
             NavigationLink(destination: SettingsView()) {
               Label ("", systemImage: "gear")
                 .foregroundColor(.gray)
                 .font(.title)
             }.navigationBarTitle(Text(""))
          
      }
   }

This is what happens when NavigationView encapsulates the label

I've, literally, spent weeks (sporadically) on this issue, looking up dozens of answers and trying various formatting options, without luck. I've also tried encapsulating parent and grandparent stacks into the NavigationView. To no avail. Surely, this is something trivial. Can somebody point me in the right direction?

p.s. there are other issues in that that Navigation link opens as a sub-window; I plan to tackle that later.

Edit: Right, so I tried using Yrb's code:

   HStack(spacing: 25) {

      ... other labels    
    NavigationView {
        NavigationLink(destination: Text("Linked View")) {
            Image(systemName: "gear")
                .foregroundColor(.gray)
                .font(.title)
        }
        .fixedSize()
        .background(Color.red)
    }
  ]

Unfortunately, there's no substantive change...

enter image description here

RudyF
  • 805
  • 1
  • 10
  • 16
  • 1
    We can’t really answer your question with the information given. Please see: [How do I ask a good question?](https://stackoverflow.com/help/how-to-ask) and [How to create a Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example). – Yrb Oct 18 '21 at 14:41
  • Fair enough. I've added code to explain better – RudyF Oct 18 '21 at 18:31
  • Might be easier to follow what was going on if you painted/filled the background of that Label (or clicked it in Preview) so we can see the frame. Also, if I needed an image which let me trigger an action on tap, I'd probably use a Button (which has content and an action) instead of a Label with empty text, and an onTap. Any particular reason you're using a Label instead? – 4D45 Oct 18 '21 at 18:42
  • 1
    Secondly, the navigation view's normally for wrapping an entire screen (or most of a screen-ful) of content, so I suspect what you're getting here, by only wrapping the single label/icon is a (tiny, invisible) navigation bar somewhere weird. Again, if you click around in code, with Preview visible, you might see frames drawn around the (tiny) NavigationView, then, inside that, the gear. I'd guess you maybe want a sheet instead of a NavigationView? – 4D45 Oct 18 '21 at 18:45
  • 1
    Short tutorial on [how to present a sheet](https://www.hackingwithswift.com/quick-start/swiftui/how-to-present-a-new-view-using-sheets) – 4D45 Oct 18 '21 at 18:47
  • Hmm... the sheet concept looks interesting. Will give it a try. – RudyF Oct 18 '21 at 19:46
  • Dang, sheets appears to require 15.0+; my iphone7 becomes useless. Works on Simulator-iPhone 13. But the NumberPicker in the SettingsView is grayed out (checkboxes work). – RudyF Oct 18 '21 at 20:07
  • "Secondly, the navigation view's normally for wrapping an entire screen". Yes, this was the issue. Thanks a bunch. – RudyF Oct 18 '21 at 20:21

2 Answers2

2

In diagnosing these sort of issues, it helps to throw a .background() with a color on. You can then see the issue. In this case, it was twofold, one, you need to use a .fixedSize to shrink the view to its smallest dimensions necessary. That would leave you with the icon plus a little space. That was due to you using a label as it was leaving a spot for the Text("") that you used as a fill in. Since you only want the image, use Image(systemName:) The code then comes out like this:

struct NavLinkNoSpace: View {
    var body: some View {
        NavigationView {
            NavigationLink(destination: Text("Linked View")) {
                Image(systemName: "gear")
                    .foregroundColor(.gray)
                    .font(.title)
            }
            .fixedSize()
            
            // Setting this shows you what space you are using. Remove it when you are done
            .background(Color.red)
        }
    }
}

A couple more things. If you have not ever set the NavigationTitle, you don't need to set it to "". In your example, there was no title, so I simply removed it and there was no effect.

More importantly, and it was addressed by some of the comments, you should only have one NavigationView in the view hierarchy. As long as you are in the hierarchy, you do not need to wrap things like NavigationLink to have them work. You can always throw one around your view call in the preview provider if you are in a child view, to show what things look like, and to test NavigationLinks, etc., but do not just put them in to your main code. It will lead to undesirable outcomes.

Yrb
  • 8,103
  • 2
  • 14
  • 44
  • Thanks for your suggestion; unfortunately, the issue remains (I've edited the question to show what happens) – RudyF Oct 18 '21 at 19:44
  • "You should only have one NavigationView in the view hierarchy". Looks like this was the key. I did have a single NavigationView, but it was at the lowest level, just around the Settings label. Once I made the NavigationView as the top-level view, the HStack alignment issue has gone away. Now I'm left with the excessive space at the top... but I should be able to figure that out. Thanks a bunch. – RudyF Oct 18 '21 at 20:18
0

To summarize what worked to fix the primary problem, that of formatting: The key was in figuring what to encapsulate within the NavigationView. My mistake was to assume that only the NavigationLink needed to be in the NavigationView.

What worked was to place all the contents of the body into the NavigationView, like below:

var body: some View {
 NavigationView {
  VStack(spacing: -10) {
    
    Text(appName)
      .font(.largeTitle)
      .foregroundColor(.blue)
      .padding(.bottom)

  // ...
  // includes a bunch of VStacks and HStacks
  // ... and finally 

        NavigationLink(destination: SettingsView()) {
          Image(systemName: "gear")
            .foregroundColor(.gray)
            .font(.title)

  // ... more stuff
  // ... and finally

 }.padding(.top, -100)   // NavigationView
} // body
RudyF
  • 805
  • 1
  • 10
  • 16