Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ let package = Package(
name: "SwiftUIPageView",
platforms: [
.iOS(.v14),
.watchOS(.v7)
.watchOS(.v7),
.macOS(.v11),
],
products: [
.library(
Expand Down
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ HPageView(alignment: .leading, pageWidth: 250, spacing: 12) {
* `pageWidth`: The width of each page, or `nil` if you want each page to fill the width of the page view.
* `spacing`: The distance between adjacent pages, or `nil` if you want the page view to choose a default distance for each pair of pages.
* `content`: A view builder that creates the content of this page view.
* `index`: An `Int` binding that exposes active page

## VPageView
A view that arranges its children in a vertical line, and provides paged scrolling behaviour.
Expand All @@ -35,6 +36,7 @@ VPageView(alignment: .top, pageHeight: 250, spacing: 12) {
* `pageHeight`: The height of each page, or `nil` if you want each page to fill the height of the page view.
* `spacing`: The distance between adjacent pages, or `nil` if you want the page view to choose a default distance for each pair of pages.
* `content`: A view builder that creates the content of this page view.
* `index`: An `Int` binding that exposes active page

## PageView
A view that arranges its children in a line, and provides paged scrolling behaviour.
Expand All @@ -54,6 +56,35 @@ PageView(.horizontal, alignment: .leading, pageLength: 250, spacing: 12) {
* `pageLength`: The length of each page, parallel to the layout axis, or `nil` if you want each page to fill the length of the page view.
* `spacing`: The distance between adjacent pages, or `nil` if you want the page view to choose a default distance for each pair of pages.
* `content`: A view builder that creates the content of this page view.
* `index`: An `Int` binding that exposes active page

## Index binding example
```
@State var currentIndex: Int = 0

...

/// inside `body`:
ZStack(alignment: .bottom) {
HPageView(alignment: .leading, pageWidth: 250, spacing: 12, index: $currentIndex) {
ForEach(items, id: \.id) { item in
ItemView(item: item)
.padding(.bottom, 24)
}
}

/// Indicator dots
HStack(spacing: 8) {
ForEach(items.indices, id: \.self) { index in
Circle()
.fill(currentIndex == index ? Color.primary : Color.secondary)
.frame(width: 8, height: 8)
.animation(.spring(), value: currentIndex == index)
}
}
.padding(.bottom, 8)
}
```

## PageViewReader
A view that provides programmatic paging, by working with a proxy to move to child pages.
Expand Down
27 changes: 27 additions & 0 deletions Sources/SwiftUIPageView/API/GestureMinimumDistance.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// File.swift
//
//
// Created by Tomas Kafka on 27.06.2022.
//

import Foundation
import CoreGraphics

public enum GestureMinimumDistance {
/// old default
case compatible
case comfortable
case custom(CGFloat)

var value: CGFloat {
switch self {
case .compatible:
return 15
case .comfortable:
return 31
case .custom(let customDistance):
return customDistance
}
}
}
6 changes: 5 additions & 1 deletion Sources/SwiftUIPageView/API/HPageView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,16 @@ where Content : View
public init(alignment: PageAlignment<HorizontalPageAlignment, VerticalAlignment> = .center,
pageWidth: CGFloat? = nil,
spacing: CGFloat? = nil,
gestureMinimumDistance: GestureMinimumDistance = .compatible,
index: Binding<Int> = Binding.constant(0),
@ViewBuilder content: @escaping () -> Content)
{
body = PageView(alignment: alignment.alignment,
axis: .horizontal,
content: content,
pageLength: pageWidth,
spacing: spacing)
spacing: spacing,
gestureMinimumDistance: gestureMinimumDistance,
index: index)
}
}
10 changes: 9 additions & 1 deletion Sources/SwiftUIPageView/API/PageView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ where Content : View
content: content,
pageLength: pageLength,
spacing: spacing,
viewLength: viewLength)
gestureMinimumDistance: gestureMinimumDistance,
viewLength: viewLength,
index: $index)
}
.animation(nil, value: axis)
}
Expand All @@ -36,6 +38,8 @@ where Content : View
internal var content: () -> Content
internal var pageLength: CGFloat?
internal var spacing: CGFloat?
internal var gestureMinimumDistance: GestureMinimumDistance
@Binding var index: Int
}


