A set of SwiftUI custom modifiers to make the ScrollView snappable.

Overview

Snappable

A set of SwiftUI custom modifiers to make the ScrollView snappable.

The goal of this library is to provide an easy way to implement Views such as carousels and slideshows.

Demo

Carousel demo Vertical demo

Requirements

  • iOS 14.0+
  • Swift 5.3+

Note

Snappable depends on Introspect for SwiftUI due to detect the behavior of scrolling from UIScrollView, so this is fragile on iOS or SwiftUI upates.

Installation

Swift Package Manager

.package(
  url: "https://github.com/hugehoge/Snappable.git",
  .upToNextMinor(from: "0.2.0")
)

Usage

Basic

struct ContentView: View {
  @State private var items: [Item]

  var body: some View {
    ScrollView(.horiaontal) {
      LazyHStack {
        ForEach(items, id: \.self) { item in
          ItemView(item)
            .snapID(item)  // Step 1
        }
      }
    }
    .snappable()  // Step 2
  }
}
  1. Added .snapID(_:) modifier to items in ScrollView
    • snapID applies .id(_:) modifier internally
  2. Added .snappable(_:mode:) modifier to ScrollView

Options

Alignment

The snap anchor point can be set as an option.

.snappable(alignment: .leading)

Available alignment parameters are below:

  • .top
  • .leading
  • .center
  • .trailing
  • .bottom

SnapMode

You can determine the snap timing after the end of the drag with following parameters.

  • .afterScrolling
  • .immediately

Both parameters are set together with scrolling deceleration rate.

.snappable(alignment: .center, mode: .afterScolling(decelerationRate: .fast))
.snappable(alignment: .center, mode: .immediately(decelerationRate: .normal, withFlick: false))
Comments
  • Do not work inside LazyVStack

    Do not work inside LazyVStack

    Environment

    • Xcode 13.2.1
    • iOS 15.2 simulator
    • Snappable 0.2.0

    Reproduction

    struct ContentView: View {
      var body: some View {
        ScrollView {
          LazyVStack {
            Color.gray.frame(height: UIScreen.main.bounds.height * 2)
    
            ScrollView(.horizontal, showsIndicators: false) {
              HStack {
                ForEach(0..<30) { index in
                  Color.red
                      .frame(width: 240, height: 135)
                      .snapID(index)
                }
              }
            }
            .snappable()
          }
        }
      }
    }
    

    |Reproduction|Replace to VStack| |-|-| |

    bug 
    opened by hugehoge 1
  • Fix the timing of introspecting UIScrollView

    Fix the timing of introspecting UIScrollView

    Resolve #15

    To fix an issue when it is used inside LazyVStack, modify the code implemented in Introspect for SwiftUI.

    I adopted the following steps to avoid any unexpected side effects.

    1. Copy the code from Introspect for SwiftUI and place it in this repository
      • Add the original license to LICENSE file
    2. Remove dependencies of Introspect for SwiftUI
    3. Refactor the copied code
      • This library only requires UIScrollView related implementation
    4. Fix the timing of introspecting views

    Result

    struct ContentView: View {
      var body: some View {
        ScrollView {
          LazyVStack {
            Color.gray.frame(height: UIScreen.main.bounds.height * 2)
    
            ScrollView(.horizontal, showsIndicators: false) {
              HStack {
                ForEach(0..<30) { index in
                  Color.red
                      .frame(width: 240, height: 135)
                      .snapID(index)
                }
              }
            }
            .snappable()
          }
        }
      }
    }
    

    |Before|After| |:-:|:-:| |

    bug changes 
    opened by hugehoge 0
  • Snap stopped when tapping in scrolling

    Snap stopped when tapping in scrolling

    Overview

    In .immediately mode, snap animation stops when tapping in scrolling.

    Reproduction

    struct ContentView: View {
      var body: some View {
        ScrollView(.horizontal) {
          LazyHStack {
            ForEach(0..<100) { index in
              ZStack {
                Color.gray
                Text("\(index)")
              }
              .frame(width: 300, height: 200)
              .snapID(index)
            }
          }
        }
        .snappable(.center, mode: .immediately)
      }
    }
    

    https://user-images.githubusercontent.com/29995702/147861813-751fe0c9-c262-4708-aa3c-df891cd89dde.mp4

    Note

    Do not happen with .afterScrolling mode.

    bug 
    opened by hugehoge 0
  • Nice project - Hoping for couple of improvments - Disable scrolling if not required - Respond to Dynamic Font Sizing.

    Nice project - Hoping for couple of improvments - Disable scrolling if not required - Respond to Dynamic Font Sizing.

    Hi, Thanks for this nice project, just hoping for the following 2 features they are kind of important:-

    1- Disable scrolling if not required. 2- Respond to Dynamic Font Sizing. (Accessibility)

    Kind Regards,

    Wael

    opened by waelsaad 0
  • Fast swipe leads to skip items

    Fast swipe leads to skip items

    I just started experimenting with SwiftUI and found this amazing package which saved me from implementing this from zero. However I just discovered a bug:

    When swiping long and fast in the horizontal scroll item, sometimes one item is skipped and the scroll snaps to the next item and one is skipped. See attached example project recording. First two times I used a "soft" swipe and everything worked fine, afterwards note that when a long and fast swipe is used the list stopped at item number 3 instead of 2.

    Thank you so much, Zoltán

    https://user-images.githubusercontent.com/109680834/180018940-12304488-82a2-4df8-b7d6-0b9d5b541fb3.mp4

    opened by bolonnd 0
