Skip to content

Swipe Left2Right & Right2Left, pure SwiftUI implementation

License

Notifications You must be signed in to change notification settings

EnesKaraosman/SwipeCell

Repository files navigation

SwipeCell

Preview

Features

  • Swipe cell from Left2Right & Right2Left.
  • Destructive swipe

Usage

  • Simply add onSwipe(leading, trailing) method to your list item
List {
    HStack {
        Text("Enes Karaosman")
        Spacer()
    }
    .listRowInsets(EdgeInsets())
    .onSwipe(leading: [
      .. // here add slots
    ])
    
}

But what is Slot?
It's just a container that wraps your elements

public struct Slot: Identifiable {
    
    /// The Icon will be displayed.
    public let image: () -> Image
    
    /// To allow modification on Text, wrap it with AnyView.
    public let title: () -> AnyView
    
    /// Tap Action
    public let action: () -> Void
    
    /// Style
    public let style: SlotStyle
}

public struct SlotStyle {
    
    /// Background color of slot.
    public let background: Color
    
    /// Image tint color
    public let imageColor: Color // default = .white
    
    /// Individual slot width
    public let slotWidth: CGFloat // default = 60
}

That's it, here is full working example

struct SwipeCellDemoView: View {
    
    var slidableContent: some View {
        HStack(spacing: 16) {
            Image(systemName: "person.crop.circle.fill")
            .resizable()
            .scaledToFit()
            .foregroundColor(.secondary)
            .frame(height: 60)
            
            VStack(alignment: .leading) {
                Text("Enes Karaosman")
                .fontWeight(.semibold)
            
                Text("eneskaraosman53@gmail.com")
                .foregroundColor(.secondary)
            }
        }.padding()
    }
    
    var slots = [
        // First item
        Slot(
            image: {
                Image(systemName: "envelope.open.fill")
            },
            title: {
                Text("Read")
                .foregroundColor(.white)
                .font(.footnote)
                .fontWeight(.semibold)
                .embedInAnyView()
            },
            action: { print("Read Slot tapped") },
            style: .init(background: .orange)
        ),
        // Second item
        Slot(
            image: {
                Image(systemName: "hand.raised.fill")
            },
            title: {
                Text("Block")
                .foregroundColor(.white)
                .font(.footnote)
                .fontWeight(.semibold)
                .embedInAnyView()
            },
            action: { print("Block Slot Tapped") },
            style: .init(background: .blue, imageColor: .red)
        )
    ]
    
    var left2Right: some View {
        slidableContent
        .frame(height: 60)
        .padding()
        .onSwipe(leading: slots)
    }
    
    var right2Left: some View {
        slidableContent
        .frame(height: 60)
        .padding()
        .onSwipe(trailing: slots)
    }
    
    var leftAndRight: some View {
        slidableContent
        .frame(height: 60)
        .padding()
        .onSwipe(leading: slots, trailing: slots)
    }
    
    var items: [AnyView] {
        [
            left2Right.embedInAnyView(),
            right2Left.embedInAnyView(),
            leftAndRight.embedInAnyView()
        ]
    }
    
    var body: some View {
        NavigationView {
            List {
                ForEach(items.indices, id: \.self) { idx in
                    self.items[idx]
                }.listRowInsets(EdgeInsets())
            }.navigationBarTitle("Messages")
        }
    }
    
}

Custom

In demo I used system images, but using local image is allowed as well.

ListItem
    .onSwipe(leading: [
        Slot(
            image: {
                Image("localImageName")
                    // To allow colorifying
                    .renderingMode(.template)
            },
            title: {
                Text("Title").embedInAnyView()
            },
            action: { print("Slot tapped") },
            style: .init(background: .orange)
        )
    ])