AFAIK there is no way of adding a single gradient to a section background but you can simply calculate the color for each row and make it look like a single gradient as follow:
import SwiftUI
struct ContentView: View {
var body: some View {
List {
Section {
ForEach(0..<5) { index in
let isFirst = index == 0
let isLast = index == 4
Text("Item \(index)")
.listRowBackground(
LinearGradient(
gradient: .init(
colors: getColorsForIndex(
start: .blue.opacity(0.6),
end: .purple.opacity(0.6),
index: index,
totalItems: 5
)
),
startPoint: .top,
endPoint: .bottom
).clipShape(RoundedCorner(radius: 12, corners: roundedCorners(isFirst: isFirst, isLast: isLast)))
)
}
} header: {
Text("Gradient Section")
}
}
.listStyle(.plain)
.padding(.horizontal, 20)
.padding(.vertical, 4)
}
func getColorsForIndex(
start: Color,
end: Color,
index: Int,
totalItems: Int
) -> [Color] {
guard totalItems > 1 else { return [start, end]}
let lower = CGFloat(index) / CGFloat(totalItems)
let upper = CGFloat(index + 1) / CGFloat(totalItems)
let top = Color.interpolate(
from: start,
to: end,
fraction: lower
)
let bottom = Color.interpolate(
from: start,
to: end,
fraction: upper
)
return [top, bottom]
}
func roundedCorners(isFirst: Bool, isLast: Bool) -> UIRectCorner {
switch (isFirst, isLast) {
case (true, true): return [.allCorners]
case (true, false): return [.topLeft, .topRight]
case (false, true): return [.bottomLeft, .bottomRight]
default: return []
}
}
}
#Preview {
ContentView()
}
extension Color {
static func interpolate(
from: Color,
to: Color,
fraction: CGFloat
) -> Color {
var (red1, green1, blue1, alpha1): (CGFloat, CGFloat, CGFloat, CGFloat) = (0,0,0,0)
UIColor(from).getRed(&red1, green: &green1, blue: &blue1, alpha: &alpha1)
var (red2, green2, blue2, alpha2): (CGFloat, CGFloat, CGFloat, CGFloat) = (0,0,0,0)
UIColor(to).getRed(&red2, green: &green2, blue: &blue2, alpha: &alpha2)
return .init(
red: Double(red1 + (red2 - red1) * fraction),
green: Double(green1 + (green2 - green1) * fraction),
blue: Double(blue1 + (blue2 - blue1) * fraction),
opacity: Double(alpha1 + (alpha2 - alpha1) * fraction)
)
}
}
struct RoundedCorner: Shape {
var radius: CGFloat = 12
var corners: UIRectCorner = .allCorners
func path(in rect: CGRect) -> Path {
let path = UIBezierPath(
roundedRect: rect,
byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius)
)
return Path(path.cgPath)
}
}
