Skip to content

Commit

Permalink
New animation faded
Browse files Browse the repository at this point in the history
  • Loading branch information
fermoya committed Mar 5, 2021
1 parent a3cb977 commit fba809b
Show file tree
Hide file tree
Showing 11 changed files with 96 additions and 2 deletions.
13 changes: 13 additions & 0 deletions Documentation/Usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,19 @@ Pager(...)

<img src="/resources/usage/interactive-pagers.gif" alt="Interactive pager" height="640"/>

### Faded

Get a interactive fading effect on your items by using `faded`:

```swift
Pager(...)
.faded(0.4)
.preferredItemSize(CGSize(width: 150, height: 150))
.itemSpacing(10)
```

<img src="/resources/usage/faded-pagers.gif" alt="Interactive pager" height="640"/>

### Rotation

You can also use `rotation3D` to add a rotation effect to your pages:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ struct ColorsExampleView: View {
self.pageView($0)
}
.contentLoadingPolicy(.eager)
.disableDragging()
.itemSpacing(10)
.padding(20)
.frame(width: min(proxy.size.height, proxy.size.width),
Expand Down
1 change: 1 addition & 0 deletions Sources/SwiftUIPager/Page.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import Combine
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
public class Page: ObservableObject {

// Needed for `iOS 13` or else it won't trigger an update
public var objectWillChange = PassthroughSubject<Void, Never>()
var _index: Int

Expand Down
14 changes: 14 additions & 0 deletions Sources/SwiftUIPager/Pager+Buildable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,20 @@ extension Pager: Buildable {
return mutating(keyPath: \.interactiveScale, value: scale)
}

/// Call this method to provide an interactive opacity effect to neighboring pages. The further they are
/// from the focused page, the more opacity will be applied
///
/// - Parameter stepPercentage: opacity step increment between each index
///
/// For instance, if the focused index is _3_ and `stepPercentage` is `0.4`,
/// then page _2_ and _4_ will have an opacity of `0.8`, pages _1_ and _5_ will have
/// an opacity of `0.4` and so on.
///
/// - Note: `increment` must be lower than _1_ and greather than _0_
public func faded(_ stepPercentage: Double = 0.4) -> Self {
mutating(keyPath: \.opacityIncrement, value: stepPercentage)
}

/// Call this method to add a 3D rotation effect.
///
/// - Parameter value: `true` if the pages should have a 3D rotation effect
Expand Down
4 changes: 4 additions & 0 deletions Sources/SwiftUIPager/Pager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ public struct Pager<Element, ID, PageView>: View where PageView: View, Element:
/// Shrink ratio that affects the items that aren't focused
var interactiveScale: CGFloat = 1

/// Opacity increment applied to unfocused pages
var opacityIncrement: Double?

/// `true` if `Pager` can be dragged
var allowsDragging: Bool = true

Expand Down Expand Up @@ -187,6 +190,7 @@ public struct Pager<Element, ID, PageView>: View where PageView: View, Element:
.loopPages(isInifinitePager, repeating: loopingCount)
.alignment(alignment)
.interactive(interactiveScale)
.faded(opacityIncrement)
.pageOffset(pageOffset)
.itemSpacing(itemSpacing)
.itemAspectRatio(itemAspectRatio, alignment: itemAlignment)
Expand Down
14 changes: 14 additions & 0 deletions Sources/SwiftUIPager/PagerContent+Buildable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,20 @@ extension Pager.PagerContent: Buildable {
func interactive(_ scale: CGFloat) -> Self {
mutating(keyPath: \.interactiveScale, value: scale)
}

/// Call this method to provide an interactive opacity effect to neighboring pages. The further they are
/// from the focused page, the more opacity will be applied
///
/// - Parameter stepPercentage: opacity step increment between each index
///
/// For instance, if the focused index is _3_ and `stepPercentage` is `0.4`,
/// then page _2_ and _4_ will have an opacity of `0.8`, pages _1_ and _5_ will have
/// an opacity of `0.4` and so on.
///
/// - Note: `increment` must be lower than _1_ and greather than _0_
func faded(_ stepPercentage: Double?) -> Self {
mutating(keyPath: \.opacityIncrement, value: stepPercentage)
}

/// Call this method to add a 3D rotation effect.
///
Expand Down
11 changes: 11 additions & 0 deletions Sources/SwiftUIPager/PagerContent+Helper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,17 @@ extension Pager.PagerContent {
return (itemAlignment.equalsIgnoreValues(.start) ? -availableSpace : availableSpace) * multiplier
}

/// Oppacity for each item when `faded` animation is chosen
func opacity(for item: PageWrapper<Element, ID>) -> Double {
guard let opacityIncrement = opacityIncrement else { return 1 }
guard let index = data.firstIndex(of: item) else { return 1 }
let totalIncrement = abs(totalOffset / pageDistance)
let currentPage = direction == .forward ? CGFloat(page) + totalIncrement : CGFloat(page) - totalIncrement

let distance = abs(CGFloat(index) - currentPage)
return Double(max(0, min(1, 1 - distance * CGFloat(opacityIncrement))))
}

/// Offset applied to `HStack` along the X-Axis. It's limitted by `offsetUpperbound` and `offsetUpperbound`
var xOffset: CGFloat {
let indexOfPageFocused = CGFloat(dataDisplayed.firstIndex(where: { data.firstIndex(of: $0) == self.page }) ?? 0)
Expand Down
4 changes: 4 additions & 0 deletions Sources/SwiftUIPager/PagerContent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ extension Pager {
/// Shrink ratio that affects the items that aren't focused
var interactiveScale: CGFloat = 1

/// Opacity increment applied to unfocused pages
var opacityIncrement: Double?

/// `true` if `Pager` can be dragged
var allowsDragging: Bool = true

Expand Down Expand Up @@ -167,6 +170,7 @@ extension Pager {
axis: (0, 0, 1))
.rotation3DEffect(self.angle(for: item),
axis: self.axis)
.opacity(opacity(for: item))
}
.offset(x: self.xOffset, y : self.yOffset)
}
Expand Down
12 changes: 11 additions & 1 deletion Tests/SwiftUIPagerTests/Pager+Buildable_Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,22 @@ final class Pager_Buildable_Tests: XCTestCase {
XCTAssertEqual(pager.sensitivity, .default)
XCTAssertEqual(pager.pageRatio, 1)
XCTAssertTrue(pager.bounces)
XCTAssertNil(pager.opacityIncrement)

let pagerContent = pager.content(for: CGSize(width: 100, height: 100))
XCTAssertNil(pagerContent.direction)
XCTAssertEqual(pagerContent.minimumDistance, 15)
XCTAssertFalse(pagerContent.isDragging)
}

func test_GivenPager_WhenFaded_ThenOpacityIncrementChanges() {
var pager = givenPager
pager = pager.faded(0.2)

let pagerContent = pager.content(for: CGSize(width: 100, height: 100))
XCTAssertEqual(pagerContent.opacityIncrement, 0.2)
}

func test_GivenPager_WhenSinglePagination_ThenRatioChanges() {
var pager = givenPager
pager = pager.singlePagination(ratio: 0.33, sensitivity: .high)
Expand Down Expand Up @@ -633,7 +642,8 @@ final class Pager_Buildable_Tests: XCTestCase {
("test_GivenPager_WhenOnDraggingBegan_ThenCallback", test_GivenPager_WhenOnDraggingBegan_ThenCallback),
("test_GivenPager_WhenOnDraggingChanged_ThenCallback", test_GivenPager_WhenOnDraggingChanged_ThenCallback),
("test_GivenPager_WhenOnDraggingEnded_ThenCallback", test_GivenPager_WhenOnDraggingEnded_ThenCallback),
("test_GivenPager_WhenOnPageChanged_ThenCallbackNotNil", test_GivenPager_WhenOnPageChanged_ThenCallbackNotNil)
("test_GivenPager_WhenOnPageChanged_ThenCallbackNotNil", test_GivenPager_WhenOnPageChanged_ThenCallbackNotNil),
("test_GivenPager_WhenFaded_ThenOpacityIncrementChanges", test_GivenPager_WhenFaded_ThenOpacityIncrementChanges)
]
}

Expand Down
24 changes: 23 additions & 1 deletion Tests/SwiftUIPagerTests/PagerContent+Helper_Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,25 @@ final class PagerContent_Helper_Tests: XCTestCase {
XCTAssertEqual(pagerContent.pagerModel.draggingOffset, pagerContent.draggingOffset)
}

func test_GivenPager_WhenOpacity_ThenOne() {
XCTAssertEqual(givenPager.opacity(for: PageWrapper(batchId: 1, keyPath: \.self, element: 1)), 1)
}

func test_GivenPager_WhenOpacityForNotFoundIndex_ThenOne() {
XCTAssertEqual(givenPager.opacity(for: PageWrapper(batchId: 0, keyPath: \.self, element: -1)), 1)
}

func test_GivenFadedPager_WhenOpacityForNotFoundIndex_ThenValues() {
let pagerContent = givenPager.faded(0.3)

let focusedItem = PageWrapper(batchId: 1, keyPath: \.self, element: 0)
let neighbor1 = PageWrapper(batchId: 1, keyPath: \.self, element: 1)
let neighbor2 = PageWrapper(batchId: 1, keyPath: \.self, element: 2)
XCTAssertEqual(pagerContent.opacity(for: focusedItem), 1)
XCTAssertEqual(pagerContent.opacity(for: neighbor1), 0.7)
XCTAssertEqual(pagerContent.opacity(for: neighbor2), 0.4)
}

func test_GivenMultiplePaginationPager_WhenDragResult_ThenValues() {
let pagerContent = givenPager.multiplePagination()
pagerContent.pagerModel.draggingOffset = -pagerContent.size.width * 2
Expand Down Expand Up @@ -369,6 +388,9 @@ final class PagerContent_Helper_Tests: XCTestCase {
("test_GivenPager_WhenPagerModelHelpers_ThenSameValues", test_GivenPager_WhenPagerModelHelpers_ThenSameValues),
("test_GivenMultiplePaginationPager_WhenDragResult_ThenValues", test_GivenMultiplePaginationPager_WhenDragResult_ThenValues),
("test_GivenPager_WhenDragQuickly_ThenIncrementPage", test_GivenPager_WhenDragQuickly_ThenIncrementPage),
("test_GivenInfinitePager_WhenDragLeft_ThenLastPage", test_GivenInfinitePager_WhenDragLeft_ThenLastPage)
("test_GivenInfinitePager_WhenDragLeft_ThenLastPage", test_GivenInfinitePager_WhenDragLeft_ThenLastPage),
("test_GivenPager_WhenOpacity_ThenOne", test_GivenPager_WhenOpacity_ThenOne),
("test_GivenPager_WhenOpacityForNotFoundIndex_ThenOne", test_GivenPager_WhenOpacityForNotFoundIndex_ThenOne),
("test_GivenFadedPager_WhenOpacityForNotFoundIndex_ThenValues", test_GivenFadedPager_WhenOpacityForNotFoundIndex_ThenValues)
]
}
Binary file added resources/usage/faded-pagers.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 fba809b

Please sign in to comment.