Home > front end >  SwiftUI Form Label above Text field Section Spacing
SwiftUI Form Label above Text field Section Spacing

Time:09-17

I am attempting to create a form in SwiftUI that has the Label above the text input field all the time.

A good example is looking at a contact on an iPhone 12. There are two standalone inputs (among others). Mobile and Notes respectively.

They look and space just how I would like mine.

No matter how I change the following code I always have a large space at the top and the fields themselves have huge spaces in between the Sections.

Form {

    Section() {
        VStack(alignment: .leading) {
            Text("Field1")
            TextField("...", text: $Field1)
        }
        .padding(EdgeInsets(top: 10, leading: 0, bottom: 10, trailing: 0))
    }
  
    Section() {
            
        VStack(alignment: .leading) {
            Text("Field2")
            TextField("...", text: $Field2)
        }
        .padding(EdgeInsets(top: 10, leading: 0, bottom: 10, trailing: 0))
        
    }
}

If the Form tag here is the issue is it better to remove it and do it all manually. Apple do seem to want you to use the Form tag for cross compatibility. In my case its for iPads and iPhones.

CodePudding user response:

My first answer to my own question. This is what I came up with (but decided not to use).

It's pretty much what I wanted in the look.

It seems that Apple really do want to force you to do it "their way".

It is difficult to alter the Form view format without everything you try having some unrequired knock on effect.

I agree with some of the comments that this does look correct but it doesn't have the best UI experience.

Form {
            
   Section() {

        VStack(alignment: .leading) {
            Text("Field1")
                .font(.headline)
            TextField("Required", text: $Field1)
        }
        .padding(EdgeInsets(top: 10, leading: 0, bottom: 10, trailing: 0))

        VStack(alignment: .leading) {
            Text("Field2")
                .font(.headline)
            TextField("Optional", text: $Field2)
        }
        .padding(EdgeInsets(top: 10, leading: 0, bottom: 10, trailing: 0))

    }
    
    Section {
        NavigationLink(destination: SomeView()) {
            Text("Next")
                .padding()
                .foregroundColor(Color.blue)
        }
    }

}
.navigationBarTitle("Main Title")

CodePudding user response:

My second answer to my own question. This is what I came up with.

I decided to go down the route of a separate label above a text input control using the header as the label. This does have a different look.

This is simply because the original look I was after didn't have the best UI experience.

It is possible to add extra code but it starts to get far to over complicated.

Form {
                    
    Section(header: Text("Field1")  // Label
                        .font(.headline)
                        .foregroundColor(.black)
                        // The padding top is larger on the first control to make it stand out more from the navigation bar title.
                        .padding(EdgeInsets(top: 30, leading: 5, bottom: 0, trailing: 0))) {
        TextField("Required", text: $Field1)
    }
    .textCase(nil) // I dont want the label to be all uppercase.
    
    Section(header: Text("Field2")  // Label
                        .font(.headline)
                        .foregroundColor(.black)
                        .padding(EdgeInsets(top: 0, leading: 5, bottom: 0, trailing: 0))) {
        TextField("Required", text: $Field1)
    }
    .textCase(nil)
    
    Section {
        NavigationLink(destination: SomeView()) {
            Text("Next")
                .padding()
                .foregroundColor(Color.blue)
        }
    }

}
.navigationBarTitle("Main Title")

CodePudding user response:

As I said in my comments, you could also put your field title in as the Section header. Also, this is your UI, make it how you want. My only comment about it was to think of the usability when designing it. Your answer gives what looks to be a large target for the user, but in reality is only half that size. I am not saying it is wrong for your app, only that you should consider it.

    Form {
        
        Section(header: Text("Field1") ) {
            TextField("Required", text: $Field1)
                // With padding that is equivalent to your padding.
                .padding(.vertical, 10)
            // .padding(EdgeInsets(top: 10, leading: 0, bottom: 10, trailing: 0))
        }
        
        Section(header: Text("Field2") ) {
            TextField("Optional", text: $Field2)
            // Without padding...
        }
        
        Section(header: Text("Field3") ) {
            TextField("Optional", text: $Field2)
                // With padding that is determined by the system.
                .padding(.vertical)
        }
    }

Obviously, this gives you a different look. As you will notice, I gave you three different .padding() looks. One is yours, instead using .vertical (sets .top and .bottom to be the same) with the same constant. The next is no padding around the field. The last in allowing the system to choose your padding.

  • Related