1

As a semi-experienced React Native dev, I'm brand new to native iOS development (downloaded xcode for the first time a few hours ago), and I'm trying to develop a simple app for the purpose of learning Swift.

I have the following view in my app: Link since this is a new account and stack overflow wont let me embed

To achieve this I simply used a VStack with my text, image, and a List containing the options I want the user to select from:

struct GetStartedView: View {
    var body: some View {
        NavigationView {
            VStack(alignment: .center) {
                Text("Plan Your Next Adventure")
                    .font(.title)
                    .fontWeight(.ultraLight)
                    .multilineTextAlignment(.center)
                    .padding()
                Image("trail_placeholder")
                    .resizable()
                    .scaledToFill()
                    .aspectRatio(contentMode: .fit)
                List(trails) { trail in
                    NavigationLink(destination: TripView()) {
                        HStack(spacing: 10) {
                            Image(trail.image)
                                .resizable()
                                .scaledToFill()
                                .padding(0.0)
                                .clipped()
                                .frame(width: 55, height: 50, alignment: .center)
                                .clipShape(RoundedRectangle(cornerRadius: 10))
                            Text(trail.name)
                        }
                    }
                }.listStyle(.plain)
                Spacer()
            }
        }
        .padding(.top, -100.0)
        .navigationTitle("")
        .navigationBarHidden(true)
        
    }
}

However when doing it this way, only the bottom section of the screen scrolls (aka the List). This is unintuitive and visually unappealing, so I want to have the entire page scroll including the list items

My first thought was to use a ScrollView containing those three things, but this leaves me with a mostly empty bugged out page. After doing some research, the consenus seemed to be "why are you using a ScrollView when List already scrolls? just use List.

So I went ahead and tried to just use list:

struct GetStartedView: View {
    var body: some View {
        NavigationView {
            VStack(alignment: .center) {
                List() {
                    Text("Plan Your Next Backpacking Adventure")
                        .font(.title)
                        .fontWeight(.ultraLight)
                        .multilineTextAlignment(.center)
                        .padding(.top, -25.0)
                    Image("trail_placeholder")
                        .resizable()
                        .scaledToFill()
                        .aspectRatio(contentMode: .fit)
                    
                    ForEach(trails) { trail in
                        NavigationLink(destination: TripView()) {
                            HStack(spacing: 10) {
                                Image(trail.image)
                                    .resizable()
                                    .scaledToFill()
                                    .padding(0.0)
                                    .clipped()
                                    .frame(width: 55, height: 50, alignment: .center)
                                    .clipShape(RoundedRectangle(cornerRadius: 10))
                                Text(trail.name)
                            }
                        }
                    }
                    
                }.listStyle(.plain)
                Spacer()
            }.navigationBarTitleDisplayMode(.inline)
        }
        .navigationTitle("test")
        .navigationBarHidden(false)
    }
}

While this does result in the behavior that I wanted, I'm left with some styling problems. Understandably, the List is treating my header text and Image as list items, which means they are styled as such. You can see it in this screenshot where the title is now leading aligned, and there are two divider lines floating at the top of the display.

How can I achieve this behavior while keeping normal styling for my non-list items? I assume that using List is not really the right approach here but I might be wrong. I know I could use ScrollView + LazyVStack to make a facimile of this behavior, but it would be messier and require me to manually recreate the styling behind each list item.

1
  • Use a Section() inside of the list. Commented Jul 21, 2022 at 22:51

1 Answer 1

4

Just group the header together with something like a VStack:

@ViewBuilder
func header () -> some View {
    VStack {
        Text("Plan Your Next Backpacking Adventure")
            .font(.title)
            .fontWeight(.ultraLight)
            .multilineTextAlignment(.center)
            .padding(.top, -25.0)
        Image("trail_placeholder")
            .resizable()
            .scaledToFill()
            .aspectRatio(contentMode: .fit)
    }
}

Then you can use it as the list header:

var body: some View {
    NavigationView {
        VStack(alignment: .center) {
            List {
                header()
                ,,,

or as the section Header:

var body: some View {
    NavigationView {
        VStack(alignment: .center) {
            List {
                Section(
                    content: { /* the for each stuff */ },
                    header: header // 👈 Here
                )
                ,,,

Result

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.