diff --git a/FSPagerView.podspec b/FSPagerView.podspec index 2087852..7bf3605 100644 --- a/FSPagerView.podspec +++ b/FSPagerView.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "FSPagerView" - s.version = "0.3.0" + s.version = "0.4.0" s.summary = "FSPagerView is an elegant Screen Slide Library for making Banner、Product Show、Welcome/Guide Pages、Screen/ViewController Sliders." s.homepage = "https://github.com/WenchaoD/FSPagerView" diff --git a/FSPagerView/FSPagerView/Info.plist b/FSPagerView/FSPagerView/Info.plist index 0d6341f..a6faa05 100644 --- a/FSPagerView/FSPagerView/Info.plist +++ b/FSPagerView/FSPagerView/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 0.3.0 + 0.4.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass diff --git a/FSPagerViewExample-Objc/FSPagerViewExample-Objc.xcodeproj/xcuserdata/wenchaoding.xcuserdatad/xcschemes/xcschememanagement.plist b/FSPagerViewExample-Objc/FSPagerViewExample-Objc.xcodeproj/xcuserdata/wenchaoding.xcuserdatad/xcschemes/xcschememanagement.plist index 44177a1..7a2ae77 100644 --- a/FSPagerViewExample-Objc/FSPagerViewExample-Objc.xcodeproj/xcuserdata/wenchaoding.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/FSPagerViewExample-Objc/FSPagerViewExample-Objc.xcodeproj/xcuserdata/wenchaoding.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,7 +7,7 @@ FSPagerViewExample-Objc.xcscheme orderHint - 0 + 1 SuppressBuildableAutocreation diff --git a/FSPagerViewExamples.xcworkspace/contents.xcworkspacedata b/FSPagerViewExamples.xcworkspace/contents.xcworkspacedata index 56c48f2..db5ee4a 100644 --- a/FSPagerViewExamples.xcworkspace/contents.xcworkspacedata +++ b/FSPagerViewExamples.xcworkspace/contents.xcworkspacedata @@ -7,4 +7,7 @@ + + diff --git a/README-OBJECTIVE-C.md b/README-OBJECTIVE-C.md index 5fe88fc..92db05e 100644 --- a/README-OBJECTIVE-C.md +++ b/README-OBJECTIVE-C.md @@ -14,6 +14,7 @@ ## Features * ***Infinite*** scrolling. * ***Automatic*** Sliding. +* Support ***Horizontal*** and ***Vertical*** paging. * Fully customizable item, with predefined banner-style item. * Fully customizable ***page control***. * Rich build-in 3D transformers. @@ -398,4 +399,6 @@ FSPageControl *pageControl = [[FSPageControl alloc] initWithFrame:frame2]; * ***[FSCalendar](https://github.com/WenchaoD/FSCalendar)*** +--- +# [Documentation](http://cocoadocs.org/docsets/FSPagerView) \ No newline at end of file diff --git a/README.md b/README.md index 266bcef..1911e42 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ ## Features * ***Infinite*** scrolling. * ***Automatic*** Sliding. +* ***Horizontal*** and ***Vertical*** paging. * Fully customizable item, with predefined banner-style item. * Fully customizable ***page control***. * Rich build-in 3D transformers. @@ -405,5 +406,6 @@ func pagerViewDidEndDecelerating(_ pagerView: FSPagerView) * ***[FSCalendar](https://github.com/WenchaoD/FSCalendar)*** +--- - +# [Documentation](http://cocoadocs.org/docsets/FSPagerView) \ No newline at end of file diff --git a/Sources/FSPageViewLayout.swift b/Sources/FSPageViewLayout.swift index 5413143..cd81d46 100644 --- a/Sources/FSPageViewLayout.swift +++ b/Sources/FSPageViewLayout.swift @@ -14,6 +14,7 @@ class FSPagerViewLayout: UICollectionViewLayout { internal var leadingSpacing: CGFloat = 0 internal var itemSpacing: CGFloat = 0 internal var needsReprepare = true + internal var scrollDirection: FSPagerViewScrollDirection = .horizontal open override class var layoutAttributesClass: AnyClass { get { @@ -82,17 +83,27 @@ class FSPagerViewLayout: UICollectionViewLayout { } return pagerView.interitemSpacing }() - self.leadingSpacing = (collectionView.frame.width-self.actualItemSize.width)*0.5 - self.itemSpacing = self.actualItemSize.width+self.actualInteritemSpacing + self.scrollDirection = pagerView.scrollDirection + self.leadingSpacing = self.scrollDirection == .horizontal ? (collectionView.frame.width-self.actualItemSize.width)*0.5 : (collectionView.frame.height-self.actualItemSize.height)*0.5 + self.itemSpacing = (self.scrollDirection == .horizontal ? self.actualItemSize.width : self.actualItemSize.height) + self.actualInteritemSpacing // Calculate and cache contentSize, rather than calculating each time self.contentSize = { let numberOfItems = self.numberOfItems*self.numberOfSections - var contentSizeWidth: CGFloat = self.leadingSpacing*2 // Leading & trailing spacing - contentSizeWidth += CGFloat(numberOfItems-1)*self.actualInteritemSpacing // Interitem spacing - contentSizeWidth += CGFloat(numberOfItems)*self.actualItemSize.width // Item sizes - let contentSize = CGSize(width: contentSizeWidth, height: collectionView.frame.height) - return contentSize + switch self.scrollDirection { + case .horizontal: + var contentSizeWidth: CGFloat = self.leadingSpacing*2 // Leading & trailing spacing + contentSizeWidth += CGFloat(numberOfItems-1)*self.actualInteritemSpacing // Interitem spacing + contentSizeWidth += CGFloat(numberOfItems)*self.actualItemSize.width // Item sizes + let contentSize = CGSize(width: contentSizeWidth, height: collectionView.frame.height) + return contentSize + case .vertical: + var contentSizeHeight: CGFloat = self.leadingSpacing*2 // Leading & trailing spacing + contentSizeHeight += CGFloat(numberOfItems-1)*self.actualInteritemSpacing // Interitem spacing + contentSizeHeight += CGFloat(numberOfItems)*self.actualItemSize.height // Item sizes + let contentSize = CGSize(width: collectionView.frame.width, height: contentSizeHeight) + return contentSize + } }() self.adjustCollectionViewBounds() } @@ -115,36 +126,36 @@ class FSPagerViewLayout: UICollectionViewLayout { return layoutAttributes } // Calculate start position and index of certain rects - let numberOfItemsBefore = max(Int((rect.minX-self.leadingSpacing)/self.itemSpacing),0) + let numberOfItemsBefore = self.scrollDirection == .horizontal ? max(Int((rect.minX-self.leadingSpacing)/self.itemSpacing),0) : max(Int((rect.minY-self.leadingSpacing)/self.itemSpacing),0) let startPosition = self.leadingSpacing + CGFloat(numberOfItemsBefore)*self.itemSpacing let startIndex = numberOfItemsBefore // Create layout attributes var itemIndex = startIndex - var x = startPosition - let maxPosition = min(rect.maxX,self.contentSize.width-self.actualItemSize.width-self.leadingSpacing) - while x <= maxPosition { + + var origin = startPosition + let maxPosition = self.scrollDirection == .horizontal ? min(rect.maxX,self.contentSize.width-self.actualItemSize.width-self.leadingSpacing) : min(rect.maxY,self.contentSize.height-self.actualItemSize.height-self.leadingSpacing) + while origin <= maxPosition { let indexPath = IndexPath(item: itemIndex%self.numberOfItems, section: itemIndex/self.numberOfItems) let attributes = self.layoutAttributesForItem(at: indexPath) as! FSPagerViewLayoutAttributes - self.applyTransform(to: attributes) + self.applyTransform(to: attributes, with: self.pagerView?.transformer) layoutAttributes.append(attributes) itemIndex += 1 - x += self.itemSpacing + origin += self.itemSpacing } return layoutAttributes + } override open func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { - guard let collectionView = self.collectionView else { - return UICollectionViewLayoutAttributes(forCellWith: indexPath) + var attributes = self.layoutAttributes[indexPath] + if attributes == nil { + attributes = FSPagerViewLayoutAttributes(forCellWith: indexPath) + self.layoutAttributes[indexPath] = attributes } - if let attributes = self.layoutAttributes[indexPath] { - return attributes - } - let attributes = FSPagerViewLayoutAttributes(forCellWith: indexPath) - let x = self.frame(for: indexPath).minX - let center = CGPoint(x: x+self.actualItemSize.width*0.5, y: collectionView.frame.height*0.5) - attributes.center = center - attributes.size = self.actualItemSize + let frame = self.frame(for: indexPath) + let center = CGPoint(x: frame.midX, y: frame.midY) + attributes!.center = center + attributes!.size = self.actualItemSize self.layoutAttributes[indexPath] = attributes return attributes } @@ -155,6 +166,9 @@ class FSPagerViewLayout: UICollectionViewLayout { } var proposedContentOffset = proposedContentOffset 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) @@ -166,7 +180,22 @@ class FSPagerViewLayout: UICollectionViewLayout { } return offset }() - proposedContentOffset = CGPoint(x: proposedContentOffsetX, y: proposedContentOffset.y) + 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 + }() + proposedContentOffset = CGPoint(x: proposedContentOffsetX, y: proposedContentOffsetY) return proposedContentOffset } @@ -182,14 +211,38 @@ class FSPagerViewLayout: UICollectionViewLayout { guard let collectionView = self.collectionView else { return origin } - let contentOffset = CGPoint(x: origin.x - (collectionView.frame.width*0.5-self.actualItemSize.width*0.5), y: collectionView.contentOffset.y) + let contentOffsetX: CGFloat = { + if self.scrollDirection == .vertical { + return 0 + } + let contentOffsetX = origin.x - (collectionView.frame.width*0.5-self.actualItemSize.width*0.5) + return contentOffsetX + }() + let contentOffsetY: CGFloat = { + if self.scrollDirection == .horizontal { + return 0 + } + let contentOffsetY = origin.y - (collectionView.frame.height*0.5-self.actualItemSize.height*0.5) + return contentOffsetY + }() + let contentOffset = CGPoint(x: contentOffsetX, y: contentOffsetY) return contentOffset } internal func frame(for indexPath: IndexPath) -> CGRect { let numberOfItems = self.numberOfItems*indexPath.section + indexPath.item - let originX = self.leadingSpacing + CGFloat(numberOfItems)*self.itemSpacing - let originY = (self.collectionView!.frame.height-self.actualItemSize.height)/2.0 + let originX: CGFloat = { + if self.scrollDirection == .vertical { + return (self.collectionView!.frame.width-self.actualItemSize.width)*0.5 + } + return self.leadingSpacing + CGFloat(numberOfItems)*self.itemSpacing + }() + let originY: CGFloat = { + if self.scrollDirection == .horizontal { + return (self.collectionView!.frame.height-self.actualItemSize.height)*0.5 + } + return self.leadingSpacing + CGFloat(numberOfItems)*self.itemSpacing + }() let origin = CGPoint(x: originX, y: originY) let frame = CGRect(origin: origin, size: self.actualItemSize) return frame @@ -217,23 +270,27 @@ class FSPagerViewLayout: UICollectionViewLayout { } let currentIndex = pagerView.currentIndex let newIndexPath = IndexPath(item: currentIndex, section: self.isInfinite ? self.numberOfSections/2 : 0) - let contentOffsetX = self.contentOffset(for: newIndexPath).x - let contentOffset = CGPoint(x: contentOffsetX, y: 0) + let contentOffset = self.contentOffset(for: newIndexPath) let newBounds = CGRect(origin: contentOffset, size: collectionView.frame.size) collectionView.bounds = newBounds } - fileprivate func applyTransform(to attributes: FSPagerViewLayoutAttributes) { + fileprivate func applyTransform(to attributes: FSPagerViewLayoutAttributes, with transformer: FSPagerViewTransformer?) { guard let collectionView = self.collectionView else { return } - guard let transformer = self.pagerView?.transformer else { + guard let transformer = transformer else { return } - let ruler = collectionView.bounds.midX - attributes.center.x = self.frame(for: attributes.indexPath).midX - attributes.position = (attributes.center.x-ruler)/self.itemSpacing - attributes.interitemSpacing = self.actualInteritemSpacing + switch self.scrollDirection { + case .horizontal: + let ruler = collectionView.bounds.midX + attributes.position = (attributes.center.x-ruler)/self.itemSpacing + case .vertical: + let ruler = collectionView.bounds.midY + attributes.position = (attributes.center.y-ruler)/self.itemSpacing + } + attributes.zIndex = Int(self.numberOfItems)-Int(attributes.position) transformer.applyTransform(to: attributes) } diff --git a/Sources/FSPageViewTransformer.swift b/Sources/FSPageViewTransformer.swift index b815f61..946d7fe 100644 --- a/Sources/FSPageViewTransformer.swift +++ b/Sources/FSPageViewTransformer.swift @@ -49,15 +49,25 @@ open class FSPagerViewTransformer: NSObject { // Apply transform to attributes - zIndex: Int, frame: CGRect, alpha: CGFloat, transform: CGAffineTransform or transform3D: CATransform3D. open func applyTransform(to attributes: FSPagerViewLayoutAttributes) { + guard let pagerView = self.pagerView else { + return + } let position = attributes.position - let itemSpacing = attributes.interitemSpacing + attributes.bounds.width + let scrollDirection = pagerView.scrollDirection + let itemSpacing = (scrollDirection == .horizontal ? attributes.bounds.width : attributes.bounds.height) + self.proposedInteritemSpacing() switch self.type { case .none: break case .crossFading: var zIndex = 0 var alpha: CGFloat = 0 - let transform = CGAffineTransform(translationX: -itemSpacing * position, y: 0) + var transform = CGAffineTransform.identity + switch scrollDirection { + case .horizontal: + transform.tx = -itemSpacing * position + case .vertical: + transform.ty = -itemSpacing * position + } if (abs(position) < 1) { // [-1,1] // Use the default slide transition when moving to the left page alpha = 1 - abs(position) @@ -80,11 +90,18 @@ open class FSPagerViewTransformer: NSObject { case -1 ... 1 : // [-1,1] // Modify the default slide transition to shrink the page as well let scaleFactor = max(self.minimumScale, 1 - abs(position)) - let vertMargin = attributes.bounds.height * (1 - scaleFactor) / 2; - let horzMargin = itemSpacing * (1 - scaleFactor) / 2; transform.a = scaleFactor transform.d = scaleFactor - transform.tx = position < 0 ? (horzMargin - vertMargin*2) : (-horzMargin + vertMargin*2) + switch scrollDirection { + case .horizontal: + let vertMargin = attributes.bounds.height * (1 - scaleFactor) / 2; + let horzMargin = itemSpacing * (1 - scaleFactor) / 2; + transform.tx = position < 0 ? (horzMargin - vertMargin*2) : (-horzMargin + vertMargin*2) + case .vertical: + let horzMargin = attributes.bounds.width * (1 - scaleFactor) / 2; + let vertMargin = itemSpacing * (1 - scaleFactor) / 2; + transform.ty = position < 0 ? (vertMargin - horzMargin*2) : (-vertMargin + horzMargin*2) + } // Fade the page relative to its size. alpha = self.minimumAlpha + (scaleFactor-self.minimumScale)/(1-self.minimumScale)*(1-self.minimumAlpha) case 1 ... CGFloat.greatestFiniteMagnitude : // (1,+Infinity] @@ -111,18 +128,23 @@ open class FSPagerViewTransformer: NSObject { transform.a = 1 transform.d = 1 zIndex = 1 - case 0 ..< 1: // (0,1] + case 0 ..< 1: // (0,1) // Fade the page out. alpha = CGFloat(1.0) - position // Counteract the default slide transition - transform.tx = itemSpacing * -position; + switch scrollDirection { + case .horizontal: + transform.tx = itemSpacing * -position + case .vertical: + transform.ty = itemSpacing * -position + } // Scale the page down (between minimumScale and 1) let scaleFactor = self.minimumScale + (1.0 - self.minimumScale) * (1.0 - abs(position)); transform.a = scaleFactor transform.d = scaleFactor zIndex = 0 - case 1 ... CGFloat.greatestFiniteMagnitude: // (1,+Infinity] + case 1 ... CGFloat.greatestFiniteMagnitude: // [1,+Infinity) // This page is way off-screen to the right. alpha = 0 zIndex = 0 @@ -133,6 +155,10 @@ open class FSPagerViewTransformer: NSObject { attributes.transform = transform attributes.zIndex = zIndex case .overlap,.linear: + guard scrollDirection == .horizontal else { + // This type doesn't support vertical mode + return + } let scale = max(1 - (1-self.minimumScale) * abs(position), self.minimumScale) let transform = CGAffineTransform(scaleX: scale, y: scale) attributes.transform = transform @@ -141,6 +167,10 @@ open class FSPagerViewTransformer: NSObject { let zIndex = (1-abs(position)) * 10 attributes.zIndex = Int(zIndex) case .coverFlow: + guard scrollDirection == .horizontal else { + // This type doesn't support vertical mode + return + } let position = min(max(-position,-1) ,1) let rotation = sin(position*CGFloat(M_PI_2)) * CGFloat(M_PI_4)*1.5 let translationZ = -itemSpacing * 0.5 * abs(position) @@ -151,6 +181,10 @@ open class FSPagerViewTransformer: NSObject { attributes.zIndex = 100 - Int(abs(position)) attributes.transform3D = transform3D case .ferrisWheel, .invertedFerrisWheel: + guard scrollDirection == .horizontal else { + // This type doesn't support vertical mode + return + } // http://ronnqvi.st/translate-rotate-translate/ var zIndex = 0 var transform = CGAffineTransform.identity @@ -175,22 +209,34 @@ open class FSPagerViewTransformer: NSObject { attributes.zIndex = zIndex case .cubic: switch position { - case -1...1: + case -CGFloat.greatestFiniteMagnitude ... -1: + attributes.alpha = 0 + case -1 ..< 1: attributes.alpha = 1 attributes.zIndex = Int((1-position) * CGFloat(10)) let direction: CGFloat = position < 0 ? 1 : -1 - let theta = position * CGFloat(M_PI_2) - let width = attributes.bounds.width - // ForwardX -> RotateY -> BackwardX - attributes.center.x += direction*width*0.5 // ForwardX + let theta = position * CGFloat(M_PI_2) * (scrollDirection == .horizontal ? 1 : -1) + let radius = scrollDirection == .horizontal ? attributes.bounds.width : attributes.bounds.height var transform3D = CATransform3DIdentity transform3D.m34 = -0.002 - transform3D = CATransform3DRotate(transform3D, theta, 0, 1, 0) // RotateY - transform3D = CATransform3DTranslate(transform3D,-direction*width*0.5, 0, 0) // BackwardX + switch scrollDirection { + case .horizontal: + // ForwardX -> RotateY -> BackwardX + attributes.center.x += direction*radius*0.5 // ForwardX + transform3D = CATransform3DRotate(transform3D, theta, 0, 1, 0) // RotateY + transform3D = CATransform3DTranslate(transform3D,-direction*radius*0.5, 0, 0) // BackwardX + case .vertical: + // ForwardY -> RotateX -> BackwardY + attributes.center.y += direction*radius*0.5 // ForwardY + transform3D = CATransform3DRotate(transform3D, theta, 1, 0, 0) // RotateX + transform3D = CATransform3DTranslate(transform3D,0, -direction*radius*0.5, 0) // BackwardY + } attributes.transform3D = transform3D - default: - attributes.zIndex = 0 + case 1 ... CGFloat.greatestFiniteMagnitude: attributes.alpha = 0 + default: + attributes.alpha = 0 + attributes.zIndex = 0 } } } @@ -200,14 +246,27 @@ open class FSPagerViewTransformer: NSObject { guard let pagerView = self.pagerView else { return 0 } + let scrollDirection = pagerView.scrollDirection switch self.type { case .overlap: + guard scrollDirection == .horizontal else { + return 0 + } return pagerView.itemSize.width * -self.minimumScale * 0.6 case .linear: + guard scrollDirection == .horizontal else { + return 0 + } return pagerView.itemSize.width * -self.minimumScale * 0.2 case .coverFlow: + guard scrollDirection == .horizontal else { + return 0 + } return -pagerView.itemSize.width * sin(CGFloat(M_PI_4)/4.0*3.0) case .ferrisWheel,.invertedFerrisWheel: + guard scrollDirection == .horizontal else { + return 0 + } return -pagerView.itemSize.width * 0.15 case .cubic: return 0 diff --git a/Sources/FSPagerCollectionView.swift b/Sources/FSPagerCollectionView.swift index a0e08a0..780733e 100644 --- a/Sources/FSPagerCollectionView.swift +++ b/Sources/FSPagerCollectionView.swift @@ -12,7 +12,7 @@ import UIKit class FSPagerViewCollectionView: UICollectionView { - fileprivate weak var pagerView: FSPagerView? { + fileprivate var pagerView: FSPagerView? { return self.superview?.superview as? FSPagerView } diff --git a/Sources/FSPagerView.swift b/Sources/FSPagerView.swift index 1d0ed0c..2182ce1 100644 --- a/Sources/FSPagerView.swift +++ b/Sources/FSPagerView.swift @@ -74,6 +74,12 @@ public protocol FSPagerViewDelegate: NSObjectProtocol { } +@objc +public enum FSPagerViewScrollDirection: Int { + case horizontal + case vertical +} + @IBDesignable open class FSPagerView: UIView,UICollectionViewDataSource,UICollectionViewDelegate { @@ -87,7 +93,14 @@ open class FSPagerView: UIView,UICollectionViewDataSource,UICollectionViewDelega open weak var dataSource: FSPagerViewDataSource? open weak var delegate: FSPagerViewDelegate? #endif - + + /// The scroll direction of the pager view. Default is horizontal. + open var scrollDirection: FSPagerViewScrollDirection = .horizontal { + didSet { + self.collectionViewLayout.forceInvalidate() + } + } + /// The time interval of automatic sliding. 0 means disabling automatic sliding. Default is 0. @IBInspectable open var automaticSlidingInterval: CGFloat = 0.0 { @@ -119,8 +132,8 @@ open class FSPagerView: UIView,UICollectionViewDataSource,UICollectionViewDelega @IBInspectable open var isInfinite: Bool = false { didSet { + self.collectionViewLayout.needsReprepare = true self.collectionView.reloadData() - self.collectionViewLayout.forceInvalidate() } } @@ -156,7 +169,8 @@ open class FSPagerView: UIView,UICollectionViewDataSource,UICollectionViewDelega /// The percentage of x position at which the origin of the content view is offset from the origin of the pagerView view. open var scrollOffset: CGFloat { - let scrollOffset = Double(self.collectionView.contentOffset.x.divided(by: self.collectionViewLayout.itemSpacing)) + let contentOffset = max(self.collectionView.contentOffset.x, self.collectionView.contentOffset.y) + let scrollOffset = Double(contentOffset.divided(by: self.collectionViewLayout.itemSpacing)) return fmod(CGFloat(scrollOffset), CGFloat(Double(self.numberOfItems))) } @@ -179,13 +193,23 @@ open class FSPagerView: UIView,UICollectionViewDataSource,UICollectionViewDelega fileprivate var dequeingSection = 0 fileprivate var centermostIndexPath: IndexPath { - guard self.numberOfItems > 0, self.collectionView.contentSize.width > 0 else { + guard self.numberOfItems > 0, self.collectionView.contentSize != .zero else { return IndexPath(item: 0, section: 0) } let sortedIndexPaths = self.collectionView.indexPathsForVisibleItems.sorted { (l, r) -> Bool in - let leftCenter = self.collectionViewLayout.frame(for: l).midX - let rightCenter = self.collectionViewLayout.frame(for: r).midX - let ruler = self.collectionView.bounds.midX + let leftFrame = self.collectionViewLayout.frame(for: l) + let rightFrame = self.collectionViewLayout.frame(for: r) + var leftCenter: CGFloat,rightCenter: CGFloat,ruler: CGFloat + switch self.scrollDirection { + case .horizontal: + leftCenter = leftFrame.midX + rightCenter = rightFrame.midX + ruler = self.collectionView.bounds.midX + case .vertical: + leftCenter = leftFrame.midY + rightCenter = rightFrame.midY + ruler = self.collectionView.bounds.midY + } return abs(ruler-leftCenter) < abs(ruler-rightCenter) } let indexPath = sortedIndexPaths.first @@ -344,7 +368,8 @@ open class FSPagerView: UIView,UICollectionViewDataSource,UICollectionViewDelega public func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) { if let function = self.delegate?.pagerViewWillEndDragging(_:targetIndex:) { - let targetItem = lround(Double(targetContentOffset.pointee.x/self.collectionViewLayout.itemSpacing)) + let contentOffset = self.scrollDirection == .horizontal ? targetContentOffset.pointee.x : targetContentOffset.pointee.y + let targetItem = lround(Double(contentOffset/self.collectionViewLayout.itemSpacing)) function(self, targetItem % self.numberOfItems) } if self.automaticSlidingInterval > 0 { @@ -417,7 +442,8 @@ open class FSPagerView: UIView,UICollectionViewDataSource,UICollectionViewDelega @objc(selectItemAtIndex:animated:) open func selectItem(at index: Int, animated: Bool) { let indexPath = self.nearbyIndexPath(for: index) - self.collectionView.selectItem(at: indexPath, animated: animated, scrollPosition: .centeredHorizontally) + let scrollPosition: UICollectionViewScrollPosition = self.scrollDirection == .horizontal ? .centeredVertically : .centeredVertically + self.collectionView.selectItem(at: indexPath, animated: animated, scrollPosition: scrollPosition) } /// Deselects the item at the specified index. diff --git a/Sources/FSPagerViewLayoutAttributes.swift b/Sources/FSPagerViewLayoutAttributes.swift index 06b4396..d93cb33 100644 --- a/Sources/FSPagerViewLayoutAttributes.swift +++ b/Sources/FSPagerViewLayoutAttributes.swift @@ -11,7 +11,6 @@ import UIKit open class FSPagerViewLayoutAttributes: UICollectionViewLayoutAttributes { open var position: CGFloat = 0 - open var interitemSpacing: CGFloat = 0 open override func isEqual(_ object: Any?) -> Bool { guard let object = object as? FSPagerViewLayoutAttributes else { @@ -19,14 +18,12 @@ open class FSPagerViewLayoutAttributes: UICollectionViewLayoutAttributes { } var isEqual = super.isEqual(object) isEqual = isEqual && (self.position == object.position) - isEqual = isEqual && (self.interitemSpacing == object.interitemSpacing) return isEqual } open override func copy(with zone: NSZone? = nil) -> Any { let copy = super.copy(with: zone) as! FSPagerViewLayoutAttributes copy.position = self.position - copy.interitemSpacing = self.interitemSpacing return copy }