Add swiftlint & fixes

This commit is contained in:
pera 2017-05-05 15:51:39 -03:00
parent a0c75eb245
commit 21ca6cc08a
32 changed files with 504 additions and 512 deletions

51
.swiftlint.yml Normal file
View File

@ -0,0 +1,51 @@
disabled_rules: # rule identifiers to exclude from running
# - colon
# - comma
# - control_statement
- line_length
- function_body_length
- identifier_name
- type_name
- large_tuple
opt_in_rules: # some rules are only opt-in
- empty_count
# Find all the available rules by running:
# swiftlint rules
excluded: # paths to ignore during linting. Takes precedence over `included`.
- Carthage
- Pods
- Source/ExcludedFolder
- Source/ExcludedFile.swift
# configurable rules can be customized from this configuration file
# binary rules can set their severity level
force_cast: warning # implicitly
force_try:
severity: warning # explicitly
# rules that have both warning and error levels, can set just the warning level
# implicitly
line_length: 200
# they can set both implicitly with an array
type_body_length:
- 300 # warning
- 400 # error
# or they can set both explicitly
file_length:
warning: 500
error: 1200
# naming rules can set warnings/errors for min_length and max_length
# additionally they can set excluded names
type_name:
min_length: 4 # only warning
max_length: # warning and error
warning: 40
error: 50
excluded: iPhone # excluded via string
identifier_name:
min_length: # only min_length
error: 4 # only error
excluded: # excluded via string array
- id
- URL
- GlobalAPIKey
reporter: "xcode" # reporter type (xcode, json, csv, checkstyle, junit, html, emoji)

View File

@ -12,15 +12,14 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
UITabBar.appearance().tintColor = UIColor.init(red: 0.027, green: 0.725, blue: 0.608, alpha: 1)
UIApplication.shared.statusBarStyle = .lightContent
let _ = YoutubeExampleViewController(nibName: nil, bundle: nil)
_ = YoutubeExampleViewController(nibName: nil, bundle: nil)
return true
}
@ -46,6 +45,4 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}

View File