Expand All @@ -62,12 +66,16 @@ public extension PageView {
alignment: PageAlignment<HorizontalPageAlignment, VerticalPageAlignment> = .center,
pageLength: CGFloat? = nil,
spacing: CGFloat? = nil,
gestureMinimumDistance: GestureMinimumDistance,
index: Binding<Int> = Binding.constant(0),
@ViewBuilder content: @escaping () -> Content)
{
self.alignment = alignment.alignment
self.axis = axis
self.content = content
self.pageLength = pageLength
self.spacing = spacing
self.gestureMinimumDistance = gestureMinimumDistance
self._index = index
}
}
6 changes: 5 additions & 1 deletion Sources/SwiftUIPageView/API/VPageView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,16 @@ where Content : View
public init(alignment: PageAlignment<HorizontalAlignment, VerticalPageAlignment> = .center,
pageHeight: CGFloat? = nil,
spacing: CGFloat? = nil,
index: Binding<Int> = Binding.constant(0),
gestureMinimumDistance: GestureMinimumDistance = .compatible,
@ViewBuilder content: @escaping () -> Content)
{
body = PageView(alignment: alignment.alignment,
axis: .vertical,
content: content,
pageLength: pageHeight,
spacing: spacing)
spacing: spacing,
gestureMinimumDistance: gestureMinimumDistance,
index: index)
}
}
21 changes: 20 additions & 1 deletion Sources/SwiftUIPageView/Internal/PageGestureView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ where Content : View
var content: () -> Content
var pageLength: CGFloat
var spacing: CGFloat
var gestureMinimumDistance: GestureMinimumDistance
var viewLength: CGFloat
@Binding var index: Int

var body: some View {
PageLayoutView(alignment: alignment,
Expand Down Expand Up @@ -55,7 +57,7 @@ where Content : View
let minimumDistance: CGFloat

switch pageState.dragState {
case .dragging, .nearlyEnded, .ended: minimumDistance = 15
case .dragging, .nearlyEnded, .ended: minimumDistance = gestureMinimumDistance.value
case .ending: minimumDistance = 0
}

Expand Down Expand Up @@ -100,6 +102,19 @@ where Content : View
private func offsetToIndex(_ offset: CGFloat) -> CGFloat {
-offset / (pageLength + spacing)
}

private func intFromIndex(_ index: CGFloat) -> Int {
if index == .infinity {
return pageState.viewCount - 1
} else if index == -.infinity {
return 0
} else if index.isNaN {
return 0
} else {
return Int(round(index))
}
}

private func onDragChanged(value: DragGesture.Value) {
if let initialIndex = pageState.initialIndex {
onDragUpdated(value: value, initialIndex: initialIndex)
Expand Down Expand Up @@ -131,6 +146,7 @@ where Content : View
withAnimation(animationState.dragAnimation) {
pageState.index = newIndex
pageState.indexOffset = 0
self.index = intFromIndex(newIndex)
}
}
}
Expand Down Expand Up @@ -167,6 +183,7 @@ where Content : View
withAnimation(animationState.dragAnimation) {
pageState.index = newIndex
pageState.indexOffset = 0
self.index = intFromIndex(newIndex)
}
}
private func onDragStarted(value: DragGesture.Value) {
Expand Down Expand Up @@ -201,6 +218,7 @@ where Content : View
withAnimation(animationState.dragAnimation) {
pageState.index = offsetToIndex(offset)
pageState.indexOffset = offsetToIndex(additionalOffset - initialOffset)
self.index = intFromIndex(offsetToIndex(offset))
}
}
private func onDragUpdated(value: DragGesture.Value, initialIndex: CGFloat) {
Expand Down Expand Up @@ -229,5 +247,6 @@ where Content : View
pageState.dragState = distance == 0 ? .ended : .ending
pageState.index = newIndex
pageState.indexOffset = 0
self.index = intFromIndex(newIndex)
}
}