1

Back with a couple of SwiftUI layout questions :

I'm trying to display 2 lists side by side with custom cells. I created the cell views (EventRow.swift) and I display them in my content view.

I added a border to my lists, for better visibility.

As you can see from the picture below, the result is ghastly:

enter image description here

I would like the gradient effect to be applied to the whole cell, width and height wise.
I tried setting the frame of my EventRow (using .infinity for width and height), but this crashes the app.
Since the size of EventRow is inferred, I also don't know how to adapt my row cells height to its size : you can see the horizontal delimitating bars are not fitted to my custom EventRow...

If anyone has some pointers for this, it would be greatly appreciated.

The sample project can be found here

But I also post my code below:

ContentView :

import SwiftUI

struct ContentView: View {

    struct listsSetup: ViewModifier {
      func body(content: Content) -> some View {
        return content
        .frame(maxHeight: UIScreen.main.bounds.size.height/3)
        .overlay(RoundedRectangle(cornerRadius: 10).stroke(Color.blue, lineWidth: 1))
            .padding([.top, .bottom])
        }
    }

    var body: some View {

        VStack {
                HStack {
                    VStack { // 1 list Vstack
                        VStack {
                        Text("List 1")
                            .padding(.top)
                        List {
                            EventRow()
                            EventRow()
                        } // END of 1st List
                        }
                            .modifier(listsSetup())
                    } // END of 1st list VStack

                    VStack { // 2nd Vstack
                        VStack {
                        Text("List 2")
                            .padding(.top)
                        List {
                            EventRow()
                            EventRow()
                        } // END of Landings List
                        }
                        .modifier(listsSetup())
                    } // End of 2nd List VStack
                } // End of 1st & 2nd lists HStack
                    .padding(.top)
                Spacer()
        } // END of VStack
    } // END of body

}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
    ContentView()
    }
}

EventRow :

import SwiftUI

struct EventRow: View {

    var body: some View {
        LinearGradient(gradient: Gradient(colors: [Color.white, Color.blue]), startPoint: .top, endPoint: .bottom)
        .edgesIgnoringSafeArea(.all)
        .overlay(
            VStack{
            HStack {
            Text("Text one")
                Spacer()
            Text("Text two")
            }
                HStack {
                    Spacer()
                    Image(systemName: "flame")
                    .font(.body)
                    Spacer()
                } // END of second HStack
                    .padding(.top, -14)
            } //END of Vstack
        )
    }
}

struct EventRow_Previews: PreviewProvider {
    static var previews: some View {
       EventRow().previewLayout(.fixed(width: 300, height: 60))

    }
}

Edit after trying Asperi's solution :
My actual EventRow code is as follows, and the listRowBackground modifier doesn't seem to have any effect :

import SwiftUI
import CoreData

struct EventRow: View {

    var event: Events

    var dateFormatter: DateFormatter {
     let formatter = DateFormatter()
    // formatter.dateStyle = .long
     formatter.dateFormat = "dd MMM yy"
     return formatter
     }

    var body: some View {
    VStack{
            HStack {
            Text(event.airportName ?? "")
                .font(.headline)
                Spacer()
            Text(self.dateFormatter.string(from: event.eventDate!))
                .font(.body)
            }
                HStack {
                    Text(event.flightNumber ?? "")
                        .font(.body)
                    Spacer()
                    if event.isSimulator {
                        Image(systemName: "s.circle")
                            .font(.body)
                    } else {
                        Image(systemName: "airplane")
                        .font(.body
                        )
                    }
                    Spacer()
                    if event.aircraftType == 0 {
                        Text("")
                        .font(.body)
                    } else if event.aircraftType == 1 {
                        Text("330")
                        .font(.body)
                    } else if event.aircraftType == 2 {
                        Text("350")
                        .font(.body)
                    }
                } // END of second HStack
                    .padding(.top, -14)

        } //END of Vstack
                .listRowBackground(LinearGradient(gradient: Gradient(colors: [Color.white, Color.blue]), startPoint: .top, endPoint: .bottom))

    }
}

struct EventRow_Previews: PreviewProvider {
    static var previews: some View {
        let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext

                let newEvent = Events(context: context)
                newEvent.eventDate = Date()
                newEvent.aircraftType = 1
                newEvent.airportName = "LDG tst"
                newEvent.flightNumber = "AF TEST"
                newEvent.id = UUID()
                newEvent.isLanding = true
                newEvent.isSimulator = false

        return EventRow(event: newEvent).environment(\.managedObjectContext, context)
        .previewLayout(.fixed(width: 300, height: 60))

    }
}
3
  • That's bad practice to change question after it has answered as postulated. One question - one answer. Bug does not change behaviour, it is another bug - another story. Commented May 16, 2020 at 11:03
  • Sorry about that Asperi, but it’s the only way I found to post some more code. The comment section does not seems like the appropriate way to do so. And since the issue is so closely linked to my previous question, I thought a follow up was better than a brand new question. Commented May 16, 2020 at 14:38
  • OK, got this to work by applying the .listRowBackround modifier ContentView, after the ForEach loop tat is populating my List. It seems that when Lists are populated by a loop, applying the modifier to the EventRow view itself does not work. Thanks for the pointer to that modifier @Asari, would have taken me days to find it ! Commented May 16, 2020 at 17:03

1 Answer 1

1

Here is a solution to make gradient row-wide

demo

struct EventRow: View {

    var body: some View {
        VStack{
            HStack {
                Text("Text one")
                Spacer()
                Text("Text two")
            }
            HStack {
                Spacer()
                Image(systemName: "flame")
                    .font(.body)
                Spacer()
            } // END of second HStack
                .padding(.top, -14)
        } //END of Vstack
        .listRowBackground(LinearGradient(gradient: Gradient(colors: [Color.white, Color.blue]), startPoint: .top, endPoint: .bottom)
        )
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Asperi to the rescue, again ! Thanks, works like a charm. Interestingly, the contentView preview still shows my old layout, but in the sim or on device, the result is perfect.
Tried to apply this to my real project, and it doesn't seem to work. My actual EventRow file pulls its info from a core data entity, but I doubt that is the problem. Tried grouping the elements as I was getting close to the 10 item limit, didn't help.Will edit my question accordingly...

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.