From fcef559931aa01ccec869bc0610f0f52d7b2de0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=81=E6=96=87=E8=B6=85?= Date: Thu, 7 Sep 2017 11:45:27 +0800 Subject: [PATCH] 1. Add 'removesInfiniteLoopForSingleItem' for FSPagerView 2. Add 'alwaysBounceVertical' and 'alwaysBounceHorizontal' for FSPagerView 3. Add 'hidesForSinglePage' for FSPageControl 4. Update Examples --- .../Base.lproj/Main.storyboard | 28 +++++++---- .../BasicExampleViewController.swift | 46 +++++++++++------ .../PageControlExampleViewController.swift | 1 + FSPagerView.podspec | 2 +- FSPagerView/FSPagerView/Info.plist | 2 +- .../Base.lproj/Main.storyboard | 25 ++++++---- .../BasicExampleViewController.m | 34 ++++++++++--- Sources/FSPageControl.swift | 50 ++++++++++--------- Sources/FSPageViewLayout.swift | 3 +- Sources/FSPagerView.swift | 27 +++++++++- 10 files changed, 149 insertions(+), 69 deletions(-) diff --git a/FSPageViewExample-Swift/FSPagerViewExample/Base.lproj/Main.storyboard b/FSPageViewExample-Swift/FSPagerViewExample/Base.lproj/Main.storyboard index 1202356..a184a2f 100644 --- a/FSPageViewExample-Swift/FSPagerViewExample/Base.lproj/Main.storyboard +++ b/FSPageViewExample-Swift/FSPagerViewExample/Base.lproj/Main.storyboard @@ -1,11 +1,11 @@ - + - + @@ -129,6 +129,11 @@ + + + + + @@ -139,8 +144,11 @@ + + + - + @@ -148,7 +156,7 @@ - + @@ -165,10 +173,10 @@ - + - + @@ -250,7 +258,7 @@ - + @@ -325,7 +333,7 @@ - + @@ -342,10 +350,10 @@ - + - + diff --git a/FSPageViewExample-Swift/FSPagerViewExample/BasicExampleViewController.swift b/FSPageViewExample-Swift/FSPagerViewExample/BasicExampleViewController.swift index 828d514..5ee2ab4 100644 --- a/FSPageViewExample-Swift/FSPagerViewExample/BasicExampleViewController.swift +++ b/FSPageViewExample-Swift/FSPagerViewExample/BasicExampleViewController.swift @@ -10,9 +10,10 @@ import UIKit class BasicExampleViewController: UIViewController,UITableViewDataSource,UITableViewDelegate,FSPagerViewDataSource,FSPagerViewDelegate { - fileprivate let sectionTitles = ["Configurations", "Item Size", "Interitem Spacing"] + fileprivate let sectionTitles = ["Configurations", "Item Size", "Interitem Spacing", "Number Of Items"] fileprivate let configurationTitles = ["Automatic sliding","Infinite"] fileprivate let imageNames = ["1.jpg","2.jpg","3.jpg","4.jpg","5.jpg","6.jpg","7.jpg"] + fileprivate var numberOfItems = 7 @IBOutlet weak var tableView: UITableView! @IBOutlet weak var pagerView: FSPagerView! { @@ -30,18 +31,6 @@ class BasicExampleViewController: UIViewController,UITableViewDataSource,UITable } } - @IBAction func sliderValueChanged(_ sender: UISlider) { - switch sender.tag { - case 1: - let newScale = 0.5+CGFloat(sender.value)*0.5 // [0.5 - 1.0] - self.pagerView.itemSize = self.pagerView.frame.size.applying(CGAffineTransform(scaleX: newScale, y: newScale)) - case 2: - self.pagerView.interitemSpacing = CGFloat(sender.value) * 20 // [0 - 20] - default: - break - } - } - // MARK:- UITableViewDataSource func numberOfSections(in tableView: UITableView) -> Int { @@ -53,7 +42,7 @@ class BasicExampleViewController: UIViewController,UITableViewDataSource,UITable switch section { case 0: return self.configurationTitles.count - case 1,2: + case 1,2,3: return 1 default: break @@ -85,6 +74,7 @@ class BasicExampleViewController: UIViewController,UITableViewDataSource,UITable let value: CGFloat = (0.5-scale)*2 return Float(value) }() + slider.isContinuous = true return cell case 2: // Interitem Spacing @@ -92,6 +82,17 @@ class BasicExampleViewController: UIViewController,UITableViewDataSource,UITable let slider = cell.contentView.subviews.first as! UISlider slider.tag = indexPath.section slider.value = Float(self.pagerView.interitemSpacing.divided(by: 20.0)) + slider.isContinuous = true + return cell + case 3: + // Number Of Items + let cell = tableView.dequeueReusableCell(withIdentifier: "slider_cell")! + let slider = cell.contentView.subviews.first as! UISlider + slider.tag = indexPath.section + slider.minimumValue = 1.0 / 7 + slider.maximumValue = 1.0 + slider.value = Float(self.numberOfItems) / 7.0 + slider.isContinuous = false return cell default: break @@ -131,7 +132,7 @@ class BasicExampleViewController: UIViewController,UITableViewDataSource,UITable // MARK:- FSPagerView DataSource public func numberOfItems(in pagerView: FSPagerView) -> Int { - return self.imageNames.count + return self.numberOfItems } public func pagerView(_ pagerView: FSPagerView, cellForItemAt index: Int) -> FSPagerViewCell { @@ -158,6 +159,21 @@ class BasicExampleViewController: UIViewController,UITableViewDataSource,UITable self.pageControl.currentPage = pagerView.currentIndex // Or Use KVO with property "currentIndex" } + @IBAction func sliderValueChanged(_ sender: UISlider) { + switch sender.tag { + case 1: + let newScale = 0.5+CGFloat(sender.value)*0.5 // [0.5 - 1.0] + self.pagerView.itemSize = self.pagerView.frame.size.applying(CGAffineTransform(scaleX: newScale, y: newScale)) + case 2: + self.pagerView.interitemSpacing = CGFloat(sender.value) * 20 // [0 - 20] + case 3: + self.numberOfItems = Int(roundf(sender.value*7.0)) + self.pageControl.numberOfPages = self.numberOfItems + self.pagerView.reloadData() + default: + break + } + } } diff --git a/FSPageViewExample-Swift/FSPagerViewExample/PageControlExampleViewController.swift b/FSPageViewExample-Swift/FSPagerViewExample/PageControlExampleViewController.swift index 669a203..c74f3a5 100644 --- a/FSPageViewExample-Swift/FSPagerViewExample/PageControlExampleViewController.swift +++ b/FSPageViewExample-Swift/FSPagerViewExample/PageControlExampleViewController.swift @@ -130,6 +130,7 @@ class PageControlExampleViewController: UIViewController,UITableViewDataSource,U self.pageControl.numberOfPages = self.imageNames.count self.pageControl.contentHorizontalAlignment = .right self.pageControl.contentInsets = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20) + self.pageControl.hidesForSinglePage = true } } diff --git a/FSPagerView.podspec b/FSPagerView.podspec index 628e7e5..25145d5 100644 --- a/FSPagerView.podspec +++ b/FSPagerView.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "FSPagerView" - s.version = "0.5.5" + s.version = "0.6.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 d7269f8..df80ae9 100644 --- a/FSPagerView/FSPagerView/Info.plist +++ b/FSPagerView/FSPagerView/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 0.5.5 + 0.6.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass diff --git a/FSPagerViewExample-Objc/FSPagerViewExample-Objc/Base.lproj/Main.storyboard b/FSPagerViewExample-Objc/FSPagerViewExample-Objc/Base.lproj/Main.storyboard index d077223..687792e 100644 --- a/FSPagerViewExample-Objc/FSPagerViewExample-Objc/Base.lproj/Main.storyboard +++ b/FSPagerViewExample-Objc/FSPagerViewExample-Objc/Base.lproj/Main.storyboard @@ -1,11 +1,11 @@ - + - + @@ -142,7 +142,7 @@ - + @@ -217,7 +217,7 @@ - + @@ -234,10 +234,10 @@ - + - + @@ -311,6 +311,10 @@ + + + + @@ -321,6 +325,9 @@ + + + @@ -330,7 +337,7 @@ - + @@ -347,10 +354,10 @@ - + - + diff --git a/FSPagerViewExample-Objc/FSPagerViewExample-Objc/BasicExampleViewController.m b/FSPagerViewExample-Objc/FSPagerViewExample-Objc/BasicExampleViewController.m index 5f4fb82..3bf74d4 100644 --- a/FSPagerViewExample-Objc/FSPagerViewExample-Objc/BasicExampleViewController.m +++ b/FSPagerViewExample-Objc/FSPagerViewExample-Objc/BasicExampleViewController.m @@ -15,6 +15,7 @@ @property (strong, nonatomic) NSArray *sectionTitles; @property (strong, nonatomic) NSArray *configurationTitles; @property (strong, nonatomic) NSArray *imageNames; +@property (assign, nonatomic) NSInteger numberOfItems; @property (weak , nonatomic) IBOutlet UITableView *tableView; @property (weak , nonatomic) IBOutlet FSPagerView *pagerView; @@ -32,9 +33,10 @@ { [super viewDidLoad]; - self.sectionTitles = @[@"Configurations", @"Item Size", @"Interitem Spacing"]; + self.sectionTitles = @[@"Configurations", @"Item Size", @"Interitem Spacing", @"Number Of Items"]; self.configurationTitles = @[@"Automatic sliding", @"Infinite"]; self.imageNames = @[@"1.jpg", @"2.jpg", @"3.jpg", @"4.jpg", @"5.jpg", @"6.jpg", @"7.jpg"]; + self.numberOfItems = 7; [self.pagerView registerClass:[FSPagerViewCell class] forCellWithReuseIdentifier:@"cell"]; self.pagerView.itemSize = self.pagerView.frame.size; @@ -53,12 +55,13 @@ - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { switch (section) { - case 0: + case 0: return self.configurationTitles.count; - case 1: - case 2: + case 1: + case 2: + case 3: return 1; - default: + default: break; } return 0; @@ -90,6 +93,7 @@ CGFloat value = (scale-0.5)*2; value; }); + slider.continuous = YES; return cell; } case 2: { @@ -98,6 +102,18 @@ UISlider *slider = cell.contentView.subviews.firstObject; slider.tag = indexPath.section; slider.value = self.pagerView.interitemSpacing / 20.0; + slider.continuous = YES; + return cell; + } + case 3: { + // Number Of Items + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"slider_cell"]; + UISlider *slider = cell.contentView.subviews.firstObject; + slider.tag = indexPath.section; + slider.value = self.numberOfItems / 7.0; + slider.minimumValue = 1.0 / 7; + slider.maximumValue = 1.0; + slider.continuous = NO; return cell; } default: @@ -146,7 +162,7 @@ - (NSInteger)numberOfItemsInPagerView:(FSPagerView *)pagerView { - return self.imageNames.count; + return self.numberOfItems; } - (FSPagerViewCell *)pagerView:(FSPagerView *)pagerView cellForItemAtIndex:(NSInteger)index @@ -189,6 +205,12 @@ self.pagerView.interitemSpacing = sender.value * 20; // [0 - 20] break; } + case 3: { + self.numberOfItems = roundf(sender.value * 7); + self.pageControl.numberOfPages = self.numberOfItems; + [self.pagerView reloadData]; + break; + } default: break; } diff --git a/Sources/FSPageControl.swift b/Sources/FSPageControl.swift index 20edbac..d522d9c 100644 --- a/Sources/FSPageControl.swift +++ b/Sources/FSPageControl.swift @@ -58,6 +58,14 @@ open class FSPageControl: UIControl { } } + /// Hide the indicator if there is only one page. default is NO + @IBInspectable + open var hidesForSinglePage: Bool = false { + didSet { + self.setNeedsUpdateIndicators() + } + } + internal var strokeColors: [UIControlState: UIColor] = [:] internal var fillColors: [UIControlState: UIColor] = [:] internal var paths: [UIControlState: UIBezierPath] = [:] @@ -71,17 +79,6 @@ open class FSPageControl: UIControl { fileprivate var needsCreateIndicators = false fileprivate var indicatorLayers = [CAShapeLayer]() - fileprivate var runLoopObserver: CFRunLoopObserver? - fileprivate var runLoopCallback: CFRunLoopObserverCallBack = { - (observer: CFRunLoopObserver?, activity: CFRunLoopActivity, info: UnsafeMutableRawPointer?) -> Void in - guard let info = info else { - return - } - let pageControl = Unmanaged.fromOpaque(info).takeUnretainedValue() - pageControl.createIndicatorsIfNecessary() - pageControl.updateIndicatorsIfNecessary() - } - public override init(frame: CGRect) { super.init(frame: frame) commonInit() @@ -92,10 +89,6 @@ open class FSPageControl: UIControl { commonInit() } - deinit { - CFRunLoopRemoveObserver(CFRunLoopGetCurrent(), self.runLoopObserver, .commonModes); - } - open override func layoutSubviews() { super.layoutSubviews() self.contentView.frame = { @@ -218,18 +211,14 @@ open class FSPageControl: UIControl { self.addSubview(view) self.contentView = view - // RunLoop - let runLoop = CFRunLoopGetCurrent() - let activities: CFRunLoopActivity = [.entry,.afterWaiting] - var context = CFRunLoopObserverContext(version: 0, info: Unmanaged.passUnretained(self).toOpaque(), retain: nil, release: nil, copyDescription: nil) - self.runLoopObserver = CFRunLoopObserverCreate(nil, activities.rawValue, true, Int.max, self.runLoopCallback, &context) - CFRunLoopAddObserver(runLoop, self.runLoopObserver, .commonModes) - } fileprivate func setNeedsUpdateIndicators() { self.needsUpdateIndicators = true self.setNeedsLayout() + DispatchQueue.main.async { + self.updateIndicatorsIfNecessary() + } } fileprivate func updateIndicatorsIfNecessary() { @@ -240,8 +229,12 @@ open class FSPageControl: UIControl { return } self.needsUpdateIndicators = false - self.indicatorLayers.forEach { (layer) in - self.updateIndicatorAttributes(for: layer) + self.contentView.isHidden = self.hidesForSinglePage && self.numberOfPages <= 1 + if !self.contentView.isHidden { + self.indicatorLayers.forEach { (layer) in + layer.isHidden = false + self.updateIndicatorAttributes(for: layer) + } } } @@ -274,6 +267,9 @@ open class FSPageControl: UIControl { fileprivate func setNeedsCreateIndicators() { self.needsCreateIndicators = true + DispatchQueue.main.async { + self.createIndicatorsIfNecessary() + } } fileprivate func createIndicatorsIfNecessary() { @@ -281,6 +277,11 @@ open class FSPageControl: UIControl { return } self.needsCreateIndicators = false + CATransaction.begin() + CATransaction.setDisableActions(true) + if self.currentPage >= self.numberOfPages { + self.currentPage = self.numberOfPages - 1 + } self.indicatorLayers.forEach { (layer) in layer.removeFromSuperlayer() } @@ -293,6 +294,7 @@ open class FSPageControl: UIControl { } self.setNeedsUpdateIndicators() self.updateIndicatorsIfNecessary() + CATransaction.commit() } } diff --git a/Sources/FSPageViewLayout.swift b/Sources/FSPageViewLayout.swift index b59d4b9..6b7bc8c 100644 --- a/Sources/FSPageViewLayout.swift +++ b/Sources/FSPageViewLayout.swift @@ -258,11 +258,12 @@ class FSPagerViewLayout: UICollectionViewLayout { guard let collectionView = self.collectionView, let pagerView = self.pagerView else { return } - let currentIndex = pagerView.currentIndex + let currentIndex = min(pagerView.currentIndex, pagerView.numberOfItems - 1) let newIndexPath = IndexPath(item: currentIndex, section: self.isInfinite ? self.numberOfSections/2 : 0) let contentOffset = self.contentOffset(for: newIndexPath) let newBounds = CGRect(origin: contentOffset, size: collectionView.frame.size) collectionView.bounds = newBounds + pagerView.currentIndex = currentIndex; } fileprivate func applyTransform(to attributes: FSPagerViewLayoutAttributes, with transformer: FSPagerViewTransformer?) { diff --git a/Sources/FSPagerView.swift b/Sources/FSPagerView.swift index bcc9b64..1911aa9 100644 --- a/Sources/FSPagerView.swift +++ b/Sources/FSPagerView.swift @@ -137,6 +137,21 @@ open class FSPagerView: UIView,UICollectionViewDataSource,UICollectionViewDelega } } + /// A Boolean value that determines whether bouncing always occurs when horizontal scrolling reaches the end of the content view. + @IBInspectable + open var alwaysBounceHorizontal: Bool = false { + didSet { + self.collectionView.alwaysBounceHorizontal = self.alwaysBounceHorizontal; + } + } + + /// A Boolean value that determines whether bouncing always occurs when vertical scrolling reaches the end of the content view. + @IBInspectable + open var alwaysBounceVertical: Bool = false { + didSet { + self.collectionView.alwaysBounceVertical = self.alwaysBounceVertical; + } + } /// The background view of the pager view. @IBInspectable @@ -167,6 +182,14 @@ open class FSPagerView: UIView,UICollectionViewDataSource,UICollectionViewDelega return self.collectionView.isTracking } + /// Remove the infinite loop if there is only one item. default is NO + @IBInspectable + open var removesInfiniteLoopForSingleItem: Bool = false { + didSet { + self.reloadData() + } + } + /// 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 contentOffset = max(self.collectionView.contentOffset.x, self.collectionView.contentOffset.y) @@ -179,7 +202,7 @@ open class FSPagerView: UIView,UICollectionViewDataSource,UICollectionViewDelega return self.collectionView.panGestureRecognizer } - open fileprivate(set) dynamic var currentIndex: Int = 0 + open internal(set) dynamic var currentIndex: Int = 0 // MARK: - Private properties @@ -277,7 +300,7 @@ open class FSPagerView: UIView,UICollectionViewDataSource,UICollectionViewDelega guard self.numberOfItems > 0 else { return 0; } - self.numberOfSections = self.isInfinite ? Int(Int16.max)/self.numberOfItems : 1 + self.numberOfSections = self.isInfinite && (self.numberOfItems > 1 || !self.removesInfiniteLoopForSingleItem) ? Int(Int16.max)/self.numberOfItems : 1 return self.numberOfSections }