@ -27,51 +27,50 @@ import XLPagerTabStrip
class BarExampleViewController: BarPagerTabStripViewController {
var isReload = false
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func viewDidLoad() {
// set up style before super view did load is executed
settings.style.selectedBarBackgroundColor = .orange
// -
super.viewDidLoad()
}
// MARK: - PagerTabStripDataSource
override func viewControllers(for pagerTabStripController: PagerTabStripViewController) -> [UIViewController] {
let child_1 = TableChildExampleViewController(style: .plain, itemInfo: "Table View")
let child_2 = ChildExampleViewController(itemInfo: "View")
let child_3 = TableChildExampleViewController(style: .grouped, itemInfo: "Table View 2")
let child_4 = ChildExampleViewController(itemInfo: "View 2")
guard isReload else {
return [child_1, child_2, child_3, child_4]
}
var childViewControllers = [child_1, child_2, child_3, child_4]
for (index, _) in childViewControllers.enumerated(){
for index in childViewControllers.indices {
let nElements = childViewControllers.count - index
let n = (Int(arc4random()) % nElements) + index
if n != index{
if n != index {
swap(&childViewControllers[index], &childViewControllers[n])
}
}
let nItems = 1 + (arc4random() % 4)
return Array(childViewControllers.prefix(Int(nItems)))
}
override func reloadPagerTabStripView() {
isReload = true
if arc4random() % 2 == 0 {
pagerBehaviour = .progressive(skipIntermediateViewControllers: arc4random() % 2 == 0, elasticIndicatorLimit: arc4random() % 2 == 0 )
}
else {
} else {
pagerBehaviour = .common(skipIntermediateViewControllers: arc4random() % 2 == 0)
}
super.reloadPagerTabStripView()

View File

@ -26,18 +26,18 @@ import Foundation
import XLPagerTabStrip
class ButtonBarExampleViewController: ButtonBarPagerTabStripViewController {
var isReload = false
override func viewDidLoad() {
super.viewDidLoad()
buttonBarView.selectedBar.backgroundColor = .orange
buttonBarView.backgroundColor = UIColor(red: 7/255, green: 185/255, blue: 155/255, alpha: 1)
}
// MARK: - PagerTabStripDataSource
override func viewControllers(for pagerTabStripController: PagerTabStripViewController) -> [UIViewController] {
let child_1 = TableChildExampleViewController(style: .plain, itemInfo: "Table View")
let child_2 = ChildExampleViewController(itemInfo: "View")
@ -47,30 +47,29 @@ class ButtonBarExampleViewController: ButtonBarPagerTabStripViewController {
let child_6 = ChildExampleViewController(itemInfo: "View 3")
let child_7 = TableChildExampleViewController(style: .grouped, itemInfo: "Table View 4")
let child_8 = ChildExampleViewController(itemInfo: "View 4")
guard isReload else {
return [child_1, child_2, child_3, child_4, child_5, child_6, child_7, child_8]
}
var childViewControllers = [child_1, child_2, child_3, child_4, child_6, child_7, child_8]
for (index, _) in childViewControllers.enumerated(){
for index in childViewControllers.indices {
let nElements = childViewControllers.count - index
let n = (Int(arc4random()) % nElements) + index
if n != index{
if n != index {
swap(&childViewControllers[index], &childViewControllers[n])
}
}
let nItems = 1 + (arc4random() % 8)
return Array(childViewControllers.prefix(Int(nItems)))
}
override func reloadPagerTabStripView() {
isReload = true
if arc4random() % 2 == 0 {
pagerBehaviour = .progressive(skipIntermediateViewControllers: arc4random() % 2 == 0, elasticIndicatorLimit: arc4random() % 2 == 0 )
}
else {
} else {
pagerBehaviour = .common(skipIntermediateViewControllers: arc4random() % 2 == 0)
}
super.reloadPagerTabStripView()

View File

@ -26,9 +26,9 @@ import Foundation
import XLPagerTabStrip
class ChildExampleViewController: UIViewController, IndicatorInfoProvider {
var itemInfo: IndicatorInfo = "View"
init(itemInfo: IndicatorInfo) {
self.itemInfo = itemInfo
super.init(nibName: nil, bundle: nil)
@ -37,23 +37,23 @@ class ChildExampleViewController: UIViewController, IndicatorInfoProvider {
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "XLPagerTabStrip"
view.addSubview(label)
view.backgroundColor = .white
view.addConstraint(NSLayoutConstraint(item: label, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: label, attribute: .centerY, relatedBy: .equal, toItem: view, attribute: .centerY, multiplier: 1, constant: -50))
}
// MARK: - IndicatorInfoProvider
func indicatorInfo(for pagerTabStripController: PagerTabStripViewController) -> IndicatorInfo {
return itemInfo
}

View File

@ -26,60 +26,61 @@ import Foundation
import XLPagerTabStrip
class TableChildExampleViewController: UITableViewController, IndicatorInfoProvider {
let cellIdentifier = "postCell"
var blackTheme = false
var itemInfo = IndicatorInfo(title: "View")
init(style: UITableViewStyle, itemInfo: IndicatorInfo) {
self.itemInfo = itemInfo
super.init(style: style)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "PostCell", bundle: Bundle.main), forCellReuseIdentifier: cellIdentifier)
tableView.estimatedRowHeight = 60.0;
tableView.estimatedRowHeight = 60.0
tableView.rowHeight = UITableViewAutomaticDimension
tableView.allowsSelection = false
if blackTheme {
tableView.backgroundColor = UIColor(red: 15/255.0, green: 16/255.0, blue: 16/255.0, alpha: 1.0)
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tableView.reloadData()
}
// MARK: - UITableViewDataSource
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return DataProvider.sharedInstance.postsData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! PostCell
let data = DataProvider.sharedInstance.postsData.object(at: indexPath.row) as!
NSDictionary
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? PostCell,
let data = DataProvider.sharedInstance.postsData.object(at: indexPath.row) as? NSDictionary else { return PostCell() }
cell.configureWithData(data)
if blackTheme {
cell.changeStylToBlack()
}
return cell
}
// MARK: - IndicatorInfoProvider
func indicatorInfo(for pagerTabStripController: PagerTabStripViewController) -> IndicatorInfo {
return itemInfo
}
}

File diff suppressed because one or more lines are too long

View File

@ -25,28 +25,25 @@
import UIKit
class PostCell: UITableViewCell {
@IBOutlet weak var userImage: UIImageView!
@IBOutlet weak var postName: UILabel!
@IBOutlet weak var postText: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
userImage.layer.cornerRadius = 10.0
}
func configureWithData(_ data: NSDictionary){
func configureWithData(_ data: NSDictionary) {
if let post = data["post"] as? NSDictionary, let user = post["user"] as? NSDictionary {
postName.text = user["name"] as? String
postText.text = post["text"] as? String
userImage.image = UIImage(named: postName.text!.replacingOccurrences(of: " ", with: "_"))
}
}
func changeStylToBlack(){
func changeStylToBlack() {
userImage?.layer.cornerRadius = 30.0
postText.text = nil
postName.font = UIFont(name: "HelveticaNeue-Light", size:18) ?? .systemFont(ofSize: 18)

View File

@ -26,10 +26,10 @@ import Foundation
import XLPagerTabStrip
class InstagramExampleViewController: ButtonBarPagerTabStripViewController {
@IBOutlet weak var shadowView: UIView!
let blueInstagramColor = UIColor(red: 37/255.0, green: 111/255.0, blue: 206/255.0, alpha: 1.0)
override func viewDidLoad() {
// change selected bar color
settings.style.buttonBarBackgroundColor = .white
@ -42,7 +42,7 @@ class InstagramExampleViewController: ButtonBarPagerTabStripViewController {
settings.style.buttonBarItemsShouldFillAvailableWidth = true
settings.style.buttonBarLeftContentInset = 0
settings.style.buttonBarRightContentInset = 0
changeCurrentIndexProgressive = { [weak self] (oldCell: ButtonBarViewCell?, newCell: ButtonBarViewCell?, progressPercentage: CGFloat, changeCurrentIndex: Bool, animated: Bool) -> Void in
guard changeCurrentIndex == true else { return }
oldCell?.label.textColor = .black
@ -50,9 +50,9 @@ class InstagramExampleViewController: ButtonBarPagerTabStripViewController {
}
super.viewDidLoad()
}
// MARK: - PagerTabStripDataSource
override func viewControllers(for pagerTabStripController: PagerTabStripViewController) -> [UIViewController] {
let child_1 = TableChildExampleViewController(style: .plain, itemInfo: "FOLLOWING")
let child_2 = ChildExampleViewController(itemInfo: "YOU")
@ -60,13 +60,8 @@ class InstagramExampleViewController: ButtonBarPagerTabStripViewController {
}
// MARK: - Custom Action
@IBAction func closeAction(_ sender: UIButton) {
dismiss(animated: true, completion: nil)
}
}

View File

@ -27,38 +27,37 @@ import XLPagerTabStrip
class NavButtonBarExampleViewController: ButtonBarPagerTabStripViewController {
var isReload = false
override func viewDidLoad() {
// set up style before super view did load is executed
settings.style.buttonBarBackgroundColor = .clear
settings.style.selectedBarBackgroundColor = .orange
//-
super.viewDidLoad()
buttonBarView.removeFromSuperview()
navigationController?.navigationBar.addSubview(buttonBarView)
changeCurrentIndexProgressive = { (oldCell: ButtonBarViewCell?, newCell: ButtonBarViewCell?, progressPercentage: CGFloat, changeCurrentIndex: Bool, animated: Bool) -> Void in
guard changeCurrentIndex == true else { return }
oldCell?.label.textColor = UIColor(white: 1, alpha: 0.6)
newCell?.label.textColor = .white
if animated {
UIView.animate(withDuration: 0.1, animations: { () -> Void in
newCell?.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
oldCell?.transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
})
}
else {
} else {
newCell?.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
oldCell?.transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
}
}
}
// MARK: - PagerTabStripDataSource
override func viewControllers(for pagerTabStripController: PagerTabStripViewController) -> [UIViewController] {
let child_1 = TableChildExampleViewController(style: .plain, itemInfo: "Table View")
let child_2 = ChildExampleViewController(itemInfo: "View")
@ -68,35 +67,34 @@ class NavButtonBarExampleViewController: ButtonBarPagerTabStripViewController {
let child_6 = ChildExampleViewController(itemInfo: "View 2")
let child_7 = TableChildExampleViewController(style: .grouped, itemInfo: "Table View 4")
let child_8 = ChildExampleViewController(itemInfo: "View 3")
guard isReload else {
return [child_1, child_2, child_3, child_4, child_5, child_6, child_7, child_8]
}
var childViewControllers = [child_1, child_2, child_3, child_4, child_6, child_7, child_8]
for (index, _) in childViewControllers.enumerated(){
for index in childViewControllers.indices {
let nElements = childViewControllers.count - index
let n = (Int(arc4random()) % nElements) + index
if n != index{
if n != index {
swap(&childViewControllers[index], &childViewControllers[n])
}
}
let nItems = 1 + (arc4random() % 8)
return Array(childViewControllers.prefix(Int(nItems)))
}
override func reloadPagerTabStripView() {
isReload = true
if arc4random() % 2 == 0 {
pagerBehaviour = .progressive(skipIntermediateViewControllers: arc4random() % 2 == 0, elasticIndicatorLimit: arc4random() % 2 == 0 )
}
else {
} else {
pagerBehaviour = .common(skipIntermediateViewControllers: arc4random() % 2 == 0)
}
super.reloadPagerTabStripView()
}
override func configureCell(_ cell: ButtonBarViewCell, indicatorInfo: IndicatorInfo) {
super.configureCell(cell, indicatorInfo: indicatorInfo)
cell.backgroundColor = .clear

View File

@ -44,12 +44,12 @@ class ReloadExampleViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let _ = navigationController {
if navigationController != nil {
navigationItem.titleView = bigLabel
bigLabel.sizeToFit()
}
if let pagerViewController = childViewControllers.filter( { $0 is PagerTabStripViewController } ).first as? PagerTabStripViewController {
if let pagerViewController = childViewControllers.first as? PagerTabStripViewController {
updateTitle(of: pagerViewController)
}
}
@ -61,11 +61,10 @@ class ReloadExampleViewController: UIViewController {
}
child.reloadPagerTabStripView()
updateTitle(of: child)
break;
break
}
}
@IBAction func closeTapped(_ sender: UIButton) {
dismiss(animated: true, completion: nil)
}
@ -81,7 +80,7 @@ class ReloadExampleViewController: UIViewController {
navigationItem.titleView?.sizeToFit()
}
override var preferredStatusBarStyle : UIStatusBarStyle {
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
}

View File

@ -26,41 +26,41 @@ import Foundation
import XLPagerTabStrip
class SegmentedExampleViewController: SegmentedPagerTabStripViewController {
var isReload = false
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
// change segmented style
settings.style.segmentedControlColor = .white
}
// MARK: - PagerTabStripDataSource
override func viewControllers(for pagerTabStripController: PagerTabStripViewController) -> [UIViewController] {
let child_1 = TableChildExampleViewController(style: .plain, itemInfo: "Table View")
let child_2 = ChildExampleViewController(itemInfo: "View")
let child_3 = TableChildExampleViewController(style: .grouped, itemInfo: "Table View 2")
let child_4 = ChildExampleViewController(itemInfo: "View 2")
guard isReload else {
return [child_1, child_2, child_3, child_4]
}
var childViewControllers = [child_1, child_2, child_3, child_4]
let count = childViewControllers.count
for (index, _) in childViewControllers.enumerated(){
for index in childViewControllers.indices {
let nElements = count - index
let n = (Int(arc4random()) % nElements) + index
if n != index{
if n != index {
swap(&childViewControllers[index], &childViewControllers[n])
}
}
let nItems = 1 + (arc4random() % 4)
return Array(childViewControllers.prefix(Int(nItems)))
}
@IBAction func reloadTapped(_ sender: UIBarButtonItem) {
isReload = true
pagerBehaviour = .common(skipIntermediateViewControllers: arc4random() % 2 == 0)

View File

@ -26,12 +26,12 @@ import Foundation
import XLPagerTabStrip
class SpotifyExampleViewController: ButtonBarPagerTabStripViewController {
@IBOutlet weak var shadowView: UIView!
let graySpotifyColor = UIColor(red: 21/255.0, green: 21/255.0, blue: 24/255.0, alpha: 1.0)
let darkGraySpotifyColor = UIColor(red: 19/255.0, green: 20/255.0, blue: 20/255.0, alpha: 1.0)
override func viewDidLoad() {
// change selected bar color
settings.style.buttonBarBackgroundColor = graySpotifyColor
@ -42,10 +42,10 @@ class SpotifyExampleViewController: ButtonBarPagerTabStripViewController {
settings.style.buttonBarMinimumLineSpacing = 0
settings.style.buttonBarItemTitleColor = .black
settings.style.buttonBarItemsShouldFillAvailableWidth = true
settings.style.buttonBarLeftContentInset = 20
settings.style.buttonBarRightContentInset = 20
changeCurrentIndexProgressive = { (oldCell: ButtonBarViewCell?, newCell: ButtonBarViewCell?, progressPercentage: CGFloat, changeCurrentIndex: Bool, animated: Bool) -> Void in
guard changeCurrentIndex == true else { return }
oldCell?.label.textColor = UIColor(red: 138/255.0, green: 138/255.0, blue: 144/255.0, alpha: 1.0)
@ -53,9 +53,9 @@ class SpotifyExampleViewController: ButtonBarPagerTabStripViewController {
}
super.viewDidLoad()
}
// MARK: - PagerTabStripDataSource
override func viewControllers(for pagerTabStripController: PagerTabStripViewController) -> [UIViewController] {
let child_1 = TableChildExampleViewController(style: .plain, itemInfo: IndicatorInfo(title: "FRIENDS"))
child_1.blackTheme = true
@ -63,15 +63,10 @@ class SpotifyExampleViewController: ButtonBarPagerTabStripViewController {
child_2.blackTheme = true
return [child_1, child_2]
}
// MARK: - Actions
@IBAction func closeAction(_ sender: UIButton) {
dismiss(animated: true, completion: nil)
}
}

View File

@ -27,9 +27,9 @@ import XLPagerTabStrip
class TwitterExampleViewController: TwitterPagerTabStripViewController {
var isReload = false
override func viewControllers(for pagerTabStripController: PagerTabStripViewController) -> [UIViewController] {
let child_1 = TableChildExampleViewController(style: .plain, itemInfo: "TableView")
let child_2 = ChildExampleViewController(itemInfo: "View")
let child_3 = TableChildExampleViewController(style: .grouped, itemInfo: "TableView 2")
@ -38,24 +38,24 @@ class TwitterExampleViewController: TwitterPagerTabStripViewController {
let child_6 = ChildExampleViewController(itemInfo: "View 3")
let child_7 = TableChildExampleViewController(style: .grouped, itemInfo: "TableView 4")
let child_8 = ChildExampleViewController(itemInfo: "View 4")
guard isReload else {
return [child_1, child_2, child_3, child_4, child_5, child_6, child_7, child_8]
}
var childViewControllers = [child_1, child_2, child_3, child_4, child_6, child_7, child_8]
for (index, _) in childViewControllers.enumerated(){
for index in childViewControllers.indices {
let nElements = childViewControllers.count - index
let n = (Int(arc4random()) % nElements) + index
if n != index{
if n != index {
swap(&childViewControllers[index], &childViewControllers[n])
}
}
let nItems = 1 + (arc4random() % 8)
return Array(childViewControllers.prefix(Int(nItems)))
}
@IBAction func reloadTapped(_ sender: AnyObject) {
isReload = true
reloadPagerTabStripView()

View File

@ -30,19 +30,18 @@ class YoutubeExampleViewController: BaseButtonBarPagerTabStripViewController<You
let redColor = UIColor(red: 221/255.0, green: 0/255.0, blue: 19/255.0, alpha: 1.0)
let unselectedIconColor = UIColor(red: 73/255.0, green: 8/255.0, blue: 10/255.0, alpha: 1.0)
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
buttonBarItemSpec = ButtonBarItemSpec.nibFile(nibName: "YoutubeIconCell", bundle: Bundle(for: YoutubeIconCell.self), width: { (cell: IndicatorInfo) -> CGFloat in
buttonBarItemSpec = ButtonBarItemSpec.nibFile(nibName: "YoutubeIconCell", bundle: Bundle(for: YoutubeIconCell.self), width: { _ in
return 55.0
})
}
override func viewDidLoad() {
// change selected bar color
settings.style.buttonBarBackgroundColor = redColor
@ -54,53 +53,44 @@ class YoutubeExampleViewController: BaseButtonBarPagerTabStripViewController<You
settings.style.buttonBarItemsShouldFillAvailableWidth = true
settings.style.buttonBarLeftContentInset = 0
settings.style.buttonBarRightContentInset = 0
changeCurrentIndexProgressive = { [weak self] (oldCell: YoutubeIconCell?, newCell: YoutubeIconCell?, progressPercentage: CGFloat, changeCurrentIndex: Bool, animated: Bool) -> Void in
guard changeCurrentIndex == true else { return }
oldCell?.iconImage.tintColor = self?.unselectedIconColor
newCell?.iconImage.tintColor = .white
}
super.viewDidLoad()
navigationController?.navigationBar.shadowImage = UIImage()
navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
}
// MARK: - PagerTabStripDataSource
override func viewControllers(for pagerTabStripController: PagerTabStripViewController) -> [UIViewController] {
let child_1 = TableChildExampleViewController(style: .plain, itemInfo: IndicatorInfo(title: " HOME", image: UIImage(named: "home")))
let child_2 = TableChildExampleViewController(style: .plain, itemInfo: IndicatorInfo(title: " TRENDING", image: UIImage(named: "trending")))
let child_3 = ChildExampleViewController(itemInfo: IndicatorInfo(title: " ACCOUNT", image: UIImage(named: "profile")))
return [child_1, child_2, child_3]
}
override func configure(cell: YoutubeIconCell, for indicatorInfo: IndicatorInfo) {
cell.iconImage.image = indicatorInfo.image?.withRenderingMode(.alwaysTemplate)
}
override func updateIndicator(for viewController: PagerTabStripViewController, fromIndex: Int, toIndex: Int, withProgressPercentage progressPercentage: CGFloat, indexWasChanged: Bool) {
super.updateIndicator(for: viewController, fromIndex: fromIndex, toIndex: toIndex, withProgressPercentage: progressPercentage, indexWasChanged: indexWasChanged)
if indexWasChanged && toIndex > -1 && toIndex < viewControllers.count {
let child = viewControllers[toIndex] as! IndicatorInfoProvider
let child = viewControllers[toIndex] as! IndicatorInfoProvider // swiftlint:disable:this force_cast
UIView.performWithoutAnimation({ [weak self] () -> Void in
guard let me = self else { return }
me.navigationItem.leftBarButtonItem?.title = child.indicatorInfo(for: me).title
})
}
}
// MARK: - Actions
@IBAction func closeAction(_ sender: UIButton) {
dismiss(animated: true, completion: nil)
}
}

View File

@ -25,9 +25,8 @@
import Foundation
import UIKit
class YoutubeIconCell: UICollectionViewCell {
class YoutubeIconCell : UICollectionViewCell {
@IBOutlet weak var iconImage: UIImageView!
}

View File

@ -8,12 +8,12 @@
import XCTest
class ExampleUITests: XCTestCase {
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
// In UI tests it is usually best to stop immediately when a failure occurs.
continueAfterFailure = false
// UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
@ -21,15 +21,15 @@ class ExampleUITests: XCTestCase {
// In UI tests its important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testExample() {
// Use recording to get started writing UI tests.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
}

View File

@ -10,4 +10,4 @@
import UIKit
import XLPagerTabStrip
var str = "Hello, playground"
var helloWorld = "Hello, playground"

View File

@ -26,34 +26,34 @@ import Foundation
import UIKit
public struct BarPagerTabStripSettings {
public struct Style {
public var barBackgroundColor: UIColor?
public var selectedBarBackgroundColor: UIColor?
public var barHeight: CGFloat = 5 // barHeight is ony set up when the bar is created programatically and not using storyboards or xib files.
}
public var style = Style()
}
open class BarPagerTabStripViewController: PagerTabStripViewController, PagerTabStripDataSource, PagerTabStripIsProgressiveDelegate {
public var settings = BarPagerTabStripSettings()
@IBOutlet weak public var barView: BarView!
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
delegate = self
datasource = self
}
public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
delegate = self
datasource = self
}
open override func viewDidLoad() {
super.viewDidLoad()
barView = barView ?? {
@ -63,11 +63,11 @@ open class BarPagerTabStripViewController: PagerTabStripViewController, PagerTab
barView.selectedBar.backgroundColor = .white
return barView
}()
barView.backgroundColor = settings.style.barBackgroundColor ?? barView.backgroundColor
barView.selectedBar.backgroundColor = settings.style.selectedBarBackgroundColor ?? barView.selectedBar.backgroundColor
}
open override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if barView.superview == nil {
@ -76,15 +76,15 @@ open class BarPagerTabStripViewController: PagerTabStripViewController, PagerTab
barView.optionsCount = viewControllers.count
barView.moveTo(index: currentIndex, animated: false)
}
open override func reloadPagerTabStripView() {
super.reloadPagerTabStripView()
barView.optionsCount = viewControllers.count
if isViewLoaded{
if isViewLoaded {
barView.moveTo(index: currentIndex, animated: false)
}
}
// MARK: - PagerTabStripDelegate
open func updateIndicator(for viewController: PagerTabStripViewController, fromIndex: Int, toIndex: Int, withProgressPercentage progressPercentage: CGFloat, indexWasChanged: Bool) {

View File

@ -25,12 +25,12 @@
import Foundation
open class BarView: UIView {
open lazy var selectedBar: UIView = { [unowned self] in
let selectedBar = UIView(frame: CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height))
return selectedBar
}()
var optionsCount = 1 {
willSet(newOptionsCount) {
if newOptionsCount <= selectedIndex {
@ -39,20 +39,19 @@ open class BarView: UIView {
}
}
var selectedIndex = 0
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
addSubview(selectedBar)
}
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(selectedBar)
}
// MARK: - Helpers
private func updateSelectedBarPosition(with animation: Bool) {
var frame = selectedBar.frame
frame.size.width = self.frame.size.width / CGFloat(optionsCount)
@ -61,20 +60,19 @@ open class BarView: UIView {
UIView.animate(withDuration: 0.3, animations: { [weak self] in
self?.selectedBar.frame = frame
})
}
else{
} else {
selectedBar.frame = frame
}
}
open func moveTo(index: Int, animated: Bool) {
selectedIndex = index
updateSelectedBarPosition(with: animated)
}
open func move(fromIndex: Int, toIndex: Int, progressPercentage: CGFloat) {
selectedIndex = (progressPercentage > 0.5) ? toIndex : fromIndex
var newFrame = selectedBar.frame
newFrame.size.width = frame.size.width / CGFloat(optionsCount)
var fromFrame = newFrame
@ -85,7 +83,7 @@ open class BarView: UIView {
targetFrame.origin.x += (toFrame.origin.x - targetFrame.origin.x) * CGFloat(progressPercentage)
selectedBar.frame = targetFrame
}
open override func layoutSubviews() {
super.layoutSubviews()
updateSelectedBarPosition(with: false)

View File

@ -24,14 +24,13 @@
import Foundation
open class BaseButtonBarPagerTabStripViewController<ButtonBarCellType : UICollectionViewCell>: PagerTabStripViewController, PagerTabStripDataSource, PagerTabStripIsProgressiveDelegate, UICollectionViewDelegate, UICollectionViewDataSource {
open class BaseButtonBarPagerTabStripViewController<ButtonBarCellType: UICollectionViewCell>: PagerTabStripViewController, PagerTabStripDataSource, PagerTabStripIsProgressiveDelegate, UICollectionViewDelegate, UICollectionViewDataSource {
public var settings = ButtonBarPagerTabStripSettings()
public var buttonBarItemSpec: ButtonBarItemSpec<ButtonBarCellType>!
public var changeCurrentIndex: ((_ oldCell: ButtonBarCellType?, _ newCell: ButtonBarCellType?, _ animated: Bool) -> Void)?
public var changeCurrentIndexProgressive: ((_ oldCell: ButtonBarCellType?, _ newCell: ButtonBarCellType?, _ progressPercentage: CGFloat, _ changeCurrentIndex: Bool, _ animated: Bool) -> Void)?
@IBOutlet public weak var buttonBarView: ButtonBarView!
lazy private var cachedCellWidths: [CGFloat]? = { [unowned self] in
@ -55,7 +54,7 @@ open class BaseButtonBarPagerTabStripViewController<ButtonBarCellType : UICollec
let buttonBarViewAux = buttonBarView ?? {
let flowLayout = UICollectionViewFlowLayout()
flowLayout.scrollDirection = .horizontal
flowLayout.sectionInset = UIEdgeInsetsMake(0, settings.style.buttonBarLeftContentInset ?? 35, 0, settings.style.buttonBarRightContentInset ?? 35)
flowLayout.sectionInset = UIEdgeInsets(top: 0, left: settings.style.buttonBarLeftContentInset ?? 35, bottom: 0, right: settings.style.buttonBarRightContentInset ?? 35)
let buttonBarHeight = settings.style.buttonBarHeight ?? 44
let buttonBar = ButtonBarView(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: buttonBarHeight), collectionViewLayout: flowLayout)
buttonBar.backgroundColor = .orange
@ -79,12 +78,12 @@ open class BaseButtonBarPagerTabStripViewController<ButtonBarCellType : UICollec
buttonBarView.dataSource = self
}
buttonBarView.scrollsToTop = false
let flowLayout = buttonBarView.collectionViewLayout as! UICollectionViewFlowLayout
let flowLayout = buttonBarView.collectionViewLayout as! UICollectionViewFlowLayout // swiftlint:disable:this force_cast
flowLayout.scrollDirection = .horizontal
flowLayout.minimumInteritemSpacing = settings.style.buttonBarMinimumInteritemSpacing ?? flowLayout.minimumInteritemSpacing
flowLayout.minimumLineSpacing = settings.style.buttonBarMinimumLineSpacing ?? flowLayout.minimumLineSpacing
let sectionInset = flowLayout.sectionInset
flowLayout.sectionInset = UIEdgeInsetsMake(sectionInset.top, settings.style.buttonBarLeftContentInset ?? sectionInset.left, sectionInset.bottom, settings.style.buttonBarRightContentInset ?? sectionInset.right)
flowLayout.sectionInset = UIEdgeInsets(top: sectionInset.top, left: settings.style.buttonBarLeftContentInset ?? sectionInset.left, bottom: sectionInset.bottom, right: settings.style.buttonBarRightContentInset ?? sectionInset.right)
buttonBarView.showsHorizontalScrollIndicator = false
buttonBarView.backgroundColor = settings.style.buttonBarBackgroundColor ?? buttonBarView.backgroundColor
buttonBarView.selectedBar.backgroundColor = settings.style.selectedBarBackgroundColor
@ -154,16 +153,14 @@ open class BaseButtonBarPagerTabStripViewController<ButtonBarCellType : UICollec
var numberOfLargeCells = 0
var totalWidthOfLargeCells: CGFloat = 0
for minimumCellWidthValue in minimumCellWidths {
if minimumCellWidthValue > suggestedStretchedCellWidth {
totalWidthOfLargeCells += minimumCellWidthValue
numberOfLargeCells += 1
}
for minimumCellWidthValue in minimumCellWidths where minimumCellWidthValue > suggestedStretchedCellWidth {
totalWidthOfLargeCells += minimumCellWidthValue
numberOfLargeCells += 1
}
guard numberOfLargeCells > previousNumberOfLargeCells else { return suggestedStretchedCellWidth }
let flowLayout = buttonBarView.collectionViewLayout as! UICollectionViewFlowLayout
let flowLayout = buttonBarView.collectionViewLayout as! UICollectionViewFlowLayout // swiftlint:disable:this force_cast
let collectionViewAvailiableWidth = buttonBarView.frame.size.width - flowLayout.sectionInset.left - flowLayout.sectionInset.right
let numberOfCells = minimumCellWidths.count
let cellSpacingTotal = CGFloat(numberOfCells - 1) * flowLayout.minimumLineSpacing
@ -216,8 +213,7 @@ open class BaseButtonBarPagerTabStripViewController<ButtonBarCellType : UICollec
if let changeCurrentIndexProgressive = changeCurrentIndexProgressive {
changeCurrentIndexProgressive(oldCell, newCell, 1, true, true)
}
}
else {
} else {
if let changeCurrentIndex = changeCurrentIndex {
changeCurrentIndex(oldCell, newCell, true)
}
@ -235,7 +231,7 @@ open class BaseButtonBarPagerTabStripViewController<ButtonBarCellType : UICollec
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as? ButtonBarCellType else {
fatalError("UICollectionViewCell should be or extend from ButtonBarViewCell")
}
let childController = viewControllers[indexPath.item] as! IndicatorInfoProvider
let childController = viewControllers[indexPath.item] as! IndicatorInfoProvider // swiftlint:disable:this force_cast
let indicatorInfo = childController.indicatorInfo(for: self)
configure(cell: cell, for: indicatorInfo)
@ -244,8 +240,7 @@ open class BaseButtonBarPagerTabStripViewController<ButtonBarCellType : UICollec
if let changeCurrentIndexProgressive = changeCurrentIndexProgressive {
changeCurrentIndexProgressive(currentIndex == indexPath.item ? nil : cell, currentIndex == indexPath.item ? cell : nil, 1, true, false)
}
}
else {
} else {
if let changeCurrentIndex = changeCurrentIndex {
changeCurrentIndex(currentIndex == indexPath.item ? nil : cell, currentIndex == indexPath.item ? cell : nil, false)
}
@ -263,19 +258,19 @@ open class BaseButtonBarPagerTabStripViewController<ButtonBarCellType : UICollec
shouldUpdateButtonBarView = true
}
open func configure(cell: ButtonBarCellType, for indicatorInfo: IndicatorInfo){
open func configure(cell: ButtonBarCellType, for indicatorInfo: IndicatorInfo) {
fatalError("You must override this method to set up ButtonBarView cell accordingly")
}
private func calculateWidths() -> [CGFloat] {
let flowLayout = buttonBarView.collectionViewLayout as! UICollectionViewFlowLayout
let flowLayout = buttonBarView.collectionViewLayout as! UICollectionViewFlowLayout // swiftlint:disable:this force_cast
let numberOfCells = viewControllers.count
var minimumCellWidths = [CGFloat]()
var collectionViewContentWidth: CGFloat = 0
for viewController in viewControllers {
let childController = viewController as! IndicatorInfoProvider
let childController = viewController as! IndicatorInfoProvider // swiftlint:disable:this force_cast
let indicatorInfo = childController.indicatorInfo(for: self)
switch buttonBarItemSpec! {
case .cellClass(let widthCallback):
@ -296,8 +291,7 @@ open class BaseButtonBarPagerTabStripViewController<ButtonBarCellType : UICollec
if !settings.style.buttonBarItemsShouldFillAvailableWidth || collectionViewAvailableVisibleWidth < collectionViewContentWidth {
return minimumCellWidths
}
else {
} else {
let stretchedCellWidthIfAllEqual = (collectionViewAvailableVisibleWidth - cellSpacingTotal) / CGFloat(numberOfCells)
let generalMinimumCellWidth = calculateStretchedCellWidths(minimumCellWidths, suggestedStretchedCellWidth: stretchedCellWidthIfAllEqual, previousNumberOfLargeCells: 0)
var stretchedCellWidths = [CGFloat]()
@ -314,7 +308,6 @@ open class BaseButtonBarPagerTabStripViewController<ButtonBarCellType : UICollec
private var shouldUpdateButtonBarView = true
}
open class ExampleBaseButtonBarPagerTabStripViewController: BaseButtonBarPagerTabStripViewController<ButtonBarViewCell> {
public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
@ -327,8 +320,8 @@ open class ExampleBaseButtonBarPagerTabStripViewController: BaseButtonBarPagerTa
initialize()
}
open func initialize(){
buttonBarItemSpec = .nibFile(nibName: "ButtonCell", bundle: Bundle(for: ButtonBarViewCell.self), width:{ [weak self] (childItemInfo) -> CGFloat in
open func initialize() {
buttonBarItemSpec = .nibFile(nibName: "ButtonCell", bundle: Bundle(for: ButtonBarViewCell.self), width: { [weak self] (childItemInfo) -> CGFloat in
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = self?.settings.style.buttonBarItemFont ?? label.font
@ -338,7 +331,7 @@ open class ExampleBaseButtonBarPagerTabStripViewController: BaseButtonBarPagerTa
})
}
open override func configure(cell: ButtonBarViewCell, for indicatorInfo: IndicatorInfo){
open override func configure(cell: ButtonBarViewCell, for indicatorInfo: IndicatorInfo) {
cell.label.text = indicatorInfo.title
if let image = indicatorInfo.image {
cell.imageView.image = image

View File

@ -25,10 +25,10 @@
import Foundation
public enum ButtonBarItemSpec<CellType: UICollectionViewCell> {
case nibFile(nibName: String, bundle: Bundle?, width:((IndicatorInfo)-> CGFloat))
case cellClass(width:((IndicatorInfo)-> CGFloat))
public var weight: ((IndicatorInfo) -> CGFloat) {
switch self {
case .cellClass(let widthCallback):
@ -40,7 +40,7 @@ public enum ButtonBarItemSpec<CellType: UICollectionViewCell> {
}
public struct ButtonBarPagerTabStripSettings {
public struct Style {
public var buttonBarBackgroundColor: UIColor?
public var buttonBarMinimumInteritemSpacing: CGFloat?
@ -51,7 +51,7 @@ public struct ButtonBarPagerTabStripSettings {
public var selectedBarBackgroundColor = UIColor.black
public var selectedBarHeight: CGFloat = 5
public var selectedBarVerticalAlignment: SelectedBarVerticalAlignment = .bottom
public var buttonBarItemBackgroundColor: UIColor?
public var buttonBarItemFont = UIFont.systemFont(ofSize: 18)
public var buttonBarItemLeftRightMargin: CGFloat = 8
@ -68,25 +68,25 @@ public struct ButtonBarPagerTabStripSettings {
// only used if button bar is created programaticaly and not using storyboards or nib files
public var buttonBarHeight: CGFloat?
}
public var style = Style()
}
open class ButtonBarPagerTabStripViewController: PagerTabStripViewController, PagerTabStripDataSource, PagerTabStripIsProgressiveDelegate, UICollectionViewDelegate, UICollectionViewDataSource {
public var settings = ButtonBarPagerTabStripSettings()
public var buttonBarItemSpec: ButtonBarItemSpec<ButtonBarViewCell>!
public var changeCurrentIndex: ((_ oldCell: ButtonBarViewCell?, _ newCell: ButtonBarViewCell?, _ animated: Bool) -> Void)?
public var changeCurrentIndexProgressive: ((_ oldCell: ButtonBarViewCell?, _ newCell: ButtonBarViewCell?, _ progressPercentage: CGFloat, _ changeCurrentIndex: Bool, _ animated: Bool) -> Void)?
@IBOutlet public weak var buttonBarView: ButtonBarView!
lazy private var cachedCellWidths: [CGFloat]? = { [unowned self] in
return self.calculateWidths()
}()
override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
delegate = self
@ -98,10 +98,10 @@ open class ButtonBarPagerTabStripViewController: PagerTabStripViewController, Pa
delegate = self
datasource = self
}
open override func viewDidLoad() {
super.viewDidLoad()
buttonBarItemSpec = .nibFile(nibName: "ButtonCell", bundle: Bundle(for: ButtonBarViewCell.self), width:{ [weak self] (childItemInfo) -> CGFloat in
buttonBarItemSpec = .nibFile(nibName: "ButtonCell", bundle: Bundle(for: ButtonBarViewCell.self), width: { [weak self] (childItemInfo) -> CGFloat in
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = self?.settings.style.buttonBarItemFont
@ -109,8 +109,7 @@ open class ButtonBarPagerTabStripViewController: PagerTabStripViewController, Pa
let labelSize = label.intrinsicContentSize
return labelSize.width + (self?.settings.style.buttonBarItemLeftRightMargin ?? 8) * 2
})
let buttonBarViewAux = buttonBarView ?? {
let flowLayout = UICollectionViewFlowLayout()
flowLayout.scrollDirection = .horizontal
@ -126,7 +125,7 @@ open class ButtonBarPagerTabStripViewController: PagerTabStripViewController, Pa
return buttonBar
}()
buttonBarView = buttonBarViewAux
if buttonBarView.superview == nil {
view.addSubview(buttonBarView)
}
@ -137,20 +136,20 @@ open class ButtonBarPagerTabStripViewController: PagerTabStripViewController, Pa
buttonBarView.dataSource = self
}
buttonBarView.scrollsToTop = false
let flowLayout = buttonBarView.collectionViewLayout as! UICollectionViewFlowLayout
let flowLayout = buttonBarView.collectionViewLayout as! UICollectionViewFlowLayout // swiftlint:disable:this force_cast
flowLayout.scrollDirection = .horizontal
flowLayout.minimumInteritemSpacing = settings.style.buttonBarMinimumInteritemSpacing ?? flowLayout.minimumInteritemSpacing
flowLayout.minimumLineSpacing = settings.style.buttonBarMinimumLineSpacing ?? flowLayout.minimumLineSpacing
let sectionInset = flowLayout.sectionInset
flowLayout.sectionInset = UIEdgeInsetsMake(sectionInset.top, settings.style.buttonBarLeftContentInset ?? sectionInset.left, sectionInset.bottom, settings.style.buttonBarRightContentInset ?? sectionInset.right)
flowLayout.sectionInset = UIEdgeInsets(top: sectionInset.top, left: settings.style.buttonBarLeftContentInset ?? sectionInset.left, bottom: sectionInset.bottom, right: settings.style.buttonBarRightContentInset ?? sectionInset.right)
buttonBarView.showsHorizontalScrollIndicator = false
buttonBarView.backgroundColor = settings.style.buttonBarBackgroundColor ?? buttonBarView.backgroundColor
buttonBarView.selectedBar.backgroundColor = settings.style.selectedBarBackgroundColor
buttonBarView.selectedBarHeight = settings.style.selectedBarHeight
buttonBarView.selectedBarVerticalAlignment = settings.style.selectedBarVerticalAlignment
// register button bar item cell
switch buttonBarItemSpec! {
case .nibFile(let nibName, let bundle, _):
@ -160,17 +159,17 @@ open class ButtonBarPagerTabStripViewController: PagerTabStripViewController, Pa
}
//-
}
open override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
buttonBarView.layoutIfNeeded()
}
open override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
guard isViewAppearing || isViewRotating else { return }
// Force the UICollectionViewFlowLayout to get laid out again with the new size if
// a) The view is appearing. This ensures that
// collectionView:layout:sizeForItemAtIndexPath: is called for a second time
@ -188,9 +187,9 @@ open class ButtonBarPagerTabStripViewController: PagerTabStripViewController, Pa
// tab/cell may end up either skewed or off screen after a rotation otherwise)
buttonBarView.moveTo(index: currentIndex, animated: false, swipeDirection: .none, pagerScroll: .scrollOnlyIfOutOfScreen)
}
// MARK: - Public Methods
open override func reloadPagerTabStripView() {
super.reloadPagerTabStripView()
guard isViewLoaded else { return }
@ -198,33 +197,33 @@ open class ButtonBarPagerTabStripViewController: PagerTabStripViewController, Pa
cachedCellWidths = calculateWidths()
buttonBarView.moveTo(index: currentIndex, animated: false, swipeDirection: .none, pagerScroll: .yes)
}
open func calculateStretchedCellWidths(_ minimumCellWidths: [CGFloat], suggestedStretchedCellWidth: CGFloat, previousNumberOfLargeCells: Int) -> CGFloat {
var numberOfLargeCells = 0
var totalWidthOfLargeCells: CGFloat = 0
for minimumCellWidthValue in minimumCellWidths where minimumCellWidthValue > suggestedStretchedCellWidth {
totalWidthOfLargeCells += minimumCellWidthValue
numberOfLargeCells += 1
}
guard numberOfLargeCells > previousNumberOfLargeCells else { return suggestedStretchedCellWidth }
let flowLayout = buttonBarView.collectionViewLayout as! UICollectionViewFlowLayout
let flowLayout = buttonBarView.collectionViewLayout as! UICollectionViewFlowLayout // swiftlint:disable:this force_cast
let collectionViewAvailiableWidth = buttonBarView.frame.size.width - flowLayout.sectionInset.left - flowLayout.sectionInset.right
let numberOfCells = minimumCellWidths.count
let cellSpacingTotal = CGFloat(numberOfCells - 1) * flowLayout.minimumLineSpacing
let numberOfSmallCells = numberOfCells - numberOfLargeCells
let newSuggestedStretchedCellWidth = (collectionViewAvailiableWidth - totalWidthOfLargeCells - cellSpacingTotal) / CGFloat(numberOfSmallCells)
return calculateStretchedCellWidths(minimumCellWidths, suggestedStretchedCellWidth: newSuggestedStretchedCellWidth, previousNumberOfLargeCells: numberOfLargeCells)
}
open func updateIndicator(for viewController: PagerTabStripViewController, fromIndex: Int, toIndex: Int) {
guard shouldUpdateButtonBarView else { return }
buttonBarView.moveTo(index: toIndex, animated: false, swipeDirection: toIndex < fromIndex ? .right : .left, pagerScroll: .yes)
if let changeCurrentIndex = changeCurrentIndex {
let oldIndexPath = IndexPath(item: currentIndex != fromIndex ? fromIndex : toIndex, section: 0)
let newIndexPath = IndexPath(item: currentIndex, section: 0)
@ -266,21 +265,21 @@ open class ButtonBarPagerTabStripViewController: PagerTabStripViewController, Pa
return cells
}
// MARK: - UICollectionViewDelegateFlowLayout
// MARK: - UICollectionViewDelegateFlowLayut
open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize {
guard let cellWidthValue = cachedCellWidths?[indexPath.row] else {
fatalError("cachedCellWidths for \(indexPath.row) must not be nil")
}
return CGSize(width: cellWidthValue, height: collectionView.frame.size.height)
}
open func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard indexPath.item != currentIndex else { return }
buttonBarView.moveTo(index: indexPath.item, animated: true, swipeDirection: .none, pagerScroll: .yes)
shouldUpdateButtonBarView = false
let oldIndexPath = IndexPath(item: currentIndex, section: 0)
let newIndexPath = IndexPath(item: indexPath.item, section: 0)
@ -290,21 +289,20 @@ open class ButtonBarPagerTabStripViewController: PagerTabStripViewController, Pa
if let changeCurrentIndexProgressive = changeCurrentIndexProgressive {
changeCurrentIndexProgressive(cells.first!, cells.last!, 1, true, true)
}
}
else {
} else {
if let changeCurrentIndex = changeCurrentIndex {
changeCurrentIndex(cells.first!, cells.last!, true)
}
}
moveToViewController(at: indexPath.item)
}
// MARK: - UICollectionViewDataSource
open func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return viewControllers.count
}
open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as? ButtonBarViewCell else {
fatalError("UICollectionViewCell should be or extend from ButtonBarViewCell")
@ -312,9 +310,9 @@ open class ButtonBarPagerTabStripViewController: PagerTabStripViewController, Pa
collectionViewDidLoad = true
let childController = viewControllers[indexPath.item] as! IndicatorInfoProvider
let childController = viewControllers[indexPath.item] as! IndicatorInfoProvider // swiftlint:disable:this force_cast
let indicatorInfo = childController.indicatorInfo(for: self)
cell.label.text = indicatorInfo.title
cell.label.font = settings.style.buttonBarItemFont
cell.label.textColor = settings.style.buttonBarItemTitleColor ?? cell.label.textColor
@ -328,41 +326,40 @@ open class ButtonBarPagerTabStripViewController: PagerTabStripViewController, Pa
}
configureCell(cell, indicatorInfo: indicatorInfo)
if pagerBehaviour.isProgressiveIndicator {
if let changeCurrentIndexProgressive = changeCurrentIndexProgressive {
changeCurrentIndexProgressive(currentIndex == indexPath.item ? nil : cell, currentIndex == indexPath.item ? cell : nil, 1, true, false)
}
}
else {
} else {
if let changeCurrentIndex = changeCurrentIndex {
changeCurrentIndex(currentIndex == indexPath.item ? nil : cell, currentIndex == indexPath.item ? cell : nil, false)
}
}
return cell
}
// MARK: - UIScrollViewDelegate
open override func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
super.scrollViewDidEndScrollingAnimation(scrollView)
guard scrollView == containerView else { return }
shouldUpdateButtonBarView = true
}
open func configureCell(_ cell: ButtonBarViewCell, indicatorInfo: IndicatorInfo){
open func configureCell(_ cell: ButtonBarViewCell, indicatorInfo: IndicatorInfo) {
}
private func calculateWidths() -> [CGFloat] {
let flowLayout = buttonBarView.collectionViewLayout as! UICollectionViewFlowLayout
let flowLayout = buttonBarView.collectionViewLayout as! UICollectionViewFlowLayout // swiftlint:disable:this force_cast
let numberOfCells = viewControllers.count
var minimumCellWidths = [CGFloat]()
var collectionViewContentWidth: CGFloat = 0
for viewController in viewControllers {
let childController = viewController as! IndicatorInfoProvider
let childController = viewController as! IndicatorInfoProvider // swiftlint:disable:this force_cast
let indicatorInfo = childController.indicatorInfo(for: self)
switch buttonBarItemSpec! {
case .cellClass(let widthCallback):
@ -375,30 +372,29 @@ open class ButtonBarPagerTabStripViewController: PagerTabStripViewController, Pa
collectionViewContentWidth += width
}
}
let cellSpacingTotal = CGFloat(numberOfCells - 1) * flowLayout.minimumLineSpacing
collectionViewContentWidth += cellSpacingTotal
let collectionViewAvailableVisibleWidth = buttonBarView.frame.size.width - flowLayout.sectionInset.left - flowLayout.sectionInset.right
if !settings.style.buttonBarItemsShouldFillAvailableWidth || collectionViewAvailableVisibleWidth < collectionViewContentWidth {
return minimumCellWidths
}
else {
} else {
let stretchedCellWidthIfAllEqual = (collectionViewAvailableVisibleWidth - cellSpacingTotal) / CGFloat(numberOfCells)
let generalMinimumCellWidth = calculateStretchedCellWidths(minimumCellWidths, suggestedStretchedCellWidth: stretchedCellWidthIfAllEqual, previousNumberOfLargeCells: 0)
var stretchedCellWidths = [CGFloat]()
for minimumCellWidthValue in minimumCellWidths {
let cellWidth = (minimumCellWidthValue > generalMinimumCellWidth) ? minimumCellWidthValue : generalMinimumCellWidth
stretchedCellWidths.append(cellWidth)
}
return stretchedCellWidths
}
}
private var shouldUpdateButtonBarView = true
private var collectionViewDidLoad = false
}

View File

@ -44,13 +44,13 @@ public enum SelectedBarVerticalAlignment {
}
open class ButtonBarView: UICollectionView {
open lazy var selectedBar: UIView = { [unowned self] in
let bar = UIView(frame: CGRect(x: 0, y: self.frame.size.height - CGFloat(self.selectedBarHeight), width: 0, height: CGFloat(self.selectedBarHeight)))
bar.layer.zPosition = 9999
return bar
}()
internal var selectedBarHeight: CGFloat = 4 {
didSet {
updateSelectedBarYPosition()
@ -59,96 +59,93 @@ open class ButtonBarView: UICollectionView {
var selectedBarVerticalAlignment: SelectedBarVerticalAlignment = .bottom
var selectedBarAlignment: SelectedBarAlignment = .center
var selectedIndex = 0
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
addSubview(selectedBar)
}
public override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
super.init(frame: frame, collectionViewLayout: layout)
addSubview(selectedBar)
}
open func moveTo(index: Int, animated: Bool, swipeDirection: SwipeDirection, pagerScroll: PagerScroll) {
selectedIndex = index
updateSelectedBarPosition(animated, swipeDirection: swipeDirection, pagerScroll: pagerScroll)
}
open func move(fromIndex: Int, toIndex: Int, progressPercentage: CGFloat,pagerScroll: PagerScroll) {
open func move(fromIndex: Int, toIndex: Int, progressPercentage: CGFloat, pagerScroll: PagerScroll) {
selectedIndex = progressPercentage > 0.5 ? toIndex : fromIndex
let fromFrame = layoutAttributesForItem(at: IndexPath(item: fromIndex, section: 0))!.frame
let numberOfItems = dataSource!.collectionView(self, numberOfItemsInSection: 0)
var toFrame: CGRect
if toIndex < 0 || toIndex > numberOfItems - 1 {
if toIndex < 0 {
let cellAtts = layoutAttributesForItem(at: IndexPath(item: 0, section: 0))
toFrame = cellAtts!.frame.offsetBy(dx: -cellAtts!.frame.size.width, dy: 0)
}
else {
} else {
let cellAtts = layoutAttributesForItem(at: IndexPath(item: (numberOfItems - 1), section: 0))
toFrame = cellAtts!.frame.offsetBy(dx: cellAtts!.frame.size.width, dy: 0)
}
}
else {
} else {
toFrame = layoutAttributesForItem(at: IndexPath(item: toIndex, section: 0))!.frame
}
var targetFrame = fromFrame
targetFrame.size.height = selectedBar.frame.size.height
targetFrame.size.width += (toFrame.size.width - fromFrame.size.width) * progressPercentage
targetFrame.origin.x += (toFrame.origin.x - fromFrame.origin.x) * progressPercentage
selectedBar.frame = CGRect(x: targetFrame.origin.x, y: selectedBar.frame.origin.y, width: targetFrame.size.width, height: selectedBar.frame.size.height)
var targetContentOffset: CGFloat = 0.0
if contentSize.width > frame.size.width {
let toContentOffset = contentOffsetForCell(withFrame: toFrame, andIndex: toIndex)
let fromContentOffset = contentOffsetForCell(withFrame: fromFrame, andIndex: fromIndex)
targetContentOffset = fromContentOffset + ((toContentOffset - fromContentOffset) * progressPercentage)
}
setContentOffset(CGPoint(x: targetContentOffset, y: 0), animated: false)
}
open func updateSelectedBarPosition(_ animated: Bool, swipeDirection: SwipeDirection, pagerScroll: PagerScroll) -> Void {
open func updateSelectedBarPosition(_ animated: Bool, swipeDirection: SwipeDirection, pagerScroll: PagerScroll) {
var selectedBarFrame = selectedBar.frame
let selectedCellIndexPath = IndexPath(item: selectedIndex, section: 0)
let attributes = layoutAttributesForItem(at: selectedCellIndexPath)
let selectedCellFrame = attributes!.frame
updateContentOffset(animated: animated, pagerScroll: pagerScroll, toFrame: selectedCellFrame, toIndex: (selectedCellIndexPath as NSIndexPath).row)
selectedBarFrame.size.width = selectedCellFrame.size.width
selectedBarFrame.origin.x = selectedCellFrame.origin.x
if animated {
UIView.animate(withDuration: 0.3, animations: { [weak self] in
self?.selectedBar.frame = selectedBarFrame
})
}
else {
} else {
selectedBar.frame = selectedBarFrame
}
}
// MARK: - Helpers
private func updateContentOffset(animated: Bool, pagerScroll: PagerScroll, toFrame: CGRect, toIndex: Int) -> Void {
private func updateContentOffset(animated: Bool, pagerScroll: PagerScroll, toFrame: CGRect, toIndex: Int) {
guard pagerScroll != .no || (pagerScroll != .scrollOnlyIfOutOfScreen && (toFrame.origin.x < contentOffset.x || toFrame.origin.x >= (contentOffset.x + frame.size.width - contentInset.left))) else { return }
let targetContentOffset = contentSize.width > frame.size.width ? contentOffsetForCell(withFrame: toFrame, andIndex: toIndex) : 0
setContentOffset(CGPoint(x: targetContentOffset, y: 0), animated: animated)
}
private func contentOffsetForCell(withFrame cellFrame: CGRect, andIndex index: Int) -> CGFloat {
let sectionInset = (collectionViewLayout as! UICollectionViewFlowLayout).sectionInset
let sectionInset = (collectionViewLayout as! UICollectionViewFlowLayout).sectionInset // swiftlint:disable:this force_cast
var alignmentOffset: CGFloat = 0.0
switch selectedBarAlignment {
case .left:
alignmentOffset = sectionInset.left
@ -164,16 +161,16 @@ open class ButtonBarView: UICollectionView {
let progress = index / (numberOfItems - 1)
alignmentOffset = leftAlignmentOffset + (rightAlignmentOffset - leftAlignmentOffset) * CGFloat(progress) - cellHalfWidth
}
var contentOffset = cellFrame.origin.x - alignmentOffset
contentOffset = max(0, contentOffset)
contentOffset = min(contentSize.width - frame.size.width, contentOffset)
return contentOffset
}
private func updateSelectedBarYPosition() {
var selectedBarFrame = selectedBar.frame
switch selectedBarVerticalAlignment {
case .top:
selectedBarFrame.origin.y = 0
@ -182,11 +179,11 @@ open class ButtonBarView: UICollectionView {
case .bottom:
selectedBarFrame.origin.y = frame.size.height - selectedBarHeight
}
selectedBarFrame.size.height = selectedBarHeight
selectedBar.frame = selectedBarFrame
}
override open func layoutSubviews() {
super.layoutSubviews()
updateSelectedBarYPosition()

View File

@ -25,8 +25,8 @@
import Foundation
open class ButtonBarViewCell: UICollectionViewCell {
@IBOutlet open var imageView: UIImageView!
@IBOutlet open var label: UILabel!
}

View File

@ -25,20 +25,20 @@
import Foundation
public struct IndicatorInfo {
public var title: String?
public var image: UIImage?
public var highlightedImage: UIImage?
public init(title: String?) {
self.title = title
}
public init(image: UIImage?, highlightedImage: UIImage? = nil) {
self.image = image
self.highlightedImage = highlightedImage
}
public init(title: String?, image: UIImage?, highlightedImage: UIImage? = nil) {
self.title = title
self.image = image
@ -47,18 +47,17 @@ public struct IndicatorInfo {
}
extension IndicatorInfo : ExpressibleByStringLiteral {
public init(stringLiteral value: String){
public init(stringLiteral value: String) {
title = value
}
public init(extendedGraphemeClusterLiteral value: String){
public init(extendedGraphemeClusterLiteral value: String) {
title = value
}
public init(unicodeScalarLiteral value: String){
public init(unicodeScalarLiteral value: String) {
title = value
}
}

View File

@ -25,10 +25,10 @@
import Foundation
public enum PagerTabStripBehaviour {
case common(skipIntermediateViewControllers: Bool)
case progressive(skipIntermediateViewControllers: Bool, elasticIndicatorLimit: Bool)
public var skipIntermediateViewControllers: Bool {
switch self {
case .common(let skipIntermediateViewControllers):
@ -37,8 +37,7 @@ public enum PagerTabStripBehaviour {
return skipIntermediateViewControllers
}
}
public var isProgressiveIndicator: Bool {
switch self {
case .common(_):
@ -47,7 +46,7 @@ public enum PagerTabStripBehaviour {
return true
}
}
public var isElasticIndicatorLimit: Bool {
switch self {
case .common(_):
@ -57,7 +56,3 @@ public enum PagerTabStripBehaviour {
}
}
}

View File

@ -25,5 +25,7 @@
import Foundation
public enum PagerTabStripError: Error {
case viewControllerNotContainedInPagerTabStrip
case viewControllerOutOfBounds
}

View File

@ -22,52 +22,50 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
// MARK: Protocols
public protocol IndicatorInfoProvider {
func indicatorInfo(for pagerTabStripController: PagerTabStripViewController) -> IndicatorInfo
}
public protocol PagerTabStripDelegate: class {
func updateIndicator(for viewController: PagerTabStripViewController, fromIndex: Int, toIndex: Int)
}
public protocol PagerTabStripIsProgressiveDelegate : PagerTabStripDelegate {
public protocol PagerTabStripIsProgressiveDelegate: PagerTabStripDelegate {
func updateIndicator(for viewController: PagerTabStripViewController, fromIndex: Int, toIndex: Int, withProgressPercentage progressPercentage: CGFloat, indexWasChanged: Bool)
}
public protocol PagerTabStripDataSource: class {
func viewControllers(for pagerTabStripController: PagerTabStripViewController) -> [UIViewController]
}
//MARK: PagerTabStripViewController
// MARK: PagerTabStripViewController
open class PagerTabStripViewController: UIViewController, UIScrollViewDelegate {
@IBOutlet weak public var containerView: UIScrollView!
open weak var delegate: PagerTabStripDelegate?
open weak var datasource: PagerTabStripDataSource?
open var pagerBehaviour = PagerTabStripBehaviour.progressive(skipIntermediateViewControllers: true, elasticIndicatorLimit: true)
open private(set) var viewControllers = [UIViewController]()
open private(set) var currentIndex = 0
open private(set) var preCurrentIndex = 0 // used *only* to store the index to which move when the pager becomes visible
open var pageWidth: CGFloat {
return containerView.bounds.width
}
open var scrollPercentage: CGFloat {
if swipeDirection != .right {
let module = fmod(containerView.contentOffset.x, pageWidth)
@ -75,17 +73,16 @@ open class PagerTabStripViewController: UIViewController, UIScrollViewDelegate {
}
return 1 - fmod(containerView.contentOffset.x >= 0 ? containerView.contentOffset.x : pageWidth + containerView.contentOffset.x, pageWidth) / pageWidth
}
open var swipeDirection: SwipeDirection {
if containerView.contentOffset.x > lastContentOffset {
return .left
}
else if containerView.contentOffset.x < lastContentOffset {
} else if containerView.contentOffset.x < lastContentOffset {
return .right
}
return .none
}
override open func viewDidLoad() {
super.viewDidLoad()
let conteinerViewAux = containerView ?? {
@ -106,20 +103,20 @@ open class PagerTabStripViewController: UIViewController, UIScrollViewDelegate {
containerView.showsHorizontalScrollIndicator = false
containerView.isPagingEnabled = true
reloadViewControllers()
let childController = viewControllers[currentIndex]
addChildViewController(childController)
childController.view.autoresizingMask = [.flexibleHeight, .flexibleWidth]
containerView.addSubview(childController.view)
childController.didMove(toParentViewController: self)
}
open override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
isViewAppearing = true
childViewControllers.forEach { $0.beginAppearanceTransition(true, animated: animated) }
}
override open func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
lastSize = containerView.bounds.size
@ -131,32 +128,32 @@ open class PagerTabStripViewController: UIViewController, UIScrollViewDelegate {
isViewAppearing = false
childViewControllers.forEach { $0.endAppearanceTransition() }
}
open override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
childViewControllers.forEach { $0.beginAppearanceTransition(false, animated: animated) }
}
open override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
childViewControllers.forEach { $0.endAppearanceTransition() }
}
override open func viewDidLayoutSubviews(){
override open func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
updateIfNeeded()
}
open override var shouldAutomaticallyForwardAppearanceMethods: Bool {
return false
}
open func moveToViewController(at index: Int, animated: Bool = true) {
guard isViewLoaded && view.window != nil && currentIndex != index else {
preCurrentIndex = index
return
}
if animated && pagerBehaviour.skipIntermediateViewControllers && abs(currentIndex - index) > 1 {
var tmpViewControllers = viewControllers
let currentChildVC = viewControllers[currentIndex]
@ -168,32 +165,31 @@ open class PagerTabStripViewController: UIViewController, UIScrollViewDelegate {
containerView.setContentOffset(CGPoint(x: pageOffsetForChild(at: fromIndex), y: 0), animated: false)
(navigationController?.view ?? view).isUserInteractionEnabled = !animated
containerView.setContentOffset(CGPoint(x: pageOffsetForChild(at: index), y: 0), animated: true)
}
else {
} else {
(navigationController?.view ?? view).isUserInteractionEnabled = !animated
containerView.setContentOffset(CGPoint(x: pageOffsetForChild(at: index), y: 0), animated: animated)
}
}
open func moveTo(viewController: UIViewController, animated: Bool = true) {
moveToViewController(at: viewControllers.index(of: viewController)!, animated: animated)
}
//MARK: - PagerTabStripDataSource
// MARK: - PagerTabStripDataSource
open func viewControllers(for pagerTabStripController: PagerTabStripViewController) -> [UIViewController] {
assertionFailure("Sub-class must implement the PagerTabStripDataSource viewControllers(for:) method")
return []
}
//MARK: - Helpers
// MARK: - Helpers
open func updateIfNeeded() {
if isViewLoaded && !lastSize.equalTo(containerView.bounds.size){
if isViewLoaded && !lastSize.equalTo(containerView.bounds.size) {
updateContent()
}
}
open func canMoveTo(index: Int) -> Bool {
return currentIndex != index && viewControllers.count > index
}
@ -201,28 +197,28 @@ open class PagerTabStripViewController: UIViewController, UIScrollViewDelegate {
open func pageOffsetForChild(at index: Int) -> CGFloat {
return CGFloat(index) * containerView.bounds.width
}
open func offsetForChild(at index: Int) -> CGFloat{
open func offsetForChild(at index: Int) -> CGFloat {
return (CGFloat(index) * containerView.bounds.width) + ((containerView.bounds.width - view.bounds.width) * 0.5)
}
open func offsetForChild(viewController: UIViewController) throws -> CGFloat{
open func offsetForChild(viewController: UIViewController) throws -> CGFloat {
guard let index = viewControllers.index(of: viewController) else {
throw PagerTabStripError.viewControllerNotContainedInPagerTabStrip
throw PagerTabStripError.viewControllerOutOfBounds
}
return offsetForChild(at: index)
}
open func pageFor(contentOffset: CGFloat) -> Int {
let result = virtualPageFor(contentOffset: contentOffset)
return pageFor(virtualPage: result)
}
open func virtualPageFor(contentOffset: CGFloat) -> Int {
return Int((contentOffset + 1.5 * pageWidth) / pageWidth) - 1
}
open func pageFor(virtualPage: Int) -> Int{
open func pageFor(virtualPage: Int) -> Int {
if virtualPage < 0 {
return 0
}
@ -231,25 +227,24 @@ open class PagerTabStripViewController: UIViewController, UIScrollViewDelegate {
}
return virtualPage
}
open func updateContent() {
if lastSize.width != containerView.bounds.size.width {
lastSize = containerView.bounds.size
containerView.contentOffset = CGPoint(x: pageOffsetForChild(at: currentIndex), y: 0)
}
lastSize = containerView.bounds.size
let pagerViewControllers = pagerTabStripChildViewControllersForScrolling ?? viewControllers
containerView.contentSize = CGSize(width: containerView.bounds.width * CGFloat(pagerViewControllers.count), height: containerView.contentSize.height)
for (index, childController) in pagerViewControllers.enumerated() {
let pageOffsetForChild = self.pageOffsetForChild(at: index)
if fabs(containerView.contentOffset.x - pageOffsetForChild) < containerView.bounds.width {
if let _ = childController.parent {
if childController.parent != nil {
childController.view.frame = CGRect(x: offsetForChild(at: index), y: 0, width: view.bounds.width, height: containerView.bounds.height)
childController.view.autoresizingMask = [.flexibleHeight, .flexibleWidth]
}
else {
} else {
childController.beginAppearanceTransition(true, animated: false)
addChildViewController(childController)
childController.view.frame = CGRect(x: offsetForChild(at: index), y: 0, width: view.bounds.width, height: containerView.bounds.height)
@ -258,9 +253,8 @@ open class PagerTabStripViewController: UIViewController, UIScrollViewDelegate {
childController.didMove(toParentViewController: self)
childController.endAppearanceTransition()
}
}
else {
if let _ = childController.parent {
} else {
if childController.parent != nil {
childController.beginAppearanceTransition(false, animated: false)
childController.willMove(toParentViewController: nil)
childController.view.removeFromSuperview()
@ -269,34 +263,31 @@ open class PagerTabStripViewController: UIViewController, UIScrollViewDelegate {
}
}
}
let oldCurrentIndex = currentIndex
let virtualPage = virtualPageFor(contentOffset: containerView.contentOffset.x)
let newCurrentIndex = pageFor(virtualPage: virtualPage)
currentIndex = newCurrentIndex
preCurrentIndex = currentIndex
let changeCurrentIndex = newCurrentIndex != oldCurrentIndex
if let progressiveDeledate = self as? PagerTabStripIsProgressiveDelegate, pagerBehaviour.isProgressiveIndicator {
let (fromIndex, toIndex, scrollPercentage) = progressiveIndicatorData(virtualPage)
progressiveDeledate.updateIndicator(for: self, fromIndex: fromIndex, toIndex: toIndex, withProgressPercentage: scrollPercentage, indexWasChanged: changeCurrentIndex)
}
else{
} else {
delegate?.updateIndicator(for: self, fromIndex: min(oldCurrentIndex, pagerViewControllers.count - 1), toIndex: newCurrentIndex)
}
}
open func reloadPagerTabStripView() {
guard isViewLoaded else { return }
for childController in viewControllers {
if let _ = childController.parent {
childController.beginAppearanceTransition(false, animated: false)
childController.willMove(toParentViewController: nil)
childController.view.removeFromSuperview()
childController.removeFromParentViewController()
childController.endAppearanceTransition()
}
for childController in viewControllers where childController.parent != nil {
childController.beginAppearanceTransition(false, animated: false)
childController.willMove(toParentViewController: nil)
childController.view.removeFromSuperview()
childController.removeFromParentViewController()
childController.endAppearanceTransition()
}
reloadViewControllers()
containerView.contentSize = CGSize(width: containerView.bounds.width * CGFloat(viewControllers.count), height: containerView.contentSize.height)
@ -307,22 +298,22 @@ open class PagerTabStripViewController: UIViewController, UIScrollViewDelegate {
containerView.contentOffset = CGPoint(x: pageOffsetForChild(at: currentIndex), y: 0)
updateContent()
}
//MARK: - UIScrollDelegate
// MARK: - UIScrollDelegate
open func scrollViewDidScroll(_ scrollView: UIScrollView) {
if containerView == scrollView {
updateContent()
lastContentOffset = scrollView.contentOffset.x
}
}
open func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
if containerView == scrollView {
lastPageNumber = pageFor(contentOffset: scrollView.contentOffset.x)
}
}
open func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
if containerView == scrollView {
pagerTabStripChildViewControllersForScrolling = nil
@ -330,9 +321,9 @@ open class PagerTabStripViewController: UIViewController, UIScrollViewDelegate {
updateContent()
}
}
//MARK: - Orientation
// MARK: - Orientation
open override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
isViewRotating = true
@ -345,40 +336,34 @@ open class PagerTabStripViewController: UIViewController, UIScrollViewDelegate {
me.updateIfNeeded()
}
}
//MARK: Private
// MARK: Private
private func progressiveIndicatorData(_ virtualPage: Int) -> (Int, Int, CGFloat) {
let count = viewControllers.count
var fromIndex = currentIndex
var toIndex = currentIndex
let direction = swipeDirection
if direction == .left {
if virtualPage > count - 1 {
fromIndex = count - 1
toIndex = count
}
else {
} else {
if self.scrollPercentage >= 0.5 {
fromIndex = max(toIndex - 1, 0)
}
else {
} else {
toIndex = fromIndex + 1
}
}
}
else if direction == .right {
} else if direction == .right {
if virtualPage < 0 {
fromIndex = 0
toIndex = -1
}
else {
} else {
if self.scrollPercentage > 0.5 {
fromIndex = min(toIndex + 1, count - 1)
}
else {
} else {
toIndex = fromIndex - 1
}
}
@ -386,26 +371,26 @@ open class PagerTabStripViewController: UIViewController, UIScrollViewDelegate {
let scrollPercentage = pagerBehaviour.isElasticIndicatorLimit ? self.scrollPercentage : ((toIndex < 0 || toIndex >= count) ? 0.0 : self.scrollPercentage)
return (fromIndex, toIndex, scrollPercentage)
}
private func reloadViewControllers(){
private func reloadViewControllers() {
guard let dataSource = datasource else {
fatalError("dataSource must not be nil")
}
viewControllers = dataSource.viewControllers(for: self)
// viewControllers
guard viewControllers.count != 0 else {
guard !viewControllers.isEmpty else {
fatalError("viewControllers(for:) should provide at least one child view controller")
}
viewControllers.forEach { if !($0 is IndicatorInfoProvider) { fatalError("Every view controller provided by PagerTabStripDataSource's viewControllers(for:) method must conform to InfoProvider") }}
}
private var pagerTabStripChildViewControllersForScrolling : [UIViewController]?
private var pagerTabStripChildViewControllersForScrolling: [UIViewController]?
private var lastPageNumber = 0
private var lastContentOffset: CGFloat = 0.0
private var pageBeforeRotate = 0
private var lastSize = CGSize(width: 0, height: 0)
internal var isViewRotating = false
internal var isViewAppearing = false
}

View File

@ -25,37 +25,36 @@
import Foundation
public struct SegmentedPagerTabStripSettings {
public struct Style {
public var segmentedControlColor: UIColor?
}
public var style = Style()
}
open class SegmentedPagerTabStripViewController: PagerTabStripViewController, PagerTabStripDataSource, PagerTabStripDelegate {
@IBOutlet weak public var segmentedControl: UISegmentedControl!
open var settings = SegmentedPagerTabStripSettings()
public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
pagerBehaviour = PagerTabStripBehaviour.common(skipIntermediateViewControllers: true)
delegate = self
datasource = self
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
pagerBehaviour = PagerTabStripBehaviour.common(skipIntermediateViewControllers: true)
delegate = self
datasource = self
}
private(set) var shouldUpdateSegmentedControl = true
open override func viewDidLoad() {
super.viewDidLoad()
segmentedControl = segmentedControl ?? UISegmentedControl()
@ -66,35 +65,34 @@ open class SegmentedPagerTabStripViewController: PagerTabStripViewController, Pa
segmentedControl.addTarget(self, action: #selector(SegmentedPagerTabStripViewController.segmentedControlChanged(_:)), for: .valueChanged)
reloadSegmentedControl()
}
open override func reloadPagerTabStripView() {
super.reloadPagerTabStripView()
if isViewLoaded {
reloadSegmentedControl()
}
}
func reloadSegmentedControl() {
segmentedControl.removeAllSegments()
for (index, item) in viewControllers.enumerated(){
let child = item as! IndicatorInfoProvider
for (index, item) in viewControllers.enumerated() {
let child = item as! IndicatorInfoProvider // swiftlint:disable:this force_cast
if let image = child.indicatorInfo(for: self).image {
segmentedControl.insertSegment(with: image, at: index, animated: false)
}
else {
} else {
segmentedControl.insertSegment(withTitle: child.indicatorInfo(for: self).title, at: index, animated: false)
}
}
segmentedControl.selectedSegmentIndex = currentIndex
}
func segmentedControlChanged(_ sender: UISegmentedControl) {
let index = sender.selectedSegmentIndex
updateIndicator(for: self, fromIndex: currentIndex, toIndex: index)
shouldUpdateSegmentedControl = false
moveToViewController(at: index)
}
// MARK: - PagerTabStripDelegate
open func updateIndicator(for viewController: PagerTabStripViewController, fromIndex: Int, toIndex: Int) {
@ -102,9 +100,9 @@ open class SegmentedPagerTabStripViewController: PagerTabStripViewController, Pa
segmentedControl.selectedSegmentIndex = toIndex
}
}
// MARK: - UIScrollViewDelegate
open override func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
super.scrollViewDidEndScrollingAnimation(scrollView)
shouldUpdateSegmentedControl = true

View File

@ -25,7 +25,7 @@
import Foundation
public struct TwitterPagerTabStripSettings {
public struct Style {
public var dotColor = UIColor(white: 1, alpha: 0.4)
public var selectedDotColor = UIColor.white
@ -33,38 +33,38 @@ public struct TwitterPagerTabStripSettings {
public var landscapeTitleFont = UIFont.systemFont(ofSize: 15)
public var titleColor = UIColor.white
}
public var style = Style()
}
open class TwitterPagerTabStripViewController: PagerTabStripViewController, PagerTabStripDataSource, PagerTabStripIsProgressiveDelegate {
open var settings = TwitterPagerTabStripSettings()
public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
pagerBehaviour = .progressive(skipIntermediateViewControllers: true, elasticIndicatorLimit: true)
delegate = self
datasource = self
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
pagerBehaviour = .progressive(skipIntermediateViewControllers: true, elasticIndicatorLimit: true)
delegate = self
datasource = self
}
open override func viewDidLoad() {
super.viewDidLoad()
if titleView.superview == nil {
navigationItem.titleView = titleView
}
// keep watching the frame of titleView
titleView.addObserver(self, forKeyPath: "frame", options: [.new, .old], context: nil)
guard let navigationController = navigationController else {
fatalError("TwitterPagerTabStripViewController should be embedded in a UINavigationController")
}
@ -77,11 +77,11 @@ open class TwitterPagerTabStripViewController: PagerTabStripViewController, Page
open override func reloadPagerTabStripView() {
super.reloadPagerTabStripView()
guard isViewLoaded else { return }
reloadNavigationViewItems()
setNavigationViewItemsPosition(updateAlpha: true)
}
// MARK: - PagerTabStripDelegate
open func updateIndicator(for viewController: PagerTabStripViewController, fromIndex: Int, toIndex: Int, withProgressPercentage progressPercentage: CGFloat, indexWasChanged: Bool) {
@ -91,11 +91,9 @@ open class TwitterPagerTabStripViewController: PagerTabStripViewController, Page
var xOffset: CGFloat = 0
if fromIndex < toIndex {
xOffset = distance * CGFloat(fromIndex) + distance * progressPercentage
}
else if fromIndex > toIndex {
} else if fromIndex > toIndex {
xOffset = distance * CGFloat(fromIndex) - distance * progressPercentage
}
else {
} else {
xOffset = distance * CGFloat(fromIndex)
}
@ -111,10 +109,10 @@ open class TwitterPagerTabStripViewController: PagerTabStripViewController, Page
open func updateIndicator(for viewController: PagerTabStripViewController, fromIndex: Int, toIndex: Int) {
fatalError()
}
open override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
guard object as AnyObject === titleView && keyPath == "frame" && change?[NSKeyValueChangeKey.kindKey] as? UInt == NSKeyValueChange.setting.rawValue else { return }
let oldRect = (change![NSKeyValueChangeKey.oldKey]! as AnyObject).cgRectValue
let newRect = (change![NSKeyValueChangeKey.oldKey]! as AnyObject).cgRectValue
if (oldRect?.equalTo(newRect!))! {
@ -122,26 +120,26 @@ open class TwitterPagerTabStripViewController: PagerTabStripViewController, Page
setNavigationViewItemsPosition(updateAlpha: true)
}
}
deinit {
if isViewLoaded {
titleView.removeObserver(self, forKeyPath: "frame")
}
}
open override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
setNavigationViewItemsPosition(updateAlpha: false)
}
// MARK: - Helpers
private lazy var titleView: UIView = {
let navigationView = UIView()
navigationView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
return navigationView
}()
private lazy var titleScrollView: UIScrollView = { [unowned self] in
let titleScrollView = UIScrollView(frame: CGRect(x: 0, y: 0, width: self.view.bounds.width, height: 44))
titleScrollView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
@ -156,7 +154,7 @@ open class TwitterPagerTabStripViewController: PagerTabStripViewController, Page
titleScrollView.alwaysBounceVertical = false
return titleScrollView
}()
private lazy var pageControl: FXPageControl = { [unowned self] in
let pageControl = FXPageControl()
pageControl.backgroundColor = .clear
@ -167,7 +165,7 @@ open class TwitterPagerTabStripViewController: PagerTabStripViewController, Page
pageControl.isUserInteractionEnabled = false
return pageControl
}()
private var childTitleLabels = [UILabel]()
private func reloadNavigationViewItems() {
@ -175,9 +173,9 @@ open class TwitterPagerTabStripViewController: PagerTabStripViewController, Page
childTitleLabels.forEach { $0.removeFromSuperview() }
childTitleLabels.removeAll()
for (index, item) in viewControllers.enumerated() {
let child = item as! IndicatorInfoProvider
let child = item as! IndicatorInfoProvider // swiftlint:disable:this force_cast
let indicatorInfo = child.indicatorInfo(for: self)
let navTitleLabel : UILabel = {
let navTitleLabel: UILabel = {
let label = UILabel()
label.text = indicatorInfo.title
label.font = UIApplication.shared.statusBarOrientation.isPortrait ? settings.style.portraitTitleFont : settings.style.landscapeTitleFont
@ -191,7 +189,7 @@ open class TwitterPagerTabStripViewController: PagerTabStripViewController, Page
childTitleLabels.append(navTitleLabel)
}
}
private func setNavigationViewItemsPosition(updateAlpha: Bool) {
guard let distance = distanceValue else { return }
let isPortrait = UIApplication.shared.statusBarOrientation.isPortrait
@ -207,30 +205,29 @@ open class TwitterPagerTabStripViewController: PagerTabStripViewController, Page
label.frame = CGRect(x: originX, y: originY - 2, width: viewSize.width, height: viewSize.height)
label.tag = index
}
let xOffset = distance * CGFloat(currentIndex)
titleScrollView.contentOffset = CGPoint(x: xOffset, y: 0)
pageControl.numberOfPages = childTitleLabels.count
pageControl.currentPage = currentIndex
let viewSize = pageControl.sizeForNumber(ofPages: childTitleLabels.count)
let originX = distance - viewSize.width / 2
pageControl.frame = CGRect(x: originX, y: navBarHeight - 10, width: viewSize.width, height: viewSize.height)
}
private func setAlphaWith(offset: CGFloat, andDistance distance: CGFloat) {
for (index, label) in childTitleLabels.enumerated() {
label.alpha = {
if offset < distance * CGFloat(index) {
return (offset - distance * CGFloat(index - 1)) / distance
}
else {
} else {
return 1 - ((offset - distance * CGFloat(index)) / distance)
}
}()
}
}
private var distanceValue: CGFloat? {
return navigationController.map { $0.navigationBar.convert($0.navigationBar.center, to: titleView) }?.x
}

View File

@ -9,27 +9,27 @@ import XCTest
@testable import XLPagerTabStrip
class XLPagerTabStripTests: XCTestCase {
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testExample() {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
func testPerformanceExample() {
// This is an example of a performance test case.
self.measure {
// Put the code you want to measure the time of here.
}
}
}

View File

@ -192,6 +192,7 @@
28F828791C494B2C00330CF4 /* Frameworks */,
28F8287A1C494B2C00330CF4 /* Headers */,
28F8287B1C494B2C00330CF4 /* Resources */,
CB25B8F81EBCF0CE00FEB0A2 /* SwiftLint */,
);
buildRules = (
);
@ -275,6 +276,23 @@
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
CB25B8F81EBCF0CE00FEB0A2 /* SwiftLint */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = SwiftLint;
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
28F828781C494B2C00330CF4 /* Sources */ = {
isa = PBXSourcesBuildPhase;