Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/c-villain/SwipeActions
Swipe actions, swipe menu based on SwiftUI
https://github.com/c-villain/SwipeActions
ios13 swiftui swiftui-animations swiftui-framework swipeactions swipemenu
Last synced: about 2 months ago
JSON representation
Swipe actions, swipe menu based on SwiftUI
- Host: GitHub
- URL: https://github.com/c-villain/SwipeActions
- Owner: c-villain
- License: mit
- Created: 2021-12-24T13:04:10.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2023-05-17T12:20:13.000Z (over 1 year ago)
- Last Synced: 2024-04-14T11:57:29.811Z (5 months ago)
- Topics: ios13, swiftui, swiftui-animations, swiftui-framework, swipeactions, swipemenu
- Language: Swift
- Homepage:
- Size: 2.75 MB
- Stars: 163
- Watchers: 5
- Forks: 19
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# SwipeActions
[![Latest release](https://img.shields.io/github/v/release/c-villain/SwipeActions?color=brightgreen&label=version)](https://github.com/c-villain/SwipeActions/releases/latest)
[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fc-villain%2FSwipeActions%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/c-villain/SwipeActions)
[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fc-villain%2FSwipeActions%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/c-villain/SwipeActions)
[![](https://img.shields.io/badge/SPM-supported-DE5C43.svg?color=brightgreen)](https://swift.org/package-manager/)
![](https://img.shields.io/github/license/c-villain/SwipeActions)[![contact: @lexkraev](https://img.shields.io/badge/contact-%40lexkraev-blue.svg?style=flat)](https://t.me/lexkraev)
[![Telegram Group](https://img.shields.io/endpoint?color=neon&style=flat-square&url=https%3A%2F%2Ftg.sumanjay.workers.dev%2Fswiftui_dev)](https://telegram.dog/swiftui_dev)
Library for creating swipe actions for any SwiftUI View, similar to Apple's [```swipeActions(edge:allowsFullSwipe:content:)```](https://developer.apple.com/documentation/swiftui/view/swipeactions(edge:allowsfullswipe:content:)) that available from iOS 15 and only in [List](https://developer.apple.com/documentation/swiftui/lists) 🤷🏼♂️.
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](https://t.me/swiftui_dev)** in telegram.
## Requirements
- iOS 13.0 or macOS 10.15
## Installation
#### Swift Package Manager
To integrate ```SwipeActions``` into your project using SwiftPM add the following to your `Package.swift`:
```swift
dependencies: [
.package(url: "https://github.com/c-villain/SwipeActions", from: "0.1.0"),
],
```
or via [XcodeGen](https://github.com/yonaskolb/XcodeGen) insert into your `project.yml`:```yaml
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:
## Quick start
Adding both leading and trailing swipe actions:
Use ```Leading { ... }``` and ```Trailing { ... }``` closures inside ```.addSwipeAction { ... }``` modifier:
```swift
import SwipeActionsstruct 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 { //<= HEREButton {
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)
}
}
}
}
}
}
}
```Adding swipe actions to one side of view:
Use ```.addSwipeAction(edge: ) { ... }``` modifier, ```edge``` - a ```HorizontalAlignment``` value input parameter - with two cases of using ```.leading``` or ```.trailing```
```swift
import SwipeActionsstruct 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) { // <== HERE! choose .trailing or .leading
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)
}
}
}
}
}
}
```For automatically closing other opened actions during sliding:
Add ```SwipeState``` var to your ```View``` and pass it as a ```binding``` in ```.addSwipeAction(state:)```:
```swift
struct YourView: View {
@State var state: SwipeState = .untouched // <=== HEREvar body: some View {
ScrollView {
VStack(spacing: 2) {
ForEach(1 ... 30, id: \.self) { cell in
Text("Cell \(cell)")
.addSwipeAction(state: $state) { // <=== HERE
....
}
}
}
}
}
}
```
### 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.
.destructive
This role is used for closing/hiding/removing cell.
```swift
struct YourView: View {
@State var range: [Int] = [1,2,3,4,5,6,7,8,9,10]var body: some View {
ScrollView {
VStack(spacing: 2) {
ForEach(range, id: \.self) { cell in
Text("Cell \(cell)")
.addFullSwipeAction(menu: .slided,
swipeColor: .red) { // <=== Color is the same as last button in Trailing for full effect
Leading {
...
}
Trailing {
...
Button {
withAnimation {
if let index = range.firstIndex(of: cell) {
range.remove(at: index)
}
}
} label: {
Image(systemName: "trash")
.foregroundColor(.white)
}
.contentShape(Rectangle())
.frame(width: 60)
.frame(maxHeight: .infinity)
.background(Color.red) // <=== Look here
}
} action: { // <=== action for full swiping
withAnimation {
if let index = range.firstIndex(of: cell) {
range.remove(at: index)
}
}
}
}
}
}
}
}
```
.defaults
This role is used for making some action on cell.
```swift
struct YourView: View { ]var body: some View {
ScrollView {
VStack(spacing: 2) {
ForEach(1...10, id: \.self) { cell in
Text("Cell \(cell)")
.addFullSwipeAction(menu: .slided,
swipeColor: .green, // <=== Color is the same as last button in Trailing for full effect
swipeRole: .defaults) { // <=== Add this parameter
Leading {
...
}
Trailing {
...
Button {
} label: {
Image(systemName: "trash")
.foregroundColor(.white)
}
.contentShape(Rectangle())
.frame(width: 60)
.frame(maxHeight: .infinity)
.background(Color.green) // <=== Look here
}
} action: { // <=== action for full swiping
...
}
}
}
}
}
}
```
### Recommendations for useWith dynamic height content.
use ```.frame(maxHeight: .infinity)``````swift
YourView()
.addSwipeAction(menu: .slided, edge: .trailing) {
Button {
...
} label: {
Image("trash")
.font(.system(size: 20.0))
.foregroundColor(.white)
.frame(width: 68, alignment: .center)
.frame(maxHeight: .infinity) // <====== HERE
.background(.red)
}
}
```With transparent colored views.
There is *no* restrictions or any recommendations for using with ```.slided``` type!
With ```.swiped``` use *non-tranparent* color layer or the same color with ```alfa = 1.0```:```swift
ForEach(1 ... 30, id: \.self) { cell in
Text("Cell \(cell)")
.padding()
.frame(height: 80)
.frame(maxWidth: .infinity)
//.background(Color.green.opacity(0.2)) // <=== DON'T USE SUCH WAY!
//.background(Color(red: 0.841, green: 0.956, blue: 0.868)) // <== USE THIS WAY!
.background( // <== OR THIS WAY!
ZStack {
Color(UIColor.systemBackground) // non-transparent color layer
Color.green.opacity(0.2)
}
).contentShape(Rectangle())
.listStyle(.plain)
.addSwipeAction(menu: .swiped, // <=== SWIPED TYPE
state: $state) {
Leading {
...
}
}
...
}
```With List.
Basically if you have minimum deployments target for your app is iOS 15 I recommend to use Apple's [swipe actions](https://developer.apple.com/documentation/swiftui/view/swipeactions(edge:allowsfullswipe:content:)) for List. Anyway you may use this.
Due to some features for working with ```List``` you should:
- specify a frame for cell width, e.g. ```.frame(width: UIScreen.main.bounds.size.width - 32, height: 80)``` and a frame for buttons on swipe actions, e.g. ```.frame(width: 60, height: 80)```. Note that height in frames should be the same!
- add modifier ```.onTapGesture { ... }``` for cell to override tapping on swipe action buttons
- add modifier ```.listRowInsets(EdgeInsets())``` for cell
```swift
List(elements) { e in
Text(e.name)
.frame(width: UIScreen.main.bounds.size.width - 32, height: 80) // <=== HERE
.background(Color(UIColor.systemBackground))
.onTapGesture { // <=== HERE
print("on cell tap!")
}
.addSwipeAction(menu: .swiped,
edge: .trailing,
state: $state) {
Button {
print("remove")
} label: {
Image(systemName: "trash")
.foregroundColor(.white)
}
.frame(width: 60, height: 80, alignment: .center) // <=== HERE
.contentShape(Rectangle())
.background(Color.red)
}
.listRowInsets(EdgeInsets()) // <=== HERE
}
.padding(16)
```Look for code in the example.
With no horizontal padding views.
To avoid effect when content in swipe actions started showing immediately after view with no horizontal padding
in ```.addSwipeAction { ... }``` add ```Rectangle``` filled with *same* color as root view:
```swift
YourView()
.frame(height: 80)
.frame(maxWidth: .infinity)
.background(Color.green.opacity(0.8)) // <=== Look here!
.addSwipeAction(edge: .trailing) {
Rectangle() // <=== HERE!
.fill(Color.green.opacity(0.8)) // <=== Don't forget!
.frame(width: 8.0, height: 80)Button {
} label: {
Image(systemName: "message")
.foregroundColor(.white)
}
.frame(width: 60, height: 80)
.contentShape(Rectangle())
.background(Color.blue)
}
```With context menu.
Due to some difficulties for SwiftUI to detect gestures for sliding view and opening context menu I recommend you to use
`.contextMenu` after `.addSwipeAction` (or `addFullSwipeAction`):```swift
YourView()
.frame(height: 80)
.frame(maxWidth: .infinity)
.contentShape(Rectangle())
.padding()
.background(Color(UIColor.systemBackground))
.addFullSwipeAction(...) { ... } // <=== Look here!
.contextMenu { ... }
```Actually if you don't use `.contentShape(Rectangle())`, you can also add `.contextMenu` before `.addSwipeAction` (or `addFullSwipeAction`):
```swift
YourView()
.frame(height: 80)
.frame(maxWidth: .infinity)
//.contentShape(Rectangle()) // <=== Look here!
.padding()
.contextMenu { ... } // <=== Look here!
.background(Color(UIColor.systemBackground))
.addFullSwipeAction(...) { ... } // <=== Look here!
```How to add swpe hint.
Use modifier `.swipeHint`:
```swift
ForEach(range, ...) {
YourCell()
...
.addFullSwipeAction(
menu: .slided,
swipeColor: .red,
state: $state) {
Leading {
...
}
Trailing {
...
}
}
.swipeHint(cell == range.first, hintOffset: 120.0) // for trailing <== LOOK HERE
.swipeHint(cell == range[1] , hintOffset: -120.0) // for leading <== LOOK HERE
...
}
```## Communication
- If you **found a bug**, open an issue or submit a fix via a pull request.
- If you **have a feature request**, open an issue or submit a implementation via a pull request or hit me up on **[email protected]** or **[telegram](https://t.me/lexkraev)**.
- If you **want to contribute**, submit a pull request onto the master branch.## License
SwipeActions package is released under an MIT license.
## Special thanks
Thx to [Prafulla Singh](https://prafullkumar77.medium.com/) for inspriration with his [SwiftUI tutorial](https://prafullkumar77.medium.com/swiftui-how-to-make-custom-swipe-able-cell-727a27abdddd).