Skip to content

High performance, super simple & customizable (SwiftUI 5+ / iOS 17+) Snap View Pager / Carousel.

License

Notifications You must be signed in to change notification settings

MaximeFILIPPI/SnapPagerCarousel

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

54 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Platforms License: MIT

SnapPager

A lightweight SwiftUI View for iOS 17 (and newer) that provides you an easy-to-use Pager / Carousel like TabView but better, faster, stronger πŸ’ͺ.

It allows you to create a horizontally scrolling list of items and custom views with centered snapping behavior, making it perfect for creating your own sliding views, images gallery, product carousels, onboarding, showcase, etc...

It is also highly performant, as the views are lazy loaded making it ideal for displaying a infinite number of pages efficiently.

screenshot screenshot

Features

βœ… Easy-to-use

βœ… 100% SwiftUI

βœ… Automatically handles user interactions

βœ… Horizontal scrolling with snapping behavior

βœ… Supports binding and controls for both selection modes: item or index.

βœ… Supports any kind items: struct / class / objects (note: Must be Hashable)

⚠️ Experimental: overlap and spacing between items

Requirements

  • iOS 17.0+
  • SwiftUI 5.0+

Installation

Swift Package Manager:

XCode > File > Add Package Dependency...

Enter the following URL of the repository into the search:

https://github.com/MaximeFILIPPI/SnapPagerCarousel

Follow the prompts to complete the installation.

Basic Usage

Here is an example of how to integrate and use SnapPager in your SwiftUI views:

import SwiftUI
import SnapPagerCarousel // <- Import

struct ContentView: View {
    
    @State var items: [YourItemType] = []       // <- Your items (should be Hashable)
    @State var selectedItem: YourItemType?      // <- Should match your items type
    @State var selectedItemIndex: Int = 0       // <- This keeps track of the page index
    
    var body: some View {
        
        SnapPager(items: $items,
                  selection: $selectedItem,
                  currentIndex: $selectedItemIndex) { index, item in
            
            YourCustomView(item) // <- Your content to display for each page here
            
        }
        
    }
    
}

In this example, items is an array of custom object / struct / class that you want to use to display some infos in the pager. You can customize the appearance of each page by providing your own view inside the content closure. The content closure returns an index and an item for your custom view (the ones corresponding to the page to load).

How To Programmatically?

The SnapPager view automatically handles the horizontal paging and snapping behavior. If you wish to change the selected item and go to another one it is really easy. You just have to set a new value for selectedItem or selectedItemIndex and it will automatically scroll to the position of the item wanted.

Example if you want to go to a certain position

// Function to navigate to the next page
func goToNextPage()
{
    self.selectedItemIndex += 1
}

or if you prefer to just change the item

// Function to navigate to the next item
func goToNextItem()
{
    self.selectedItem = items[selectedItemIndex+1]
}

Customization (Experimental)

You can slightly customize the appearance of your pager by adjusting the edgesOverlap and itemsMargin properties that controls how much adjacent your pages should overlap when snapping.

It gives a kind of carousel-like vibes to your pager (cf examples-map).

SnapPager(items: $items,
          selection: $selectedItem,
          currentIndex: $selectedItemIndex,
          edgesOverlap: 16, // Adjust as needed (controls overlap between pages)
          itemsMargin: 8    // Adjust as needed (controls margin between pages)
          ) { index, item in
          
    // Your content for each page here
    CustomView(item)
    
}

Note Be careful not to set the edgesOverlap or itemsMargin too high as the native SwiftUI scrollview (used by SnapPager) seems to have issue determining the correct item selected & will lose track of the other ones.

Examples

Please refer to the directory EXAMPLES for fully detailed code on how to achieve certain effects.

Here is how simple it is to bind the SnapPager to a Map (from MapKit); You just have to use the same @State variable for the places and selectedPlace:

import SwiftUI
import MapKit
import SnapPagerCarousel

struct ExampleMapView: View {

    @State private var cameraPosition: MapCameraPosition = .automatic
    
    // Same items for Map AND SnapCarousel
    @State var places: [Place] = []
    
    // Same selected item for Map AND SnapPager
    @State var selectedPlace: Place?
    
    // Index of selected place (if needed)
    @State var indexPlace: Int = 0
    
    
    var body: some View {
        
        ZStack(alignment: .bottom)
        {
            // Map SwiftUI
            Map(position: $cameraPosition, selection: $selectedPlace) {
                
                ForEach(places, id: \.self) { place in
                    
                    Marker(place.name,
                           systemImage: place.icon,
                           coordinate: CLLocationCoordinate2D(latitude: place.latitude,
                                                              longitude: place.longitude))
                    .tint(place.color)
                    .tag(place)
                    
                }
                
            }.mapStyle(.standard(pointsOfInterest: .excludingAll))
            
            
            // Bottom Cards SlideShow
            SnapPager(items: $places,
                      selection: $selectedPlace,
                      currentIndex: $indexPlace,
                      edgesOverlap: 40,
                      itemsMargin: 10) { index, place in
             
                PlaceCardView(place: place)
                
            }.frame(maxHeight: 100)
            
        }
        
    }
    
}

Another example for a fullscreen ViewPager experience with custom PagerIndicator

import SwiftUI
import SnapPagerCarousel

struct ExampleOnBoardingView: View {
    
    @State var pages: [OnBoarding] = [ ]
    
    @State var pageSelected: OnBoarding?
    @State var pageIndex: Int = 0
    
    var body: some View {
        
        ZStack(alignment:.bottom)
        {
            // Pager Mode
            SnapPager(items: $pages,
                      selection: $pageSelected,
                      currentIndex: $pageIndex) { index, page in
                
                OnBoardingPageView(page: page, position: index)
            }
            
            // Indicator at the bottom
            PagerIndicatorView(pages: $pages,
                               pageSelected: $pageSelected)
            
        }
        .background(Color.black)
        .ignoresSafeArea()
    }
    
}


// -------------------------------------------------------------

struct PagerIndicatorView: View {
    
    @Binding var pages: [OnBoarding]
    
    @Binding var pageSelected: OnBoarding?
    
    
    var body: some View
    {
        // Custom pager Indicator
        HStack
        {
            ForEach(pages, id: \.self) { page in
                
                Button(role: .none) {
                    
                    self.selectPage(page)
                    
                } label: {
                    
                    Capsule()
                        .fill(.white)
                        .opacity(page == pageSelected ? 0.5 : 0.25)
                        .frame(width: page == pageSelected ? 22 : 8, height: 8)
                }
                
            }
            
        }
        .padding(.bottom, 48)
    }
    
    
    func selectPage(_ page: OnBoarding)
    {
        withAnimation {
            self.pageSelected = page
        }
    }
    
}

License

SnapPager is available under the MIT license. See the LICENSE file for more details.

Credits

SnapPager is developed and maintained by [Maxime FILIPPI].

If you encounter any issues or have suggestions for improvements, please open an issue.

About

High performance, super simple & customizable (SwiftUI 5+ / iOS 17+) Snap View Pager / Carousel.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Languages