Giter Site home page Giter Site logo

aheze / swipeactions Goto Github PK

View Code? Open in Web Editor NEW
908.0 5.0 37.0 8.74 MB

Add customizable swipe actions to any view.

Home Page: https://twitter.com/aheze0/status/1646399867764510721

License: MIT License

Swift 100.00%
gesture ios notifications swift swiftui swipe swipe-actions drag list

swipeactions's Introduction

SwipeActions

Add customizable swipe actions to any view.

  • Enable swipe actions on any view, not just Lists.
  • Customize literally everything โ€” corner radius, color, etc...
  • Supports drag-to-delete and advanced gesture handling.
  • Fine-tune animations and styling to your taste.
  • Programmatically show/hide swipe actions.
  • Automatically close when interacting with other views.
  • Made with 100% SwiftUI. Supports iOS 14+.
  • Lightweight, no dependencies. One file.
General Basics Customization
Styles Animations Advanced

Installation

SwipeActions is available via the Swift Package Manager. Alternatively, because all of SwipeActions is contained within a single file, drag SwipeActions.swift into your project. Requires iOS 14+.

https://github.com/aheze/SwipeActions

Usage

import SwiftUI
import SwipeActions

struct ContentView: View {
    var body: some View {
        SwipeView {
            Text("Hello")
                .frame(maxWidth: .infinity)
                .padding(.vertical, 32)
                .background(Color.blue.opacity(0.1))
                .cornerRadius(32)
        } trailingActions: { _ in
            SwipeAction("World") {
                print("Tapped!")
            }
        }
        .padding()
    }
}

The result, 'World' displayed on the right.

Examples

Check out the example app for all examples and advanced usage!

2 screenshots of the example app

Customization

SwipeActions supports over 20 modifiers for customization. To use them, simply attach the modifier to SwipeAction/SwipeView.

SwipeView {
    Text("Hello")
} leadingActions: { _ in
} trailingActions: { _ in
    SwipeAction("World") {
        print("Tapped!")
    }
    .allowSwipeToTrigger() /// Modifiers for `SwipeAction` go here.
}
.swipeActionsStyle(.cascade) /// Modifiers for `SwipeView` go here.
// MARK: - Available modifiers for `SwipeAction` (the side views)

/**
 Apply this to the edge action to enable drag-to-trigger.

     SwipeView {
         Text("Swipe")
     } leadingActions: { _ in
         SwipeAction("1") {}
             .allowSwipeToTrigger()

         SwipeAction("2") {}
     } trailingActions: { _ in
         SwipeAction("3") {}

         SwipeAction("4") {}
             .allowSwipeToTrigger()
     }
 */
func allowSwipeToTrigger(_ value: Bool = true)

/// Constrain the action's content size (helpful for text).
func swipeActionLabelFixedSize(_ value: Bool = true) 

/// Additional horizontal padding.
func swipeActionLabelHorizontalPadding(_ value: Double = 16)

/// The opacity of the swipe actions, determined by `actionsVisibleStartPoint` and `actionsVisibleEndPoint`.
func swipeActionChangeLabelVisibilityOnly(_ value: Bool) 
// MARK: - Available modifiers for `SwipeView` (the main view)

/// The minimum distance needed to drag to start the gesture. Should be more than 0 for best compatibility with other gestures/buttons.
func swipeMinimumDistance(_ value: Double) 

/// The style to use (`mask`, `equalWidths`, or `cascade`).
func swipeActionsStyle(_ value: SwipeActionStyle) 

/// The corner radius that encompasses all actions.
func swipeActionsMaskCornerRadius(_ value: Double) 

/// At what point the actions start becoming visible.
func swipeActionsVisibleStartPoint(_ value: Double) 

/// At what point the actions become fully visible.
func swipeActionsVisibleEndPoint(_ value: Double)

/// The corner radius for each action.
func swipeActionCornerRadius(_ value: Double) 

/// The width for each action.
func swipeActionWidth(_ value: Double) 

/// Spacing between actions and the label view.
func swipeSpacing(_ value: Double) 

/// The point where the user must drag to expand actions.
func swipeReadyToExpandPadding(_ value: Double) 

/// The point where the user must drag to enter the `triggering` state.
func swipeReadyToTriggerPadding(_ value: Double) 

/// Ensure that the user must drag a significant amount to trigger the edge action, even if the actions' total width is small.
func swipeMinimumPointToTrigger(_ value: Double) 

/// Applies if `swipeToTriggerLeadingEdge/swipeToTriggerTrailingEdge` is true.
func swipeEnableTriggerHaptics(_ value: Bool) 

/// Applies if `swipeToTriggerLeadingEdge/swipeToTriggerTrailingEdge` is false, or when there's no actions on one side.
func swipeStretchRubberBandingPower(_ value: Double)

/// If true, you can change from the leading to the trailing actions in one single swipe.
func swipeAllowSingleSwipeAcross(_ value: Bool) 

/// The animation used for adjusting the content's view when it's triggered.
func swipeActionContentTriggerAnimation(_ value: Animation)

/// Values for controlling the close animation.
func swipeOffsetCloseAnimation(stiffness: Double, damping: Double)

/// Values for controlling the expand animation.
func swipeOffsetExpandAnimation(stiffness: Double, damping: Double)

/// Values for controlling the trigger animation.
func swipeOffsetTriggerAnimation(stiffness: Double, damping: Double)

Example usage of these modifiers is available in the example app.

