diff --git a/FSPageViewExample-Swift/FSPagerViewExample.xcodeproj/project.pbxproj b/FSPageViewExample-Swift/FSPagerViewExample.xcodeproj/project.pbxproj index ed44194..1eb7c69 100644 --- a/FSPageViewExample-Swift/FSPagerViewExample.xcodeproj/project.pbxproj +++ b/FSPageViewExample-Swift/FSPagerViewExample.xcodeproj/project.pbxproj @@ -43,6 +43,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 50989DFE2151DB29004DBB4A /* FSPagerViewObjcCompat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSPagerViewObjcCompat.h; sourceTree = ""; }; F95483991E625F1E0069FD7E /* FSPagerViewLayoutAttributes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FSPagerViewLayoutAttributes.swift; sourceTree = ""; }; F9580B511E5D995400C5B267 /* FSPageControl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FSPageControl.swift; sourceTree = ""; }; F9580B521E5D995400C5B267 /* FSPagerCollectionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FSPagerCollectionView.swift; sourceTree = ""; }; @@ -99,6 +100,7 @@ F9580B551E5D995400C5B267 /* FSPageViewLayout.swift */, F9580B561E5D995400C5B267 /* FSPageViewTransformer.swift */, F95483991E625F1E0069FD7E /* FSPagerViewLayoutAttributes.swift */, + 50989DFE2151DB29004DBB4A /* FSPagerViewObjcCompat.h */, ); name = Sources; path = ../Sources; diff --git a/FSPagerView/FSPagerView.xcodeproj/project.pbxproj b/FSPagerView/FSPagerView.xcodeproj/project.pbxproj index a3d1cd3..a45e2e1 100644 --- a/FSPagerView/FSPagerView.xcodeproj/project.pbxproj +++ b/FSPagerView/FSPagerView.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 50C44A1D2150E7800093B3E9 /* FSPagerViewObjcCompat.h in Headers */ = {isa = PBXBuildFile; fileRef = 50C44A1C2150E7800093B3E9 /* FSPagerViewObjcCompat.h */; }; F9580B7B1E5D9F0600C5B267 /* FSPagerView.h in Headers */ = {isa = PBXBuildFile; fileRef = F9580B791E5D9F0600C5B267 /* FSPagerView.h */; settings = {ATTRIBUTES = (Public, ); }; }; F9580B881E5D9F2B00C5B267 /* FSPageControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9580B821E5D9F2B00C5B267 /* FSPageControl.swift */; }; F9580B891E5D9F2B00C5B267 /* FSPagerCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9580B831E5D9F2B00C5B267 /* FSPagerCollectionView.swift */; }; @@ -18,6 +19,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 50C44A1C2150E7800093B3E9 /* FSPagerViewObjcCompat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSPagerViewObjcCompat.h; sourceTree = ""; }; F9580B761E5D9F0600C5B267 /* FSPagerView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FSPagerView.framework; sourceTree = BUILT_PRODUCTS_DIR; }; F9580B791E5D9F0600C5B267 /* FSPagerView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FSPagerView.h; sourceTree = ""; }; F9580B7A1E5D9F0600C5B267 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -77,6 +79,7 @@ F9580B861E5D9F2B00C5B267 /* FSPageViewLayout.swift */, F9D7BD291E63DD5F003F6A0E /* FSPagerViewLayoutAttributes.swift */, F9580B871E5D9F2B00C5B267 /* FSPageViewTransformer.swift */, + 50C44A1C2150E7800093B3E9 /* FSPagerViewObjcCompat.h */, ); name = Sources; path = ../Sources; @@ -90,6 +93,7 @@ buildActionMask = 2147483647; files = ( F9580B7B1E5D9F0600C5B267 /* FSPagerView.h in Headers */, + 50C44A1D2150E7800093B3E9 /* FSPagerViewObjcCompat.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/FSPagerViewExample-Objc/FSPagerViewExample-Objc.xcodeproj/project.pbxproj b/FSPagerViewExample-Objc/FSPagerViewExample-Objc.xcodeproj/project.pbxproj index 552c942..8404a6c 100644 --- a/FSPagerViewExample-Objc/FSPagerViewExample-Objc.xcodeproj/project.pbxproj +++ b/FSPagerViewExample-Objc/FSPagerViewExample-Objc.xcodeproj/project.pbxproj @@ -44,6 +44,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 50989DFD2151DB25004DBB4A /* FSPagerViewObjcCompat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSPagerViewObjcCompat.h; sourceTree = ""; }; F908BC321E35AAE4002B2F51 /* 1.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = 1.jpg; sourceTree = ""; }; F908BC3A1E35AAE4002B2F51 /* 2.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = 2.jpg; sourceTree = ""; }; F908BC3B1E35AAE4002B2F51 /* 3.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = 3.jpg; sourceTree = ""; }; @@ -121,6 +122,7 @@ F9580B621E5D997200C5B267 /* FSPageViewLayout.swift */, F9FF349E1E65B38C001E943F /* FSPagerViewLayoutAttributes.swift */, F9580B631E5D997200C5B267 /* FSPageViewTransformer.swift */, + 50989DFD2151DB25004DBB4A /* FSPagerViewObjcCompat.h */, ); name = Sources; path = ../Sources; diff --git a/Sources/FSPageViewLayout.swift b/Sources/FSPageViewLayout.swift index fc2c850..22a1ddc 100644 --- a/Sources/FSPageViewLayout.swift +++ b/Sources/FSPageViewLayout.swift @@ -151,39 +151,49 @@ class FSPagerViewLayout: UICollectionViewLayout { } override open func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint { - guard let collectionView = self.collectionView else { + guard let collectionView = self.collectionView, let pagerView = self.pagerView else { return proposedContentOffset } var proposedContentOffset = proposedContentOffset + let touchedContentOffset: CGPoint = collectionView.panGestureRecognizer.location(in: collectionView) + + func calculateTargetOffset(by proposedOffset: CGFloat, touchedOffset: CGFloat, boundedOffset: CGFloat) -> CGFloat { + var targetOffset: CGFloat + if pagerView.pagingDistance == FSPagerViewAutomaticPagingDistance { + if abs(velocity.x) >= 0.3 { + let vector: CGFloat = velocity.x >= 0 ? 1.0 : -1.0 + targetOffset = round(proposedOffset/self.itemSpacing+0.35*vector) * self.itemSpacing // Ceil by 0.15, rather than 0.5 + } else { + targetOffset = round(proposedOffset/self.itemSpacing) * self.itemSpacing + } + } else { + let extraDistance = max(pagerView.pagingDistance-1, 0) + switch velocity.x { + case 0.3 ... CGFloat.greatestFiniteMagnitude: + targetOffset = ceil(touchedOffset/self.itemSpacing+CGFloat(extraDistance)) * self.itemSpacing + case -CGFloat.greatestFiniteMagnitude ... -0.3: + targetOffset = floor(touchedOffset/self.itemSpacing-1-CGFloat(extraDistance)) * self.itemSpacing + default: + targetOffset = round(proposedOffset/self.itemSpacing) * self.itemSpacing + } + } + targetOffset = max(0, targetOffset) + targetOffset = min(boundedOffset, targetOffset) + return targetOffset + } let proposedContentOffsetX: CGFloat = { if self.scrollDirection == .vertical { return proposedContentOffset.x } - let translation = -collectionView.panGestureRecognizer.translation(in: collectionView).x - var offset: CGFloat = round(proposedContentOffset.x/self.itemSpacing)*self.itemSpacing - let minFlippingDistance = min(0.5 * self.itemSpacing,150) - let originalContentOffsetX = collectionView.contentOffset.x - translation - if abs(translation) <= minFlippingDistance { - if abs(velocity.x) >= 0.3 && abs(proposedContentOffset.x-originalContentOffsetX) <= self.itemSpacing*0.5 { - offset += self.itemSpacing * (velocity.x)/abs(velocity.x) - } - } - return offset + let boundedOffset = collectionView.contentSize.width-self.itemSpacing + return calculateTargetOffset(by: proposedContentOffset.x, touchedOffset: touchedContentOffset.x, boundedOffset: boundedOffset) }() let proposedContentOffsetY: CGFloat = { if self.scrollDirection == .horizontal { return proposedContentOffset.y } - let translation = -collectionView.panGestureRecognizer.translation(in: collectionView).y - var offset: CGFloat = round(proposedContentOffset.y/self.itemSpacing)*self.itemSpacing - let minFlippingDistance = min(0.5 * self.itemSpacing,150) - let originalContentOffsetY = collectionView.contentOffset.y - translation - if abs(translation) <= minFlippingDistance { - if abs(velocity.y) >= 0.3 && abs(proposedContentOffset.y-originalContentOffsetY) <= self.itemSpacing*0.5 { - offset += self.itemSpacing * (velocity.y)/abs(velocity.y) - } - } - return offset + let boundedOffset = collectionView.contentSize.height-self.itemSpacing + return calculateTargetOffset(by: proposedContentOffset.y, touchedOffset: touchedContentOffset.y, boundedOffset: boundedOffset) }() proposedContentOffset = CGPoint(x: proposedContentOffsetX, y: proposedContentOffsetY) return proposedContentOffset diff --git a/Sources/FSPagerView.swift b/Sources/FSPagerView.swift index 2a7fa34..41b7ad0 100644 --- a/Sources/FSPagerView.swift +++ b/Sources/FSPagerView.swift @@ -83,6 +83,9 @@ public enum FSPagerViewScrollDirection: Int { case vertical } +/// The paging distance is automatically calculated according to the scrolling speed of the pager view. +public let FSPagerViewAutomaticPagingDistance: UInt = 0 + @IBDesignable open class FSPagerView: UIView,UICollectionViewDataSource,UICollectionViewDelegate { @@ -138,6 +141,10 @@ open class FSPagerView: UIView,UICollectionViewDataSource,UICollectionViewDelega } } + /// An unsigned integer value that determines the paging distance of the pager view, which indicates the number of passing items during a single paging. When the value of this property is FSPagerViewAutomaticPagingDistance(0), the actual 'distance' is automatically calculated according to the scrolling speed of the pager view. Default is 1. + @IBInspectable + open var pagingDistance: UInt = 1 + /// A Boolean value that determines whether bouncing always occurs when horizontal scrolling reaches the end of the content view. @IBInspectable open var alwaysBounceHorizontal: Bool { diff --git a/Sources/FSPagerViewObjcCompat.h b/Sources/FSPagerViewObjcCompat.h new file mode 100644 index 0000000..7b53c0b --- /dev/null +++ b/Sources/FSPagerViewObjcCompat.h @@ -0,0 +1,9 @@ +// +// FSPagerViewObjcCompat.h +// FSPagerView +// +// Created by 丁文超 on 2018/9/18. +// Copyright © 2018 Wenchao Ding. All rights reserved. +// + +#define FSPagerViewAutomaticPagingDistance 0