You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

345 lines
14 KiB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. # XLPagerTabStrip
  2. <p align="left">
  3. <a href="https://travis-ci.org/xmartlabs/XLPagerTabStrip"><img src="https://travis-ci.org/xmartlabs/XLPagerTabStrip.svg?branch=master" alt="Build status" /></a>
  4. <img src="https://img.shields.io/badge/platform-iOS-blue.svg?style=flat" alt="Platform iOS" />
  5. <a href="https://developer.apple.com/swift"><img src="https://img.shields.io/badge/swift4-compatible-4BC51D.svg?style=flat" alt="Swift 4 compatible" /></a>
  6. <a href="https://github.com/Carthage/Carthage"><img src="https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat" alt="Carthage compatible" /></a>
  7. <a href="https://cocoapods.org/pods/XLPagerTabStrip"><img src="https://img.shields.io/cocoapods/v/XLPagerTabStrip.svg" alt="CocoaPods compatible" /></a>
  8. <a href="https://raw.githubusercontent.com/xmartlabs/XLPagerTabStrip/master/LICENSE"><img src="http://img.shields.io/badge/license-MIT-blue.svg?style=flat" alt="License: MIT" />
  9. </a>
  10. <!-- <a href="https://codebeat.co/projects/github-com-xmartlabs-xlpagertabstrip"><img alt="codebeat badge" src="https://codebeat.co/badges/f32c9ad3-0aa1-4b40-a632-9421211bd39e" /></a> -->
  11. </p>
  12. Made with ❤️ by [XMARTLABS](http://xmartlabs.com).
  13. Android [PagerTabStrip](http://developer.android.com/reference/android/support/v4/view/PagerTabStrip.html) for iOS!
  14. **XLPagerTabStrip** is a *Container View Controller* that allows us to switch easily among a collection of view controllers. Pan gesture can be used to move on to next or previous view controller. It shows a interactive indicator of the current, previous, next child view controllers.
  15. <table>
  16. <tr>
  17. <th><img src="Example/instagram.gif" width="250"/></th>
  18. <th><img src="Example/spotify.gif" width="250"/></th>
  19. <th><img src="Example/youtube.gif" width="250"/></th>
  20. <th><img src="Example/pagerTabStripTypes.gif" width="250"/></th>
  21. </tr>
  22. </table>
  23. ## Getting involved
  24. * If you **want to contribute** please feel free to **submit pull requests**.
  25. * If you **have a feature request** please **open an issue**.
  26. * If you **found a bug** or **need help** please **check older issues, [FAQ](#faq) and threads on [StackOverflow](http://stackoverflow.com/questions/tagged/XLPagerTabStrip) (Tag 'XLPagerTabStrip') before submitting an issue**.
  27. **Before contribute check the [CONTRIBUTING](CONTRIBUTING.md) file for more info.**
  28. If you use **XLPagerTabStrip** in your app we would love to hear about it! Drop us a line on [twitter](https://twitter.com/xmartlabs).
  29. ## Pager Types
  30. The library provides 4 different ways to show the view controllers.
  31. ### Button Bar
  32. This is likely the most common pager type. It's used by many well-known apps such as instagram, youtube, skype, and many others.
  33. <img src="Example/barButton.gif" width="250"/>
  34. ### Bar
  35. This mode doesn't show a title neither an image. It only shows a bar that indicates the current view controller.
  36. <img src="Example/bar.gif" width="250"/>
  37. ### Twitter
  38. A long time ago, the twitter app made use of this type of pager in the app main screen.
  39. <img src="Example/twitter.gif" width="250"/>
  40. ### Segmented
  41. This mode uses a `UISegmentedControl` to indicate which view controller is being displayed.
  42. <img src="Example/segmented.gif" width="250"/>
  43. ## Usage
  44. Basically, we just need to provide the list of child view controllers to show, and these view controllers should provide the information (title or image) that will be shown in the associated indicator.
  45. Let's see the steps to do this:
  46. ##### Choose which type of pager we want to create
  47. First, we must choose the type of pager we want to create. Depending on our choice, we will have to create a view controller that extends from one of the following controllers: `TwitterPagerTabStripViewController`, `ButtonBarPagerTabStripViewController`, `SegmentedPagerTabStripViewController`, `BarPagerTabStripViewController`.
  48. > All these built-in pager controllers extend from the base class `PagerTabStripViewController`.
  49. > You can also make your custom pager controller by extending directly from `PagerTabStripViewController` in the event that no pager menu type fits your needs.
  50. ```swift
  51. import XLPagerTabStrip
  52. class MyPagerTabStripName: ButtonBarPagerTabStripViewController {
  53. ..
  54. }
  55. ```
  56. ##### Connect outlets and add layout constraints
  57. We strongly recommend using IB to set up our page controller views.
  58. Drag a `UIViewController` into the storyboard and set up its class with your pager controller (`MyPagerTabStripName`).
  59. Drag a `UIScrollView` into your view controller view and connect `PagerTabStripViewController` `containerView` outlet with the scroll view.
  60. Depending on which type of paging view controller you are working with you may have to connect more outlets.
  61. For `BarPagerTabStripViewController`, we should connect `barView` outlet. barView type is UIView. `ButtonBarPagerTabStripViewController` requires us to connect `buttonBarView` outlet. `buttonBarView` type is `ButtonBarView` which extends from `UICollectionView`. `SegmentedPagerTabStripViewController` has a `segmentedControl` outlet; if the outlet is not connected the library try to set up the navigationItem `titleView` property using a `UISegmentedControl`. `TwitterPagerTabStripViewController` doesn't require us to connect any additional outlet.
  62. > The example project contains a example for each pager controller type and we can look into it to see how views were added and how outlets were connected.
  63. ##### Provide the view controllers that will appear embedded into the PagerTabStrip view controller
  64. You can provide the view controllers by overriding `func viewControllers(for: pagerTabStripController: PagerTabStripViewController) -> [UIViewController]` method.
  65. ```swift
  66. override public func viewControllers(for pagerTabStripController: PagerTabStripViewController) -> [UIViewController] {
  67. return [MyEmbeddedViewController(), MySecondEmbeddedViewController()]
  68. }
  69. ```
  70. > The method above is the only method declared in `PagerTabStripDataSource` protocol. We don't need to explicitly conform to it since base pager class already does it.
  71. ##### Provide information to show in each indicator
  72. Every UIViewController that will appear within the PagerTabStrip needs to provide either a title or an image.
  73. In order to do so they should conform to `IndicatorInfoProvider` by implementing `func indicatorInfo(for pagerTabStripController: PagerTabStripViewController) -> IndicatorInfo`
  74. which provides the information required to show the PagerTabStrip menu (indicator) associated with the view controller.
  75. ```swift
  76. class MyEmbeddedViewController: UITableViewController, IndicatorInfoProvider {
  77. func indicatorInfo(for pagerTabStripController: PagerTabStripViewController) -> IndicatorInfo {
  78. return IndicatorInfo(title: "My Child title")
  79. }
  80. }
  81. ```
  82. **For a detailed step-by-step guide about how to use the library, please check out this community [blog post](https://medium.com/michaeladeyeri/how-to-implement-android-like-tab-layouts-in-ios-using-swift-3-578516c3aa9).**
  83. That's it! We're done! 🍻🍻
  84. ## Customization
  85. ##### Pager Behaviour
  86. The pager indicator can be updated progressive as we swipe or at once in the middle of the transition between the view controllers.
  87. By setting up `pagerBehaviour` property we can choose how the indicator should be updated.
  88. ```swift
  89. public var pagerBehaviour: PagerTabStripBehaviour
  90. ```
  91. ```swift
  92. public enum PagerTabStripBehaviour {
  93. case common(skipIntermediteViewControllers: Bool)
  94. case progressive(skipIntermediteViewControllers: Bool, elasticIndicatorLimit: Bool)
  95. }
  96. ```
  97. Default Values:
  98. ```swift
  99. // Twitter Type
  100. PagerTabStripBehaviour.common(skipIntermediateViewControllers: true)
  101. // Segmented Type
  102. PagerTabStripBehaviour.common(skipIntermediateViewControllers: true)
  103. // Bar Type
  104. PagerTabStripBehaviour.progressive(skipIntermediateViewControllers: true, elasticIndicatorLimit: true)
  105. // ButtonBar Type
  106. PagerTabStripBehaviour.progressive(skipIntermediateViewControllers: true, elasticIndicatorLimit: true)
  107. ```
  108. As you might have noticed, `common` and `progressive` enumeration cases have `skipIntermediateViewControllers` and `elasticIndicatorLimit` associated values.
  109. `skipIntermediateViewControllers` allows us to skip intermediate view controllers when a tab indicator is tapped.
  110. `elasticIndicatorLimit` allows us to tension the indicator when we reach a limit, I mean when we try to move forward from last indicator or move back from first indicator.
  111. ##### PagerTabStripDelegate & PagerTabStripIsProgressiveDelegate
  112. Normally we don't need to implement these protocols because each pager type already conforms to it in order to properly update its indicator. However, there may be some scenarios when overriding a method may come in handy.
  113. ```swift
  114. public protocol PagerTabStripDelegate: class {
  115. func updateIndicator(for viewController: PagerTabStripViewController, fromIndex: Int, toIndex: Int)
  116. }
  117. public protocol PagerTabStripIsProgressiveDelegate : PagerTabStripDelegate {
  118. func updateIndicator(for viewController: PagerTabStripViewController, fromIndex: Int, toIndex: Int, withProgressPercentage progressPercentage: CGFloat, indexWasChanged: Bool)
  119. }
  120. ```
  121. > Again, the method invoked by the library depends on the `pagerBehaviour` value.
  122. ### ButtonBar Customization
  123. ```swift
  124. settings.style.buttonBarBackgroundColor: UIColor?
  125. // buttonBar minimumInteritemSpacing value, note that button bar extends from UICollectionView
  126. settings.style.buttonBarMinimumInteritemSpacing: CGFloat?
  127. // buttonBar minimumLineSpacing value
  128. settings.style.buttonBarMinimumLineSpacing: CGFloat?
  129. // buttonBar flow layout left content inset value
  130. settings.style.buttonBarLeftContentInset: CGFloat?
  131. // buttonBar flow layout right content inset value
  132. settings.style.buttonBarRightContentInset: CGFloat?
  133. // selected bar view is created programmatically so it's important to set up the following 2 properties properly
  134. settings.style.selectedBarBackgroundColor = UIColor.black
  135. settings.style.selectedBarHeight: CGFloat = 5
  136. // each buttonBar item is a UICollectionView cell of type ButtonBarViewCell
  137. settings.style.buttonBarItemBackgroundColor: UIColor?
  138. settings.style.buttonBarItemFont = UIFont.systemFont(ofSize: 18)
  139. // helps to determine the cell width, it represent the space before and after the title label
  140. settings.style.buttonBarItemLeftRightMargin: CGFloat = 8
  141. settings.style.buttonBarItemTitleColor: UIColor?
  142. // in case the barView items do not fill the screen width this property stretch the cells to fill the screen
  143. settings.style.buttonBarItemsShouldFillAvailiableWidth = true
  144. // only used if button bar is created programmatically and not using storyboards or nib files as recommended.
  145. public var buttonBarHeight: CGFloat?
  146. ```
  147. **Important:** Settings should be called before `viewDidLoad` is called.
  148. ```swift
  149. override func viewDidLoad() {
  150. self.settings.style.selectedBarHeight = 2
  151. self.settings.style.selectedBarBackgroundColor = UIColor.white
  152. super.viewDidLoad()
  153. }
  154. ```
  155. ##### Update cells when selected indicator changes
  156. We may need to update the indicator cell when the displayed view controller changes. The following function properties help to accomplish that. Depending on our pager `pagerBehaviour` value we will have to set up `changeCurrentIndex` or `changeCurrentIndexProgressive`.
  157. ```swift
  158. public var changeCurrentIndex: ((oldCell: ButtonBarViewCell?, newCell: ButtonBarViewCell?, animated: Bool) -> Void)?
  159. public var changeCurrentIndexProgressive: ((oldCell: ButtonBarViewCell?, newCell: ButtonBarViewCell?, progressPercentage: CGFloat, changeCurrentIndex: Bool, animated: Bool) -> Void)?
  160. ```
  161. Let's see an example:
  162. ```swift
  163. changeCurrentIndexProgressive = { (oldCell: ButtonBarViewCell?, newCell: ButtonBarViewCell?, progressPercentage: CGFloat, changeCurrentIndex: Bool, animated: Bool) -> Void in
  164. guard changeCurrentIndex == true else { return }
  165. oldCell?.label.textColor = UIColor(white: 1, alpha: 0.6)
  166. newCell?.label.textColor = UIColor.white
  167. if animated {
  168. UIView.animate(withDuration: 0.1, animations: { () -> Void in
  169. newCell?.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
  170. oldCell?.transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
  171. })
  172. }
  173. else {
  174. newCell?.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
  175. oldCell?.transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
  176. }
  177. }
  178. ```
  179. ### Bar Type Customization
  180. ```swift
  181. settings.style.barBackgroundColor: UIColor?
  182. settings.style.selectedBarBackgroundColor: UIColor?
  183. // barHeight is only set up when the bar is created programmatically and not using storyboards or xib files as recommended.
  184. settings.style.barHeight: CGFloat = 5
  185. ```
  186. ### Twitter Type Customization
  187. ```swift
  188. settings.style.dotColor = UIColor(white: 1, alpha: 0.4)
  189. settings.style.selectedDotColor = UIColor.white
  190. settings.style.portraitTitleFont = UIFont.systemFont(ofSize: 18)
  191. settings.style.landscapeTitleFont = UIFont.systemFont(ofSize: 15)
  192. settings.style.titleColor = UIColor.white
  193. ```
  194. ### Segmented Type Customization
  195. ```swift
  196. settings.style.segmentedControlColor: UIColor?
  197. ```
  198. ## Requirements
  199. * iOS 9.3+
  200. * Xcode 10.1+
  201. ## Examples
  202. Follow these 3 steps to run Example project: Clone XLPagerTabStrip repository, open XLPagerTabStrip workspace and run the *Example* project.
  203. ## Installation
  204. ### CocoaPods
  205. [CocoaPods](https://cocoapods.org/) is a dependency manager for Cocoa projects.
  206. To install XLPagerTabStrip, simply add the following line to your Podfile:
  207. ```ruby
  208. pod 'XLPagerTabStrip', '~> 8.1'
  209. ```
  210. ### Carthage
  211. [Carthage](https://github.com/Carthage/Carthage) is a simple, decentralized dependency manager for Cocoa.
  212. To install XLPagerTabStrip, simply add the following line to your Cartfile:
  213. ```ogdl
  214. github "xmartlabs/XLPagerTabStrip" ~> 8.1
  215. ```
  216. ## FAQ
  217. #### How to change the visible child view controller programmatically
  218. `PagerTabStripViewController` provides the following methods to programmatically change the visible child view controller:
  219. ```swift
  220. func moveToViewController(at index: Int)
  221. func moveToViewController(at index: Int, animated: Bool)
  222. func moveTo(viewController: UIViewController)
  223. func moveTo(viewController: UIViewController, animated: Bool)
  224. ```
  225. #### How to migrate from Swift 2 to Swift 3 <a name="migrate"></a>
  226. Check out [our migration guide](https://github.com/xmartlabs/XLPagerTabStrip/blob/master/Migration.md)
  227. ## Author
  228. * [Martin Barreto](https://github.com/mtnBarreto) ([@mtnBarreto](https://twitter.com/mtnBarreto))
  229. ## Change Log
  230. This can be found in the [CHANGELOG.md](CHANGELOG.md) file.