Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/gh123man/swiftui-lazypager

A SwiftUI, lazy loaded, paging, panning, and zooming view for images and more
https://github.com/gh123man/swiftui-lazypager

ios swift swiftui

Last synced: 4 days ago
JSON representation

A SwiftUI, lazy loaded, paging, panning, and zooming view for images and more

Awesome Lists containing this project

README

        

# LazyPager for SwiftUI

A buttery smooth, lazy loaded, panning, zooming, and gesture dismissible view pager view for SwiftUI.

The goal of this package is to expose a simple SwiftUI interface for a fluid and seamless content viewer. Unlike other pagers for SwiftUI - this is built on top of UIKit APIs exposing features not yet available in SwiftUI.

### Horizontal


animated

The above example is from [dateit](https://dateit.com/) demonstrating the capabilities of this library. Note: the overlay is custom and can be added by putting `LazyPager` inside a `ZStack`.

### Vertical


animated

The above example [can be found in the example project.](https://github.com/gh123man/SwiftUI-LazyPager/blob/master/Examples/LazyPagerExampleApp/VerticalMediaPager.swift)

# Usage

## Add the Swift Package

1. Right click on your project -> `Add Package`
2. In the search bar paste: `https://github.com/gh123man/LazyPager`
3. Click `Add Package`

Or add the package to your `Package.swift` if your project is a Swift package.

## Examples

### Simple Example
A simple image pager that displays images by name from your app assets.

```swift
@State var data = [ ... ]

var body: some View {
LazyPager(data: data) { element in
Image(element)
.resizable()
.aspectRatio(contentMode: .fit)
}
}
```

That's it!

### Detailed Example

```swift
@State var data = [ ... ]
@State var show = true
@State var opacity: CGFloat = 1 // Dismiss gesture background opacity
@State var index = 0

var body: some View {
Button("Open") {
show.toggle()
}
.fullScreenCover(isPresented: $show) {

// Provide any list of data and bind to an index
LazyPager(data: data, page: $index) { element in

// Supports any kind of view - not only images
Image(element)
.resizable()
.aspectRatio(contentMode: .fit)
}

// Make the content zoomable
.zoomable(min: 1, max: 5)

// Enable the swipe to dismiss gesture and background opacity control
.onDismiss(backgroundOpacity: $opacity) {
show = false
}

// Handle single tap gestures
.onTap {
print("tap")
}

// Get notified when to load more content
.shouldLoadMore {
data.append("foobar")
}

// Get notified when swiping past the beginning or end of the list
.overscroll { position in
if position == .beginning {
print("Swiped past beginning")
} else {
print("Swiped past end")
}
}

// Set the background color with the drag opacity control
.background(.black.opacity(opacity))

// A special included modifier to help make fullScreenCover transparent
.background(ClearFullScreenBackground())

// Works with safe areas or ignored safe areas
.ignoresSafeArea()
}
}
```

#### Vertical paging

```swift
@State var data = [ ... ]

var body: some View {
LazyPager(data: data, direction: .vertical) { element in
Image(element)
.resizable()
.aspectRatio(contentMode: .fill)
}
}
```

For a full working example, [open the sample project](https://github.com/gh123man/LazyPager/tree/master/Examples) in the examples folder, or [check out the code here](https://github.com/gh123man/SwiftUI-LazyPager/blob/master/Examples/LazyPagerExampleApp/FullTestView.swift)

# Features

- All content is lazy loaded. By default content is pre-loaded 3 elements ahead and behind the current index.
- Display any kind of content - not just images!
- Horizontal or Vertical paging.
- Lazy loaded views are disposed when they are outside of the pre-load frame to conserve resources.
- Enable zooming and panning with `.zoomable(min: CGFloat, max: CGFloat)`.
- Double tap to zoom is also supported through `.zoomable` modifier.
- Notifies when to load more content with `.shouldLoadMore`.
- Notifies when you swipe past the beginning or end of data with `.overscroll`.
- Animate page transitions by using `withAnimation` when changing the page index.
- Works with `.ignoresSafeArea()` (or not) to get a true full screen view.
- Drag to dismiss is supported with `.onDismiss` - Supply a binding opacity value to control the background opacity during the transition.
- Tap events are handled internally, so use `.onTap` to handle single taps (useful for hiding and showing UI).
- Use `.onDoubleTap` to get notified on double taps.
- Use `.settings` to [modify advanced settings](https://github.com/gh123man/SwiftUI-LazyPager/blob/master/Sources/LazyPager/LazyPager.swift#L70).
- Use `.absoluteContentPosition` to subscribe to content position updates (the index + the offset while paging)
- Use `.onZoom` to get notified of the current zoom level

# Detailed usage

## Working with `fullScreenCover`

`fullScreenCover` is a good native element for displaying a photo browser, however it has an opaque background by default that is difficult to remove. So `LazyPager` provides a `ClearFullScreenBackground` background view you can use to fix it. Simply add `.background(ClearFullScreenBackground())` to the root element of your `fullScreenCover`. This makes the pull to dismiss gesture seamless.

## Double tap to zoom
You can customize the double tap behavior using the `zoomable(min: CGFloat, max: CGFloat, doubleTapGesture: DoubleTap)`. By default `doubleTapGesture` is set to `.scale(0.5)` which means "zoom 50% when double tapped". You can change this to a different ratio or set it to `.disabled` to disable the double tap gesture.

## Dismiss gesture handling
By default `.onDismiss` will be called after the pull to dismiss gesture is completed. It is often desirable to fade out the background in the process. `LazyPager` uses a fully transparent background by default so you can set your own custom background. NOTE: `.onDismiss` is only supported for `.horizontal` pagers.

To control the dismiss opacity of a custom background, use a `Binding` like `.onDismiss(backgroundOpacity: $opacity) {` to fade out your custom background.