SwipeActions
Swipe actions for any view, swipe menu based on SwiftUI, full swiping and RTL languages supporting, iOS 13+, add your own views to swipes
Install / Use
/learn @c-villain/SwipeActionsREADME
SwipeActions
<p align="left"> <img src="Sources/Gifs/teaser.jpg" alt="corner radius" width="600"> </p>Library for creating fully customizable swipe actions for any SwiftUI View, similar to Apple's swipeActions(edge:allowsFullSwipe:content:) that available from iOS 15 and only in List 🤷🏼♂️.
You can use SwipeActions in project targeting iOS 13 with any view (e.g. Text or VStack).
👨🏻💻 Feel free to subscribe to channel SwiftUI dev in telegram.
Requirements
- iOS 13.0 or macOS 10.15
Comparison table
| Features support | This SPM | Others | | :--- | :---: | :---: | | SwiftUI | 🟢 | 🟢 | | SPM | 🟢 | 🟢 | | MacOS | 🟢 | 🔴 | | iOS 13.0 | 🟢 | 🔴 | | RTL Languages | 🟢 | 🔴 | | FullSwipe Mode | 🟢 | 🔴 | | Flexibility | 🟢 | 🟡 | | Haptics | 🟢 | 🟡 | | Ease of Use | 🟢 | 🔴 |
Installation
Swift Package Manager
To integrate SwipeActions into your project using SwiftPM add the following to your Package.swift:
dependencies: [
.package(url: "https://github.com/c-villain/SwipeActions", from: "0.1.0"),
],
or via XcodeGen insert into your project.yml:
name: YourProjectName
options:
deploymentTarget:
iOS: 13.0
packages:
SwipeActions:
url: https://github.com/c-villain/SwipeActions
from: 0.1.0
targets:
YourTarget:
type: application
...
dependencies:
- package: SwipeActions
Types
Different types of menu:
- .swiped
- .slided
Both types can be upgraded with full swiping:
<p align="center"> <img src="Sources/Gifs/fullSwipe.gif" alt="Example of full swipe with non-destructive role" width="280"> </p>Quick start
<details> <summary>Adding both leading and trailing swipe actions:</summary> <p align="center"> <img src="Sources/Gifs/both.gif" alt="Example with leading and trailing swipes" height="160" width="280"> </p>Use Leading { ... } and Trailing { ... } closures inside .addSwipeAction { ... } modifier:
import SwipeActions
struct YourView: View {
var body: some View {
ScrollView {
LazyVStack {
ForEach(1...100, id: \.self) { cell in
Text("Cell \(cell)")
.frame(height: 50, alignment: .center)
.frame(maxWidth: .infinity)
.contentShape(Rectangle())
.addSwipeAction {
Leading { //<= HERE
Button {
print("edit \(cell)")
} label: {
Image(systemName: "pencil")
.foregroundColor(.white)
}
.frame(width: 60, height: 50, alignment: .center)
.contentShape(Rectangle())
.background(Color.green)
}
Trailing { //<= HERE
HStack(spacing: 0) {
Button {
print("remove \(cell)")
} label: {
Image(systemName: "trash")
.foregroundColor(.white)
}
.frame(width: 60, height: 50, alignment: .center)
.contentShape(Rectangle())
.background(Color.red)
Button {
print("Inform \(cell)")
} label: {
Image(systemName: "bell.slash.fill")
.foregroundColor(.white)
}
.frame(width: 60, height: 50, alignment: .center)
.background(Color.blue)
}
}
}
}
}
}
}
}
</details>
<details>
<summary>Adding several actions on the side:</summary>
Don't forget that your actions are subviews in general and buttons or smth else particularly. Please arrange them:
YourView()
.addSwipeAction(edge: .trailing) {
HStack(spacing: 0) { // <= 👀 Look here
Rectangle()
.fill(Color.green.opacity(0.8))
.frame(width: 8.0, height: 80)
Button {
} label: {
Image(systemName: "message")
.foregroundColor(.white)
.frame(width: 60, height: 80)
.contentShape(Rectangle())
}
.background(Color.blue)
}
}
</details>
<details>
<summary>Adding swipe actions to the one side of the view:</summary>
<p align="center">
<img src="Sources/Gifs/trailing.gif" alt="Example with trailing swipe menu" height="160" width="280">
</p>
Use .addSwipeAction(edge: ) { ... } modifier, edge - a HorizontalAlignment value input parameter - with two cases of using .leading or .trailing
import SwipeActions
struct YourView: View {
var body: some View {
ScrollView {
LazyVStack {
ForEach(1...100, id: \.self) { cell in
Text("Cell \(cell)")
.frame(height: 50, alignment: .center)
.frame(maxWidth: .infinity)
.contentShape(Rectangle())
.addSwipeAction(edge: .trailing) { // <= choose here .trailing or .leading
HStack(spacing: 0) {
Button {
print("remove \(cell)")
} label: {
Image(systemName: "trash")
.foregroundColor(.white)
}
.frame(width: 60, height: 50, alignment: .center)
.contentShape(Rectangle())
.background(Color.red)
Button {
print("Inform \(cell)")
} label: {
Image(systemName: "bell.slash.fill")
.foregroundColor(.white)
}
.frame(width: 60, height: 50, alignment: .center)
.background(Color.blue)
}
}
}
}
}
}
}
</details>
<details>
<summary>For automatically closing other opened actions during sliding: </summary>
<p align="center">
<img src="Sources/Gifs/autoclosing.gif" alt="Example with auto closing swipe actions" width="280">
</p>
Add SwipeState var to your View and pass it as a binding in .addSwipeAction(state:):
struct YourView: View {
@State var state: SwipeState = .untouched // <= HERE
var body: some View {
ScrollView {
VStack(spacing: 2) {
ForEach(1 ... 30, id: \.self) { cell in
Text("Cell \(cell)")
.addSwipeAction(state: $state) { // <= HERE
....
}
}
}
}
}
}
</details>
Full swipe action
For full swipe use modifier .addFullSwipeAction(menu:swipeColor:swipeRole:state:content:action:)
Basically there are two main SwipeRole for full swipe action: .destructive (defaults) and other one.
This role is used for closing/hiding/removing cell.
<p align="center"> <img src="Sources/Gifs/destructiveFullSwipe.gif" alt="Example of full swipe with destructive role" width="280"> </p>
struct YourView: View {
@St
Related Skills
openhue
343.3kControl Philips Hue lights and scenes via the OpenHue CLI.
sag
343.3kElevenLabs text-to-speech with mac-style say UX.
weather
343.3kGet current weather and forecasts via wttr.in or Open-Meteo
tweakcc
1.5kCustomize Claude Code's system prompts, create custom toolsets, input pattern highlighters, themes/thinking verbs/spinners, customize input box & user message styling, support AGENTS.md, unlock private/unreleased features, and much more. Supports both native/npm installs on all platforms.