Releases(0.3.0)
Owner
hugehoge
hugehoge
ToDoList - An ios app that help users to set their todos and make it easy to remember this todos

An ios app that help users to set their todos and make it easy to remember this todos by reminders them when todo time's up, this app make sure that you don't forget any todos that you want to do just give it to the app and let the app hundle it for you.

Ahmed Mahrous 1 Apr 25, 2022
Social App - In that application I desided to make a custom messenger service

Social App About the project / О проекте English In that application I desided to make a custom messenger service. Project is on early development sta

null 0 Dec 6, 2021
SwiftUI Backports - Introducing a collection of SwiftUI backports to make your iOS development easier

SwiftUI Backports Introducing a collection of SwiftUI backports to make your iOS development easier. Many backports support iOS 13+ but where UIKIt fe

Shaps 530 Dec 28, 2022
Set of available SF Symbols

SFSymbolsFinder SFSymbolsFinder is a convenient library to get whole list of available latest SF Symbols image Introduction SFSymbolsFinder introduces

Michael Abadi Santoso 54 Jan 3, 2023
The demo project to show how to organize code to make SwiftUI apps easy to be test.

TestableApp I combined the idea to use functional programming instead of an loader instance in ModelView(I prefer to think of it as a service) and Res

VictorK 2 Jan 7, 2022
A mobile application project designed for everybody which provides the easiest way to make searchs for public services

A mobile application project designed for everybody which provides the easiest way to make searchs for public services

null 0 Nov 23, 2021
An iOS app to make your love for Pokemon real.

An iOS app to make your love for Pokemon real.Which offers to make your pokemon cards live as if they were pokeballs. Each card has its own pokemon stored in it as a picturised but what if you had the powers of god to make it real and enjoyable. Don't worry now you do.Use our Poke3D and you're the god of pokemons.

Dishant Nagpal 1 Feb 27, 2022
SwiftUI & Combine app using MovieDB API. With a custom Flux (Redux) implementation.

MovieSwiftUI MovieSwiftUI is an application that uses the MovieDB API and is built with SwiftUI. It demos some SwiftUI (& Combine) concepts. The goal

Thomas Ricouard 6.2k Jan 8, 2023
An example of creating custom popups in SwiftUI

Custom Popup Example An example project for Implementing custom popups in SwiftUI article. Author Artem Novichkov, [email protected] License The

Artem Novichkov 37 Dec 10, 2022
Your SwiftUI custom slider is crap. Here's mine, which is also crap, but it's my crap

Fuck your custom slider It doesn't work. Sure, it looks great, with gradients, and multiple thumbs, but really, it's useless. No more paying for a sub

Rob Bishop 0 Nov 29, 2021
INTUZ is presenting an interesting a custom alert view in SwiftUI

Introduction INTUZ is presenting an interesting a custom alert view in SwiftUI, App Control to integrate inside your native iOS-based application. Cus

INTUZ 2 Jul 10, 2022
A collection of additional custom SFSymbols for Swift

MoreSFSymbols A collection of additional custom SFSymbols for Swift Content Usage Symbols Developer Logos Contributing Licence Usage iOS 15.0: Downloa

Cameron Shemilt 57 Dec 2, 2022
🎲 100% SwiftUI 2.0, classic 2048 game [SwiftUI 2.0, iOS 14.0+, iPadOS 14.0+, macOS 11.0+, Swift 5.3].

swiftui-2048 If you like the project, please give it a star ⭐ It will show the creator your appreciation and help others to discover the repo. ✍️ Abou

Astemir Eleev 174 Dec 17, 2022
A simple SwiftUI Application to demonstrate creation of UI using SwiftUI.

WatchShop_UI A simple SwiftUI Application to demonstrate creation of UI using SwiftUI. How to run the project ? Fork the project. Run the project usin

Shubham Kr. Singh 12 Apr 15, 2022
E-commerce app built in SwiftUI. Built in the course SwiftUI Masterclass in Udemy.

Touchdown-SwiftUI E-commerce app built in SwiftUI. Built in the course SwiftUI Masterclass in Udemy. Main components and concepts used: @EnvironmentOb

Jorge Martinez 5 Aug 18, 2022
A multiplatform SwiftUI project demonstrating various SwiftUI features.

WikiDemo A multiplatform SwiftUI project demonstrating various SwiftUI features, including creating a master-detail interface. It's a multiplatform ve

Swift Dev Journal 6 Oct 17, 2022
SwiftUI Projects from Udemy SwiftUI Masterclass

SwiftUI Masterclass Repos: AsyncImage (N/A) Fructus (finished): an app for getting information about different fruits. Data comes from json files. Afr

Patrick Spafford 1 Mar 3, 2022
Best architecture for SwiftUI + CombineBest architecture for SwiftUI + Combine

Best architecture for SwiftUI + Combine The content of the presentation: First of the proposed architectures - MVP + C Second of the proposed architec

Kyrylo Triskalo 3 Sep 1, 2022