Notes

  • To automatically close swipe views when another one is swiped (accordion style), use SwipeViewGroup.
SwipeViewGroup {
    SwipeView {} /// Only one of the actions will be shown.
    SwipeView {}
    SwipeView {}
}
  • To programmatically show/hide actions, use the context parameter.
import Combine
import SwiftUI
import SwipeActions

struct ProgrammaticSwipeView: View {
    @State var open = PassthroughSubject<Void, Never>()

    var body: some View {
        SwipeView {
            Button {
                open.send() /// Fire the `PassthroughSubject`.
            } label: {
                Text("Tap to Open")
                    .frame(maxWidth: .infinity)
                    .padding(.vertical, 32)
                    .background(Color.blue.opacity(0.1))
                    .cornerRadius(32)
            }
        } trailingActions: { context in
            SwipeAction("Tap to Close") {
                context.state.wrappedValue = .closed
            }
            .onReceive(open) { _ in /// Receive the `PassthroughSubject`.
                context.state.wrappedValue = .expanded
            }
        }
    }
}
  • To enable swiping on transparent areas, add .contentShape(Rectangle()).
SwipeView {
    Text("Lots of empty space here.")
        .frame(maxWidth: .infinity)
        .padding(.vertical, 32)
        .contentShape(Rectangle()) /// Enable swiping on the empty space.
} trailingActions: { _ in
    SwipeAction("Hello!") { }
}
  • Everything in the example app is swipeable โ€” even the gray-capsule headers!

The 'Styles' header swiped to the left and the 'Open' action shown on the right.

Community

Author Contributing Need Help?
SwipeActions is made by aheze. All contributions are welcome. Just fork the repo, then make a pull request. Open an issue or join the Discord server. You can also ping me on Twitter.

License

MIT License

Copyright (c) 2023 A. Zheng

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

SwipeActions.mp4

swipeactions's People

Contributors

aheze avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

swipeactions's Issues

Scroll doesn't work in the example app

Whenever I try to scroll up or down in the example app, it only works if I use the left or right edge of the screen. Does it work inside scroll views?

SwipeAction has some unknown minimum corner radius

Trying to make a SwipeView and SwipeAction that both have a corner radius less than about 18 makes the SwipeView have a smaller corner radius than the Swipe Action. I want a corner radius of 12, but I am not able to because the swipeActionCornerRadius() modifier doesn't do anything below values of around 18.

    var body: some View {
        SwipeView {
            Text("Hello")
                .frame(maxWidth: .infinity)
                .padding(.vertical, 20)
                .background(Color.blue.opacity(0.1))
                .cornerRadius(12)
        } trailingActions: { _ in
            SwipeAction("World") {
                print("Tapped!")
            }
        }
        .swipeActionCornerRadius(12)
    }

Screenshot 2023-06-06 at 5 03 12 PM

"Hint" style (option to set custom swipe offset)

Many apps with swipe actions display a "hint" to let the user know that swipe actions are available.

SwipeActions should have an option for programmatically setting a custom offset (~20px or so).

Accessibility Support

VoiceOver support needs to be added.

  • [] Read out swipe actions (currently they're completely ignored)
  • [] Option to group main label content as a single accessibility element

Detect Swipe Action Context State

I need something like this to adjust SwipeView

SwipeView {
    teamNoteRow(note: note)
        .contentShape(Rectangle())
} trailingActions: { context in
    SwipeAction(action: {
        withAnimation {
            viewModel.deleteNote(id: note.id)
        }
    }, label: { _ in
        Image(systemName: "trash")
            .foregroundColor(Color.white)
    }, background: { _ in
        Color.red
    })
    .onReceive(context) { newValue in
        isTrailingActionVisible = context == .open // globaly detect state of swipe actions
}

Check if UIImpactGenerator is allowed

Yes, IK swipe actions maybe not the perfect thing for vision pro, but I have an ios app using this library which I would love to try out (including swiping) and it fails to build because their is no Haptic feedback

Can't access SwipeView id

Documentation says it's possible to override id by set options.id, however i couldn't find any thing related.

Screenshot 2024-02-01 at 12 26 48

Access the SwipeView id is important for context where we're trying to open multiple rows programmatically. SwipeViewGroup doesn't seem to be affected by context state changes like context.state.wrappedValue = context.state.wrappedValue == .expanded ? .closed : .expanded, so access id would allow us to set correctly the swipeViewGroupSelection and eventually automatically close not target rows.

Multiple actions collapsing on long swipe?

Is there a way to make it so that if there are multiple actions on a view, if the user swipes a certain threshold it shows action1, if they keep swiping it switches to action2?

And if so, can they support swipe to perform action? As in, if they swipe a certain amount while action1 is showing and release it fires the event

example: https://wefwef.app/posts/lemmy.world/all
if you swipe on a post it shows 1 action, continue swiping it shows action 2? (this example appears to be heavily inspired by Apollo)

Issue on tapping 3rd of 4 buttons in .mask ActionStyle

I've been using this as a workaround for a bug with SwiftUI lists in lists.

In my example, I've hit an issue where I have four swipe action buttons, two leading and two trailing with a 90 or 100 width. The style is set to .mask.

In this situation the 3rd swipe button (the first on the right and the leftmost right/trailing button) is only tappable on its right side and not on its left side.

If the style is changed to .cascade or .equalWidths the 3rd button becomes fully tappable instead of half-tappable.

If you have any quick answers feel free to reply.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.