Skip to content

Commit

Permalink
Merge pull request #1 from fermoya/rotation-effect
Browse files Browse the repository at this point in the history
Rotation effect
  • Loading branch information
fermoya authored Jan 21, 2020
2 parents 1d22a58 + 106565d commit 38273cd
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 7 deletions.
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ whereas a value greater than one will make it look like a box:

<img src="resources/page_aspect_ratio_greater_than_1.png" alt="PageAspectRatio greater than 1" height="640"/>

You can also use `interactive` to pass a shrink ratio that will be applied to those components that are not focused, that is, those elements whose index is different from `pageIndex` binding:
### Animations

Use `interactive` to pass a shrink ratio that will be applied to those components that are not focused, that is, those elements whose index is different from `pageIndex` binding:

```swift
Pager(...)
Expand All @@ -72,6 +74,16 @@ Pager(...)

<img src="resources/interactive-pager.gif" alt="Interactive pager"/>

You can also use `rotation3D` to add a rotation effect to your pages:

```swift
Pager(...)
.itemSpacing(10)
.rotation3D()
```

<img src="resources/rotation3D.gif" alt="PageAspectRatio lower than 1" height="640"/>

### Gestures

`Pager` comes with the following built-in gestures:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"repositoryURL": "https://github.com/fermoya/SwiftUIPager.git",
"state": {
"branch": "master",
"revision": "fb221c6d2305c05b8ba7d1c2911d19082b9ec1c1",
"revision": "1d22a5878394697884a4b15215522e04a68f835c",
"version": null
}
}
Expand Down
14 changes: 12 additions & 2 deletions Sources/SwiftUIPager/Pager+Buildable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,22 @@ extension Pager: Buildable {

/// Call this method to provide a shrink ratio that will apply to the items that are not focused.
///
/// - Parameter scale: shrink ratio
/// - Note: `scale` must be lower than _1_, otherwise it defaults to _1_
/// - Parameter scale: shrink ratio
/// - Note: `scale` must be lower than _1_, otherwise it defaults to _1_
public func interactive(_ scale: CGFloat) -> Self {
guard !shouldRotate else { return self }
let scale = min(1, abs(scale))
return mutating(keyPath: \.interactiveScale, value: scale)
}

/// Call this method to add a 3D rotation effect.
///
/// - Parameter value: `true` if the pages should have a 3D rotation effect
/// - Note: If you call this method, any previous or later call to `interactive` will have no effect.
public func rotation3D(_ value: Bool = true) -> Self {
mutating(keyPath: \.interactiveScale, value: rotationInteractiveScale)
.mutating(keyPath: \.shouldRotate, value: value)
}

/// Provides an offset to modify the
public func contentOffset(_ pageOffset: Double) -> Self {
Expand Down
25 changes: 25 additions & 0 deletions Sources/SwiftUIPager/Pager+Helper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,31 @@ extension Pager {
return max(offsetUpperbound, min(offsetLowerbound, offset))
}

/// Angle for the 3D rotation effect
func angle(for item: Data) -> Angle {
guard shouldRotate else { return .zero }
guard let index = data.firstIndex(of: item) else { return .zero }

let totalIncrement = abs(totalOffset / pageDistance)

let currentAngle = index == page ? .zero : index < page ? Angle(degrees: rotationDegrees) : Angle(degrees: -rotationDegrees)
guard isDragging else {
return currentAngle
}

let newAngle = direction == .forward ? Angle(degrees: currentAngle.degrees + rotationDegrees * Double(totalIncrement)) : Angle(degrees: currentAngle.degrees - rotationDegrees * Double(totalIncrement) )
return newAngle
}

/// Axis for the rotations effect
func axis(for item: Data) -> (CGFloat, CGFloat, CGFloat) {
guard shouldRotate else { return (0, 0, 0) }
guard let index = data.firstIndex(of: item) else { return (0, 0, 0) }

let currentXAxis: CGFloat = index == page ? 0 : index < page ? rotationAxis.x : -rotationAxis.x
return (currentXAxis, rotationAxis.y, rotationAxis.z)
}

/// Scale that applies to a particular item
func scale(for item: Data) -> CGFloat {
guard isDragging else { return isFocused(item) ? 1 : interactiveScale }
Expand Down
20 changes: 17 additions & 3 deletions Sources/SwiftUIPager/Pager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ public struct Pager<Data, Content>: View where Content: View, Data: Identifiabl
/// A ratio of 3, for instance, would mean the items held in memory are enough
/// to cover 3 times the size of the pager
let recyclingRatio = 4

/// Angle of rotation when should rotate
let rotationDegrees: Double = 20

/// Angle of rotation when should rotate
let rotationInteractiveScale: CGFloat = 0.7

/// Axis of rotation when should rotate
let rotationAxis: (x: CGFloat, y: CGFloat, z: CGFloat) = (0.2, 1, 0)

/*** Dependencies ***/

Expand All @@ -58,6 +67,9 @@ public struct Pager<Data, Content>: View where Content: View, Data: Identifiabl

/// Shrink ratio that affects the items that aren't focused
var interactiveScale: CGFloat = 1

/// `true` if pages should have a 3D rotation effect
var shouldRotate: Bool = false

/// Used to modify `Pager` offset outside this view
var contentOffset: CGFloat = 0
Expand Down Expand Up @@ -94,9 +106,9 @@ public struct Pager<Data, Content>: View where Content: View, Data: Identifiabl

/// Initializes a new Pager.
///
/// - Parameter page: Binding to the index of the focused page
/// - Parameter data: Array of items to populate the content
/// - Parameter content: Factory method to build new pages
/// - Parameter page: Binding to the index of the focused page
/// - Parameter data: Array of items to populate the content
/// - Parameter content: Factory method to build new pages
public init(page: Binding<Int>, data: [Data], @ViewBuilder content: @escaping (Data) -> Content) {
self._page = page
self.data = data
Expand All @@ -109,6 +121,8 @@ public struct Pager<Data, Content>: View where Content: View, Data: Identifiabl
self.content(item)
.frame(size: self.pageSize)
.scaleEffect(self.scale(for: item))
.rotation3DEffect(self.angle(for: item),
axis: self.axis(for: item))
.onTapGesture (perform: {
withAnimation(.spring()) {
self.scrollToItem(item)
Expand Down
Binary file added resources/rotation3D.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 38273cd

Please sign in to comment.