3

I'm trying to achieve a specific UI design in SwiftUI where the bottom section of my List has a different background color than the top section. For example, the "Your Medications" Section has a different background than the top "Log" Section:

Goal layout:

enter image description here

Here some example code. I wonder if I am supposed to use two Lists instead. If I use two Lists though and nest it in a ScrollView, the height of the lists needs to be specified. I am working with dynamic content, though so I don't think that is ideal.

class ProtocolMedication {} // Example model

struct HomeView: View {
    @Query private var protocolMedications: [ProtocolMedication]
    
    var body: some View {
        NavigationStack {
            List {
                // Upper sections with default background
                Section {
                    Text("Content 1")
                } header: {
                    Text("Log")
                }
                // Bottom section that needs different background
                Section {
                    ForEach(protocolMedications) { medication in
                        Text(medication.name)
                    }
                } header: {
                    Text("Your Medications")
                }
            }
            .listStyle(.insetGrouped)
        }
    }
}
2
  • does this post with various answers address your question: stackoverflow.com/questions/56867334/… Commented Dec 21, 2024 at 22:49
  • The unsatisfactory answer is that it is (currently) not possible to give the Section elements their own background. Currently (iOS 18) the list type insetGrouped uses a UICollectionView and even gives the sections a decoration view for their backgrounds, but offers no direct way to influence it. I could show you a solution using ScrollView, LazyVStack and Section elements, but I don't know if you would be interested in it, because it doesn't have the automatic functions of List. Commented Dec 22, 2024 at 13:10

2 Answers 2

2

If I understand correctly, you want a different color for the outer background around the section, this being the list group background.

  • The default background can be hidden by applying .scrollContentBackground(.hidden) to the List. Then you can apply your own .background to the List.

  • The default background is UIColor.systemGroupedBackground, so this can be used as the first layer in a ZStack that you show in the background.

  • Show the color for the section background as the next layer in the ZStack.

  • The position of the second color can be matched to the section header using .matchedGeometryEffect with alignment: .top.

  • Apply .frame(maxWidth: .infinity, alignment: .leading) to the content of the section header, so that .top (used for matching position) is then the middle of the row, not just the middle of the content.

  • Padding can be used to tweak the position, if necessary.

If you had more sections then you can use the same technique for them too. Each section would have its own layer in the ZStack. In this case, you might want to avoid colors that are partially transparent (colors with opacity), unless you want the transparency effects to combine.

For the list rows themselves, set your own background using .listRowBackground.

struct HomeView: View {
    @Namespace private var ns

    var body: some View {
        NavigationStack {
            List {
                // Upper sections with default background
                Section {
                    Text("Content 1")
                } header: {
                    Text("Log")
                }
                // Bottom section that needs different background
                Section {
                    ForEach(1..<6) { i in
                        Text("Row \(i)")
                    }
                    .padding(.leading, 80)
                    .frame(minHeight: 80)
                    .listRowBackground(
                        HStack(spacing: 0) {
                            Image(systemName: "pills")
                                .resizable()
                                .scaledToFit()
                                .frame(width: 50)
                                .symbolRenderingMode(.hierarchical)
                                .padding(.horizontal)
                                .frame(maxHeight: .infinity)
                                .background(Color(.tertiarySystemBackground).gradient)
                            Color(.secondarySystemGroupedBackground)
                        }
                    )
                } header: {
                    Text("Your Medications")
                        .frame(maxWidth: .infinity, alignment: .leading)
                        .matchedGeometryEffect(
                            id: "Section2",
                            in: ns,
                            anchor: .top
                        )
                }
            }
            .listStyle(.insetGrouped)
            .scrollContentBackground(.hidden)
            .background {
                ZStack {
                    Color(.systemGroupedBackground)
                    Color.yellow
                        .opacity(0.5)
                        .padding(.top, -16)
                        .matchedGeometryEffect(
                            id: "Section2",
                            in: ns,
                            properties: .position,
                            anchor: .top,
                            isSource: false
                        )
                }
                .ignoresSafeArea()
            }
        }
    }
}

Screenshot

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

1 Comment

That's cool, I never tried using a view other than Color in .listRowBackground.
0

You could use .listRowBackground():

 } header: {
    Text("Your Medications")
 }
 .listRowBackground(Color.purple.opacity(0.15))
 ...

1 Comment

That changed the background of the items for that Section. It didn't change the entire Section's background

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.