DEV Community

Kolmar Kafran
Kolmar Kafran

Posted on

13

SwiftUI List Card View

I love the way Apple's Health and Fitness apps presents CardViews: in a List with a gap between the cards and a swipe left to delete. This seem to be a desired design between iOS developers.

Apple's Fitness app with a swift to delete List CardView

This playground is a simple example on how to recreate the same effect with SwiftUI since all the examples I found online implements the same design in a much more complex manner.

Playground app showcasing List CardView with swipe to delete

We'll take the Apple's Dev Training "Creating a card view" as an inspiration and starting point.

Data Model

First lets create the Data Model for our CardView. It's a simple model holding a Theme to color our CardViews.



import Foundation

struct ColorCard: Identifiable {
    let id = UUID()
    var theme: Theme
}


Enter fullscreen mode Exit fullscreen mode

Card View

The CardView has the following structure.



import SwiftUI

struct CardView: View {
    let colorCard: ColorCard

    var body: some View {
        Text(colorCard.theme.name)
            .foregroundColor(colorCard.theme.accentColor)
            .font(.headline)
            .padding(
                EdgeInsets(
                    top: 25,
                    leading: 5,
                    bottom: 25,
                    trailing: 5
                )
            )
    }
}


Enter fullscreen mode Exit fullscreen mode

Content View

And finally our ContentView containing the List of CardViews. To create the gap between the List items we remove the list row separators .listRowSeparator(.hidden) and set the list row background to an InsettableShape .listRowBackground() defining a top and a bottom EdgeInsets padding. The final touch is to set the .listStyle(.plain) to .plain.



import SwiftUI

struct ContentView: View {
    @State private var colorCards: [ColorCard] = ColorCard.sampleData

    var body: some View {
        List {
            ForEach(colorCards) { colorCard in
                NavigationLink(destination: colorCard.theme.mainColor) {
                    CardView(colorCard: colorCard)
                }
                .listRowSeparator(.hidden)
                .listRowBackground(
                    RoundedRectangle(cornerRadius: 5)
                        .background(.clear)
                        .foregroundColor(colorCard.theme.mainColor)
                        .padding(
                            EdgeInsets(
                                top: 2,
                                leading: 10,
                                bottom: 2,
                                trailing: 10
                            )
                        )
                )
            }
            .onDelete { idx in
                colorCards.remove(atOffsets: idx)
            }
        }
        .listStyle(.plain)
        .navigationTitle("Color Cards")
        .toolbar {
            Button {
                colorCards.append(ColorCard(theme: Theme.allCases.randomElement()!))
            } label: {
                Image(systemName: "plus")
            }
        }
    }
}


Enter fullscreen mode Exit fullscreen mode

A complete Playground App is available on github reposity SwiftUI List CardView Example.

Sentry growth stunted Image

If you are wasting time trying to track down the cause of a crash, it’s time for a better solution. Get your crash rates to zero (or close to zero as possible) with less time and effort.

Try Sentry for more visibility into crashes, better workflow tools, and customizable alerts and reporting.

Switch Tools 🔁

Top comments (0)

Sentry mobile image

App store rankings love fast apps - mobile vitals can help you get there

Slow startup times, UI hangs, and frozen frames frustrate users—but they’re also fixable. Mobile Vitals help you measure and understand these performance issues so you can optimize your app’s speed and responsiveness. Learn how to use them to reduce friction and improve user experience.

Read full post →

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay