├── .gitignore ├── .travis.yml ├── LICENSE ├── PageController ├── .DS_Store ├── FloodView.swift ├── MenuItem.swift ├── MenuView.swift ├── PageController.swift └── ProgressView.swift ├── README.md ├── StoryboardExample ├── StoryboardExample.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcuserdata │ │ │ └── Mark.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ ├── xcshareddata │ │ └── xcschemes │ │ │ └── StoryboardExample.xcscheme │ └── xcuserdata │ │ └── Mark.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ └── xcschememanagement.plist ├── StoryboardExample │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ ├── ParentController │ │ └── CustomPageController.swift │ ├── TableViewController.swift │ └── ViewController.swift ├── StoryboardExampleTests │ ├── Info.plist │ └── StoryboardExampleTests.swift └── StoryboardExampleUITests │ ├── Info.plist │ └── StoryboardExampleUITests.swift ├── WMPageController-Swift.podspec ├── WMPageController-Swift.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── Mark.xcuserdatad │ │ └── UserInterfaceState.xcuserstate ├── xcshareddata │ └── xcschemes │ │ ├── WMPageController-Swift.xcscheme │ │ └── WMPageControllerSwiftFramework.xcscheme └── xcuserdata │ └── Mark.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── WMPageController-Swift ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── TableViewController.swift └── ViewController.swift ├── WMPageController-SwiftTests ├── Info.plist └── WMPageController_SwiftTests.swift ├── WMPageController-SwiftUITests ├── Info.plist └── WMPageController_SwiftUITests.swift └── WMPageControllerSwiftFramework ├── Info.plist └── WMPageControllerSwiftFramework.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | # Pods/ 27 | 28 | # Carthage 29 | # 30 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 31 | # Carthage/Checkouts 32 | 33 | Carthage/Build 34 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: xcode7.3 3 | xcode_project: WMPageController-Swift.xcodeproj 4 | xcode_scheme: WMPageControllerSwiftFramework 5 | xcode_sdk: iphonesimulator9.3 6 | env: 7 | global: 8 | - FRAMEWORK_NAME=WMPageControllerSwiftFramework 9 | before_install: 10 | - brew update 11 | - brew outdated carthage || brew upgrade carthage 12 | before_script: 13 | before_deploy: 14 | - carthage build --no-skip-current 15 | - carthage archive WMPageControllerSwift 16 | deploy: 17 | provider: releases 18 | api_key: 19 | secure: hxnNtDAGGZFHRMxJF02POFZfDZq7mjYd+B1osAtCXPmf7wE+Twk3+Ax4VuFR3bGrtYCbegaSWFsrxwG7JOtqTzDQ6eIJvvK85N6+//MX3iyloO/sbtljgDEdDDdjwKiIK3pQhnL9F7Rd+3fz5JAVPYIkNEO5E7BnwvDIWQOxK/QtW5fhBmuGM1+YacvsQX8f+MrHjKslIsZp5DRaXXLtyDlV8eKwHef127+nRmnvkPBHVA/ZQhVMLAdcuNvzl64XXryDgNQxCDCqNw60IiIFnMNtaN1G1H9JwF0mQBWm4Pn8Yua+KV8rVOyW3F39YXFCrfcBIfgqJpeB7bzJr7WD2p2G4y1x2yAiXn1Dc5TpCrhnLffoJ3MtyD2KbgD/kVsKOtnfWAdAHyKIbSTQIEpHfRLcr7beucANxoDK4VMtARPsz1WGyzNqUU+Chguj32B6IXKB3NMifXy7syBBT59ZJzUCbyp1Om/CAJDCChP8EsByFD8AhDSYfZKvfO3NK/x+qZdgxV3EOiCrcF9q7rACA32yyxXTa75J+LzcsgN/ESd9GPOC8E8t0I86JdwwRlROGUNjcSRFOcGZ50Rrdd2c5L42rD1OOkTzUCAnacj2U2ewnyDREQ0SQ7EYsrVl8Mtzglb1VNISrsgscx2gJwCZXtbWIitMdcGCv6K1mMB9HNg= 20 | file: WMPageControllerSwift.framework.zip 21 | on: 22 | repo: wangmchn/WMPageController-Swift 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Wang Ming 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /PageController/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangmchn/WMPageController-Swift/4c68bdc69568c02809b06e1c403050ecb967ac46/PageController/.DS_Store -------------------------------------------------------------------------------- /PageController/FloodView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FooldView.swift 3 | // PageController 4 | // 5 | // Created by Mark on 15/10/20. 6 | // Copyright © 2015年 Wecan Studio. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class FloodView: ProgressView { 12 | 13 | // MARK: - Vars 14 | var hollow = false 15 | fileprivate var margin: CGFloat = 0.0 16 | fileprivate var radius: CGFloat = 0.0 17 | fileprivate var height: CGFloat = 0.0 18 | 19 | // MARK: - Private funcs 20 | override func willMove(toSuperview newSuperview: UIView?) { 21 | height = frame.size.height 22 | margin = height * 0.15 23 | radius = (height - margin * 2.0) / 2.0 24 | } 25 | 26 | override func draw(_ rect: CGRect) { 27 | // Drawing code 28 | let currentIndex = Int(progress) 29 | let rate = progress - CGFloat(currentIndex) 30 | let nextIndex = (currentIndex + 1) >= itemFrames.count ? currentIndex : currentIndex + 1 31 | let currentFrame = itemFrames[currentIndex] 32 | let currentWidth = currentFrame.size.width 33 | let currentX = currentFrame.origin.x 34 | let nextWidth = itemFrames[nextIndex].size.width 35 | let nextX = self.itemFrames[nextIndex].origin.x 36 | let startX = currentX + (nextX - currentX) * rate 37 | let endX = startX + currentWidth + (nextWidth - currentWidth) * rate 38 | let ctx = UIGraphicsGetCurrentContext() 39 | ctx?.translateBy(x: 0.0, y: height) 40 | ctx?.scaleBy(x: 1.0, y: -1.0) 41 | ctx?.addArc(center: CGPoint(x: startX + radius, y: height / 2.0), radius: radius, startAngle: CGFloat(Double.pi / 2), endAngle: CGFloat(Double.pi / 2) * 3, clockwise: false) 42 | // CGContextAddArc(ctx, startX + radius, height / 2.0, radius, CGFloat(M_PI_2), CGFloat(M_PI_2) * 3, 0) 43 | ctx?.addLine(to: CGPoint(x: endX - radius, y: margin)) 44 | ctx?.addArc(center: CGPoint(x: endX - radius, y: height / 2.0), radius: radius, startAngle: CGFloat(-Double.pi / 2), endAngle: CGFloat(Double.pi / 2), clockwise: false) 45 | // CGContextAddArc(ctx, endX - radius, height / 2.0, radius, CGFloat(-M_PI_2), CGFloat(M_PI_2), 0) 46 | ctx?.closePath() 47 | if hollow == true { 48 | ctx?.setStrokeColor(color) 49 | ctx?.strokePath() 50 | return 51 | } 52 | ctx?.closePath() 53 | ctx?.setFillColor(color) 54 | ctx?.fillPath() 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /PageController/MenuItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MenuItem.swift 3 | // PageController 4 | // 5 | // Created by Mark on 15/10/20. 6 | // Copyright © 2015年 Wecan Studio. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | protocol MenuItemDelegate: NSObjectProtocol { 12 | func didSelectedMenuItem(_ menuItem: MenuItem) 13 | } 14 | 15 | class MenuItem: UILabel { 16 | 17 | // MARK: - Public vars 18 | var normalSize: CGFloat = 15.0 19 | var selectedSize: CGFloat = 18.0 20 | weak var delegate: MenuItemDelegate? 21 | 22 | var selected = false { 23 | didSet { rate = (selected == false) ? 0.0 : 1.0 } 24 | } 25 | 26 | var rate: CGFloat = 0.0 { 27 | didSet { 28 | let red = normalComponents.red + (selectedComponets.red - normalComponents.red) * rate 29 | let green = normalComponents.green + (selectedComponets.green - normalComponents.green) * rate 30 | let blue = normalComponents.blue + (selectedComponets.blue - normalComponents.blue) * rate 31 | let alpha = normalComponents.alpha + (selectedComponets.alpha - normalComponents.alpha) * rate 32 | let minScale = normalSize / selectedSize 33 | let trueScale = minScale + (1 - minScale) * rate 34 | textColor = UIColor(red: red, green: green, blue: blue, alpha: alpha) 35 | transform = CGAffineTransform(scaleX: trueScale, y: trueScale) 36 | } 37 | } 38 | 39 | var normalColor: UIColor? { 40 | didSet { 41 | normalColor?.getRed(&normalComponents.red, green: &normalComponents.green, blue: &normalComponents.blue, alpha: &normalComponents.alpha) 42 | } 43 | } 44 | 45 | var selectedColor: UIColor? { 46 | didSet { 47 | selectedColor?.getRed(&selectedComponets.red, green: &selectedComponets.green, blue: &selectedComponets.blue, alpha: &selectedComponets.alpha) 48 | } 49 | } 50 | 51 | // MARK: - Private vars 52 | fileprivate var normalComponents: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) = (0.0, 0.0, 0.0, 0.0) 53 | fileprivate var selectedComponets: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) = (0.0, 0.0, 0.0, 0.0) 54 | 55 | // MARK: - Public funcs 56 | func selectWithAnimation(_ select: Bool) -> Void { 57 | if selected == select { return } 58 | UIView.animate(withDuration: 0.3, animations: { () -> Void in 59 | if self.selected == true { 60 | self.rate = 0.0 61 | } else { 62 | self.rate = 1.0 63 | } 64 | self.selected = select 65 | }) 66 | } 67 | 68 | override init(frame: CGRect) { 69 | super.init(frame: frame) 70 | setup() 71 | } 72 | 73 | required init?(coder aDecoder: NSCoder) { 74 | super.init(coder: aDecoder) 75 | setup() 76 | } 77 | 78 | // MARK: - Private funcs 79 | fileprivate func setup() { 80 | textAlignment = NSTextAlignment.center 81 | isUserInteractionEnabled = true 82 | backgroundColor = .clear 83 | numberOfLines = 0 84 | } 85 | 86 | override func touchesEnded(_ touches: Set, with event: UIEvent?) { 87 | delegate?.didSelectedMenuItem(self) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /PageController/MenuView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MenuView.swift 3 | // PageController 4 | // 5 | // Created by Mark on 15/10/20. 6 | // Copyright © 2015年 Wecan Studio. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @objc public protocol MenuViewDelegate: NSObjectProtocol { 12 | func menuView(_ menuView: MenuView, widthForItemAtIndex index: Int) -> CGFloat 13 | @objc optional func menuView(_ menuView: MenuView, didSelectedIndex index: Int, fromIndex currentIndex: Int) 14 | @objc optional func menuView(_ menuView: MenuView, itemMarginAtIndex index: Int) -> CGFloat 15 | } 16 | 17 | @objc public protocol MenuViewDataSource: NSObjectProtocol { 18 | func menuView(_ menuView: MenuView, titleAtIndex index: Int) -> String 19 | func numbersOfTitlesInMenuView(_ menuView: MenuView) -> Int 20 | } 21 | 22 | public enum MenuViewStyle { 23 | case `default`, line, flood, fooldHollow 24 | } 25 | 26 | open class MenuView: UIView, MenuItemDelegate { 27 | 28 | // MARK: - Public vars 29 | override open var frame: CGRect { 30 | didSet { 31 | guard contentView != nil else { return } 32 | 33 | let rightMargin = (rightView == nil) ? contentMargin : contentMargin + rightView!.frame.width 34 | let leftMargin = (leftView == nil) ? contentMargin : contentMargin + leftView!.frame.width 35 | let contentWidth = contentView.frame.width + leftMargin + rightMargin 36 | 37 | let startX = (leftView != nil) ? leftView!.frame.origin.x : (contentView.frame.origin.x - contentMargin) 38 | 39 | // Make the contentView center, because system will change menuView's frame if it's a titleView. 40 | if (startX + contentWidth / 2 != bounds.width / 2) { 41 | let xOffset = (contentWidth - bounds.width) / 2 42 | contentView.frame.origin.x -= xOffset 43 | rightView?.frame.origin.x -= xOffset 44 | leftView?.frame.origin.x -= xOffset 45 | } 46 | 47 | } 48 | } 49 | 50 | open weak var leftView: UIView? { 51 | willSet { 52 | leftView?.removeFromSuperview() 53 | } 54 | didSet { 55 | if let lView = leftView { 56 | addSubview(lView) 57 | } 58 | resetFrames() 59 | } 60 | } 61 | 62 | open weak var rightView: UIView? { 63 | willSet { 64 | rightView?.removeFromSuperview() 65 | } 66 | didSet { 67 | if let rView = rightView { 68 | addSubview(rView) 69 | } 70 | resetFrames() 71 | } 72 | } 73 | 74 | open var contentMargin: CGFloat = 0.0 { 75 | didSet { 76 | guard contentView != nil else { return } 77 | resetFrames() 78 | } 79 | } 80 | 81 | open var style = MenuViewStyle.default 82 | open var fontName: String? 83 | open var progressHeight: CGFloat = 2.0 84 | open var normalSize: CGFloat = 15.0 85 | open var selectedSize: CGFloat = 18.0 86 | open var progressColor: UIColor? 87 | 88 | open weak var delegate: MenuViewDelegate? 89 | open weak var dataSource: MenuViewDataSource! 90 | open lazy var normalColor = UIColor.black 91 | open lazy var selectedColor = UIColor(red: 168.0/255.0, green: 20.0/255.0, blue: 4/255.0, alpha: 1.0) 92 | 93 | // MARK: - Private vars 94 | fileprivate weak var contentView: UIScrollView! 95 | fileprivate weak var progressView: ProgressView? 96 | fileprivate weak var selectedItem: MenuItem! 97 | fileprivate var itemFrames = [CGRect]() 98 | fileprivate let tagGap = 6250 99 | fileprivate var itemsCount: Int { 100 | return dataSource.numbersOfTitlesInMenuView(self) 101 | } 102 | 103 | open func reload() { 104 | itemFrames.removeAll() 105 | progressView?.removeFromSuperview() 106 | for subview in contentView.subviews { 107 | subview.removeFromSuperview() 108 | } 109 | 110 | addMenuItems() 111 | addProgressView() 112 | } 113 | 114 | // MARK: - Public funcs 115 | open func slideMenuAtProgress(_ progress: CGFloat) { 116 | progressView?.progress = progress 117 | let tag = Int(progress) + tagGap 118 | let rate = progress - CGFloat(tag - tagGap) 119 | let currentItem = viewWithTag(tag) as? MenuItem 120 | let nextItem = viewWithTag(tag + 1) as? MenuItem 121 | if rate == 0.0 { 122 | selectedItem.selected = false 123 | selectedItem = currentItem 124 | selectedItem.selected = true 125 | refreshContentOffset() 126 | return 127 | } 128 | currentItem?.rate = 1.0 - rate 129 | nextItem?.rate = rate 130 | } 131 | 132 | open func selectItemAtIndex(_ index: Int) { 133 | let tag = index + tagGap 134 | let currentIndex = selectedItem.tag - tagGap 135 | guard currentIndex != index && selectedItem != nil else { return } 136 | 137 | let menuItem = viewWithTag(tag) as! MenuItem 138 | selectedItem.selected = false 139 | selectedItem = menuItem 140 | selectedItem.selected = true 141 | progressView?.moveToPosition(index, animation: false) 142 | delegate?.menuView?(self, didSelectedIndex: index, fromIndex: currentIndex) 143 | refreshContentOffset() 144 | } 145 | 146 | // MARK: - Update Title 147 | open func updateTitle(_ title: String, atIndex index: Int, andWidth update: Bool) { 148 | guard index >= 0 && index < itemsCount else { return } 149 | let item = viewWithTag(tagGap + index) as? MenuItem 150 | item?.text = title 151 | guard update else { return } 152 | resetFrames() 153 | } 154 | 155 | // MARK: - Update Frames 156 | open func resetFrames() { 157 | 158 | var contentFrame = bounds 159 | if let rView = rightView { 160 | var rightFrame = rView.frame 161 | rightFrame.origin.x = contentFrame.width - rightFrame.width 162 | rightView?.frame = rightFrame 163 | contentFrame.size.width -= rightFrame.width 164 | } 165 | 166 | if let lView = leftView { 167 | var leftFrame = lView.frame 168 | leftFrame.origin.x = 0 169 | leftView?.frame = leftFrame 170 | contentFrame.origin.x += leftFrame.width 171 | contentFrame.size.width -= leftFrame.width 172 | } 173 | 174 | contentFrame.origin.x += contentMargin 175 | contentFrame.size.width -= contentMargin * 2 176 | contentView.frame = contentFrame 177 | resetFramesFromIndex(0) 178 | refreshContentOffset() 179 | } 180 | 181 | open func resetFramesFromIndex(_ index: Int) { 182 | itemFrames.removeAll() 183 | calculateFrames() 184 | for i in index ..< itemsCount { 185 | let item = viewWithTag(tagGap + i) as? MenuItem 186 | item?.frame = itemFrames[i] 187 | } 188 | if let progress = progressView { 189 | var pFrame = progress.frame 190 | pFrame.size.width = contentView.contentSize.width 191 | if progress.isKind(of: FloodView.self) { 192 | pFrame.origin.y = 0 193 | } else { 194 | pFrame.origin.y = frame.size.height - progressHeight 195 | } 196 | progress.frame = pFrame 197 | progress.itemFrames = itemFrames 198 | progress.setNeedsDisplay() 199 | } 200 | } 201 | 202 | // MARK: - Private funcs 203 | override open func willMove(toSuperview newSuperview: UIView?) { 204 | super.willMove(toSuperview: newSuperview) 205 | guard contentView == nil else { return } 206 | addScollView() 207 | addMenuItems() 208 | addProgressView() 209 | } 210 | 211 | fileprivate func refreshContentOffset() { 212 | let itemFrame = selectedItem.frame 213 | let itemX = itemFrame.origin.x 214 | let width = contentView.frame.size.width 215 | let contentWidth = contentView.contentSize.width 216 | if itemX > (width / 2) { 217 | var targetX: CGFloat = itemFrame.origin.x - width/2 + itemFrame.size.width/2 218 | if (contentWidth - itemX) <= (width / 2) { 219 | targetX = contentWidth - width 220 | } 221 | if (targetX + width) > contentWidth { 222 | targetX = contentWidth - width 223 | } 224 | contentView.setContentOffset(CGPoint(x: targetX, y: 0), animated: true) 225 | } else { 226 | contentView.setContentOffset(CGPoint.zero, animated: true) 227 | } 228 | } 229 | 230 | // MARK: - Create Views 231 | fileprivate func addScollView() { 232 | let scrollViewFrame = CGRect(x: contentMargin, y: 0, width: frame.size.width - contentMargin * 2, height: frame.size.height) 233 | let scrollView = UIScrollView(frame: scrollViewFrame) 234 | scrollView.showsVerticalScrollIndicator = false 235 | scrollView.showsHorizontalScrollIndicator = false 236 | scrollView.backgroundColor = .clear 237 | scrollView.scrollsToTop = false 238 | addSubview(scrollView) 239 | contentView = scrollView 240 | } 241 | 242 | fileprivate func addMenuItems() { 243 | calculateFrames() 244 | for index in 0 ..< itemsCount { 245 | let menuItemFrame = itemFrames[index] 246 | let menuItem = MenuItem(frame: menuItemFrame) 247 | menuItem.tag = index + tagGap 248 | menuItem.delegate = self 249 | menuItem.text = dataSource.menuView(self, titleAtIndex: index) 250 | menuItem.textColor = normalColor 251 | if let optionalFontName = fontName { 252 | menuItem.font = UIFont(name: optionalFontName, size: selectedSize) 253 | } else { 254 | menuItem.font = UIFont.systemFont(ofSize: selectedSize) 255 | } 256 | menuItem.normalSize = normalSize 257 | menuItem.selectedSize = selectedSize 258 | menuItem.normalColor = normalColor 259 | menuItem.selectedColor = selectedColor 260 | menuItem.selected = (index == 0) ? true : false 261 | if index == 0 { selectedItem = menuItem } 262 | contentView.addSubview(menuItem) 263 | } 264 | } 265 | 266 | fileprivate func addProgressView() { 267 | var optionalType: ProgressView.Type? 268 | var hollow = false 269 | switch style { 270 | case .default: break 271 | case .line: optionalType = ProgressView.self 272 | case .fooldHollow: 273 | optionalType = FloodView.self 274 | hollow = true 275 | case .flood: optionalType = FloodView.self 276 | } 277 | if let viewType = optionalType { 278 | let pView = viewType.init() 279 | let height = (style == .line) ? progressHeight : frame.size.height 280 | let progressY = (style == .line) ? (frame.size.height - progressHeight) : 0 281 | pView.frame = CGRect(x: 0, y: progressY, width: contentView.contentSize.width, height: height) 282 | pView.itemFrames = itemFrames 283 | if (progressColor == nil) { 284 | progressColor = selectedColor 285 | } 286 | pView.color = (progressColor?.cgColor)! 287 | pView.backgroundColor = .clear 288 | if let fooldView = pView as? FloodView { 289 | fooldView.hollow = hollow 290 | } 291 | contentView.insertSubview(pView, at: 0) 292 | progressView = pView 293 | } 294 | } 295 | 296 | // MARK: - Calculate Frames 297 | fileprivate func calculateFrames() { 298 | var contentWidth: CGFloat = itemMarginAtIndex(0) 299 | for index in 0 ..< itemsCount { 300 | let itemWidth = delegate!.menuView(self, widthForItemAtIndex: index) 301 | let itemFrame = CGRect(x: contentWidth, y: 0, width: itemWidth, height: frame.size.height) 302 | itemFrames.append(itemFrame) 303 | contentWidth += itemWidth + itemMarginAtIndex(index + 1) 304 | } 305 | if contentWidth < contentView.frame.size.width { 306 | let distance = contentView.frame.size.width - contentWidth 307 | let itemMargin = distance / CGFloat(itemsCount + 1) 308 | for index in 0 ..< itemsCount { 309 | var itemFrame = itemFrames[index] 310 | itemFrame.origin.x += itemMargin * CGFloat(index + 1) 311 | itemFrames[index] = itemFrame 312 | } 313 | contentWidth = contentView.frame.size.width 314 | } 315 | contentView.contentSize = CGSize(width: contentWidth, height: frame.size.height) 316 | } 317 | 318 | fileprivate func itemMarginAtIndex(_ index: Int) -> CGFloat { 319 | if let itemMargin = delegate?.menuView?(self, itemMarginAtIndex: index) { 320 | return itemMargin 321 | } 322 | return 0.0 323 | } 324 | 325 | // MARK: - MenuItemDelegate 326 | func didSelectedMenuItem(_ menuItem: MenuItem) { 327 | if selectedItem == menuItem { return } 328 | let position = menuItem.tag - tagGap 329 | let currentIndex = selectedItem.tag - tagGap 330 | progressView?.moveToPosition(position, animation: true) 331 | delegate?.menuView?(self, didSelectedIndex: position, fromIndex: currentIndex) 332 | 333 | menuItem.selectWithAnimation(true) 334 | selectedItem.selectWithAnimation(false) 335 | selectedItem = menuItem 336 | refreshContentOffset() 337 | } 338 | 339 | } 340 | -------------------------------------------------------------------------------- /PageController/PageController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PageController.swift 3 | // PageController 4 | // 5 | // Created by Mark on 15/10/20. 6 | // Copyright © 2015年 Wecan Studio. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public enum CachePolicy: Int { 12 | case noLimit = 0 13 | case lowMemory = 1 14 | case balanced = 3 15 | case high = 5 16 | } 17 | 18 | public enum PreloadPolicy: Int { 19 | case never = 0 20 | case neighbour = 1 21 | case near = 2 22 | } 23 | 24 | public let WMPageControllerDidMovedToSuperViewNotification = "WMPageControllerDidMovedToSuperViewNotification" 25 | public let WMPageControllerDidFullyDisplayedNotification = "WMPageControllerDidFullyDisplayedNotification" 26 | 27 | @objc public protocol PageControllerDataSource: NSObjectProtocol { 28 | @objc optional func numberOfControllersInPageController(_ pageController: PageController) -> Int 29 | @objc optional func pageController(_ pageController: PageController, viewControllerAtIndex index: Int) -> UIViewController 30 | @objc optional func pageController(_ pageController: PageController, titleAtIndex index: Int) -> String 31 | } 32 | 33 | @objc public protocol PageControllerDelegate: NSObjectProtocol { 34 | @objc optional func pageController(_ pageController: PageController, lazyLoadViewController viewController: UIViewController, withInfo info: NSDictionary) 35 | @objc optional func pageController(_ pageController: PageController, willCachedViewController viewController: UIViewController, withInfo info: NSDictionary) 36 | @objc optional func pageController(_ pageController: PageController, willEnterViewController viewController: UIViewController, withInfo info: NSDictionary) 37 | @objc optional func pageController(_ pageController: PageController, didEnterViewController viewController: UIViewController, withInfo info: NSDictionary) 38 | } 39 | 40 | open class ContentView: UIScrollView, UIGestureRecognizerDelegate { 41 | 42 | open func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool { 43 | 44 | guard let wrapperView = NSClassFromString("UITableViewWrapperView"), let otherGestureView = otherGestureRecognizer.view else { return false } 45 | 46 | if otherGestureView.isKind(of: wrapperView) && (otherGestureRecognizer is UIPanGestureRecognizer) { 47 | return true 48 | } 49 | return false 50 | } 51 | 52 | } 53 | 54 | open class PageController: UIViewController, UIScrollViewDelegate, MenuViewDelegate, MenuViewDataSource, PageControllerDelegate, PageControllerDataSource { 55 | 56 | // MARK: - Public vars 57 | open weak var dataSource: PageControllerDataSource? 58 | open weak var delegate: PageControllerDelegate? 59 | 60 | open var viewControllerClasses: [UIViewController.Type]? 61 | open var titles: [String]? 62 | open var values: NSArray? 63 | open var keys: [String]? 64 | open var progressColor: UIColor? 65 | open var progressHeight: CGFloat = 2.0 66 | open var itemMargin: CGFloat = 0.0 67 | open var menuViewStyle = MenuViewStyle.default 68 | open var titleFontName: String? 69 | open var pageAnimatable = false 70 | open var postNotification = false 71 | open var bounces = false 72 | open var showOnNavigationBar = false 73 | open var startDragging = false 74 | open var titleSizeSelected: CGFloat = 18.0 75 | open var titleSizeNormal: CGFloat = 15.0 76 | open var menuHeight: CGFloat = 30.0 77 | open var menuItemWidth: CGFloat = 65.0 78 | open weak var contentView: ContentView? 79 | open weak var menuView: MenuView? 80 | 81 | open var itemsWidths: [CGFloat]? 82 | 83 | open fileprivate(set) var currentViewController: UIViewController? 84 | 85 | open var selectedIndex: Int { 86 | set { 87 | _selectedIndex = newValue 88 | menuView?.selectItemAtIndex(newValue) 89 | } 90 | get { return _selectedIndex } 91 | } 92 | 93 | open var menuViewContentMargin: CGFloat = 0.0 { 94 | didSet { 95 | guard let menu = menuView else { return } 96 | menu.contentMargin = oldValue 97 | } 98 | } 99 | 100 | open var viewFrame = CGRect() { 101 | didSet { 102 | if let _ = menuView { 103 | hasInit = false 104 | viewDidLayoutSubviews() 105 | } 106 | } 107 | } 108 | 109 | open var itemsMargins: [CGFloat]? 110 | open var preloadPolicy: PreloadPolicy = .never 111 | 112 | open var cachePolicy: CachePolicy = .noLimit { 113 | didSet { memCache.countLimit = cachePolicy.rawValue } 114 | } 115 | 116 | open lazy var titleColorSelected = UIColor(red: 168.0/255.0, green: 20.0/255.0, blue: 4/255.0, alpha: 1.0) 117 | open lazy var titleColorNormal = UIColor.black 118 | open lazy var menuBGColor = UIColor(red: 244.0/255.0, green: 244.0/255.0, blue: 244.0/255.0, alpha: 1.0) 119 | 120 | override open var edgesForExtendedLayout: UIRectEdge { 121 | didSet { 122 | hasInit = false 123 | viewDidLayoutSubviews() 124 | } 125 | } 126 | 127 | // MARK: - Private vars 128 | fileprivate var memoryWarningCount = 0 129 | fileprivate var viewHeight: CGFloat = 0.0 130 | fileprivate var viewWidth: CGFloat = 0.0 131 | fileprivate var viewX: CGFloat = 0.0 132 | fileprivate var viewY: CGFloat = 0.0 133 | fileprivate var _selectedIndex = 0 134 | fileprivate var targetX: CGFloat = 0.0 135 | fileprivate var superviewHeight: CGFloat = 0.0 136 | fileprivate var hasInit = false 137 | fileprivate var shouldNotScroll = false 138 | fileprivate var initializedIndex = -1 139 | fileprivate var controllerCount = -1 140 | 141 | fileprivate var childControllersCount: Int { 142 | if controllerCount == -1 { 143 | if let count = dataSource?.numberOfControllersInPageController?(self) { 144 | controllerCount = count 145 | } else { 146 | controllerCount = (viewControllerClasses?.count ?? 0) 147 | } 148 | } 149 | return controllerCount 150 | } 151 | 152 | lazy fileprivate var displayingControllers = NSMutableDictionary() 153 | lazy fileprivate var memCache = NSCache() 154 | lazy fileprivate var childViewFrames = [CGRect]() 155 | 156 | // MARK: - Life cycle 157 | public convenience init(vcClasses: [UIViewController.Type], theirTitles: [String]) { 158 | self.init() 159 | assert(vcClasses.count == theirTitles.count, "`vcClasses.count` must equal to `titles.count`") 160 | titles = theirTitles 161 | viewControllerClasses = vcClasses 162 | } 163 | 164 | override open func viewDidLoad() { 165 | super.viewDidLoad() 166 | view.backgroundColor = .white 167 | guard childControllersCount > 0 else { return } 168 | 169 | calculateSize() 170 | addScrollView() 171 | addViewControllerAtIndex(_selectedIndex) 172 | currentViewController = displayingControllers[_selectedIndex] as? UIViewController 173 | addMenuView() 174 | } 175 | 176 | override open func viewDidLayoutSubviews() { 177 | super.viewDidLayoutSubviews() 178 | guard childControllersCount > 0 else { return } 179 | 180 | let oldSuperviewHeight = superviewHeight 181 | superviewHeight = view.frame.size.height 182 | guard (!hasInit || superviewHeight != oldSuperviewHeight) && (view.window != nil) else { return } 183 | 184 | calculateSize() 185 | adjustScrollViewFrame() 186 | adjustMenuViewFrame() 187 | removeSuperfluousViewControllersIfNeeded() 188 | currentViewController?.view.frame = childViewFrames[_selectedIndex] 189 | hasInit = true 190 | view.layoutIfNeeded() 191 | } 192 | 193 | override open func viewDidAppear(_ animated: Bool) { 194 | super.viewDidAppear(animated) 195 | guard childControllersCount > 0 else { return } 196 | postFullyDisplayedNotificationWithIndex(_selectedIndex) 197 | didEnterController(currentViewController!, atIndex: _selectedIndex) 198 | } 199 | 200 | override open func didReceiveMemoryWarning() { 201 | super.didReceiveMemoryWarning() 202 | 203 | memoryWarningCount += 1 204 | cachePolicy = CachePolicy.lowMemory 205 | NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(PageController.growCachePolicyAfterMemoryWarning), object: nil) 206 | NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(PageController.growCachePolicyToHigh), object: nil) 207 | memCache.removeAllObjects() 208 | if memoryWarningCount < 3 { 209 | perform(#selector(PageController.growCachePolicyAfterMemoryWarning), with: nil, afterDelay: 3.0, inModes: [RunLoopMode.commonModes]) 210 | } 211 | } 212 | 213 | // MARK: - Reload 214 | open func reloadData() { 215 | clearDatas() 216 | resetScrollView() 217 | memCache.removeAllObjects() 218 | viewDidLayoutSubviews() 219 | resetMenuView() 220 | } 221 | 222 | // MARK: - Update Title 223 | open func updateTitle(_ title: String, atIndex index: Int) { 224 | menuView?.updateTitle(title, atIndex: index, andWidth: false) 225 | } 226 | 227 | open func updateTitle(_ title: String, atIndex index: Int, andWidth width: CGFloat) { 228 | if var widths = itemsWidths { 229 | guard index < widths.count else { return } 230 | widths[index] = width 231 | itemsWidths = widths 232 | } else { 233 | var widths = [CGFloat]() 234 | for i in 0 ..< childControllersCount { 235 | let newWidth = (i == index) ? width : menuItemWidth 236 | widths.append(newWidth) 237 | } 238 | itemsWidths = widths 239 | } 240 | menuView?.updateTitle(title, atIndex: index, andWidth: true) 241 | } 242 | 243 | // MARK: - Data Source 244 | fileprivate func initializeViewControllerAtIndex(_ index: Int) -> UIViewController { 245 | if let viewController = dataSource?.pageController?(self, viewControllerAtIndex: index) { 246 | return viewController 247 | } 248 | return viewControllerClasses![index].init() 249 | } 250 | 251 | fileprivate func titleAtIndex(_ index: Int) -> String { 252 | if let titleAtIndex = dataSource?.pageController?(self, titleAtIndex: index) { 253 | return titleAtIndex 254 | } 255 | return titles![index] 256 | } 257 | 258 | // MARK: - Delegate 259 | fileprivate func infoWithIndex(_ index: Int) -> NSDictionary { 260 | let title = titleAtIndex(index) 261 | return ["title": title, "index": index] 262 | } 263 | 264 | fileprivate func willCachedController(_ vc: UIViewController, atIndex index: Int) { 265 | guard childControllersCount > 0 else { return } 266 | delegate?.pageController?(self, willCachedViewController: vc, withInfo: infoWithIndex(index)) 267 | } 268 | 269 | fileprivate func willEnterController(_ vc: UIViewController, atIndex index: Int) { 270 | guard childControllersCount > 0 else { return } 271 | delegate?.pageController?(self, willEnterViewController: vc, withInfo: infoWithIndex(index)) 272 | } 273 | 274 | fileprivate func didEnterController(_ vc: UIViewController, atIndex index: Int) { 275 | 276 | guard childControllersCount > 0 else { return } 277 | 278 | let info = infoWithIndex(index) 279 | 280 | delegate?.pageController?(self, didEnterViewController: vc, withInfo: info) 281 | 282 | if initializedIndex == index { 283 | delegate?.pageController?(self, lazyLoadViewController: vc, withInfo: info) 284 | initializedIndex = -1 285 | } 286 | 287 | if preloadPolicy == .never { return } 288 | var start = 0 289 | var end = childControllersCount - 1 290 | if index > preloadPolicy.rawValue { 291 | start = index - preloadPolicy.rawValue 292 | } 293 | 294 | if childControllersCount - 1 > preloadPolicy.rawValue + index { 295 | end = index + preloadPolicy.rawValue 296 | } 297 | 298 | for i in start ... end { 299 | if memCache.object(forKey: NSNumber(integerLiteral: i)) == nil && displayingControllers[i] == nil { 300 | addViewControllerAtIndex(i) 301 | postMovedToSuperViewNotificationWithIndex(i) 302 | } 303 | } 304 | _selectedIndex = index 305 | } 306 | 307 | // MARK: - Private funcs 308 | fileprivate func clearDatas() { 309 | controllerCount = -1 310 | hasInit = false 311 | _selectedIndex = _selectedIndex < childControllersCount ? _selectedIndex : childControllersCount - 1 312 | for viewController in displayingControllers.allValues { 313 | if let vc = viewController as? UIViewController { 314 | vc.view.removeFromSuperview() 315 | vc.willMove(toParentViewController: nil) 316 | vc.removeFromParentViewController() 317 | } 318 | } 319 | memoryWarningCount = 0 320 | NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(PageController.growCachePolicyAfterMemoryWarning), object: nil) 321 | NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(PageController.growCachePolicyToHigh), object: nil) 322 | currentViewController = nil 323 | displayingControllers.removeAllObjects() 324 | calculateSize() 325 | } 326 | 327 | fileprivate func resetScrollView() { 328 | contentView?.removeFromSuperview() 329 | addScrollView() 330 | addViewControllerAtIndex(_selectedIndex) 331 | currentViewController = displayingControllers[_selectedIndex] as? UIViewController 332 | } 333 | 334 | fileprivate func calculateSize() { 335 | var navBarHeight = (navigationController != nil) ? navigationController!.navigationBar.frame.maxY : 0 336 | let tabBar = tabBarController?.tabBar ?? (navigationController?.toolbar ?? nil) 337 | let height = (tabBar != nil && tabBar?.isHidden != true) ? tabBar!.frame.height : 0 338 | var tabBarHeight = (hidesBottomBarWhenPushed == true) ? 0 : height 339 | 340 | let mainWindow = UIApplication.shared.delegate?.window! 341 | let absoluteRect = view.superview?.convert(view.frame, to: mainWindow) 342 | if let rect = absoluteRect { 343 | navBarHeight -= rect.origin.y; 344 | tabBarHeight -= mainWindow!.frame.height - rect.maxY; 345 | } 346 | 347 | viewX = viewFrame.origin.x 348 | viewY = viewFrame.origin.y 349 | if viewFrame == CGRect.zero { 350 | viewWidth = view.frame.size.width 351 | viewHeight = view.frame.size.height - menuHeight - navBarHeight - tabBarHeight 352 | viewY += navBarHeight 353 | } else { 354 | viewWidth = viewFrame.size.width 355 | viewHeight = viewFrame.size.height - menuHeight 356 | } 357 | if showOnNavigationBar && (navigationController?.navigationBar != nil) { 358 | viewHeight += menuHeight 359 | } 360 | childViewFrames.removeAll() 361 | for index in 0 ..< childControllersCount { 362 | let viewControllerFrame = CGRect(x: CGFloat(index) * viewWidth, y: 0, width: viewWidth, height: viewHeight) 363 | childViewFrames.append(viewControllerFrame) 364 | } 365 | } 366 | 367 | fileprivate func addScrollView() { 368 | let scrollView = ContentView() 369 | scrollView.scrollsToTop = false 370 | scrollView.isPagingEnabled = true 371 | scrollView.delegate = self 372 | scrollView.showsVerticalScrollIndicator = false 373 | scrollView.showsHorizontalScrollIndicator = false 374 | scrollView.bounces = bounces 375 | view.addSubview(scrollView) 376 | contentView = scrollView 377 | } 378 | 379 | fileprivate func addMenuView() { 380 | var menuY = viewY 381 | if showOnNavigationBar && (navigationController?.navigationBar != nil) { 382 | let naviHeight = navigationController!.navigationBar.frame.height 383 | let realMenuHeight = menuHeight > naviHeight ? naviHeight : menuHeight 384 | menuY = (naviHeight - realMenuHeight) / 2 385 | } 386 | 387 | let menuViewFrame = CGRect(x: viewX, y: menuY, width: viewWidth, height: menuHeight) 388 | let menu = MenuView(frame: menuViewFrame) 389 | menu.delegate = self 390 | menu.dataSource = self 391 | menu.backgroundColor = menuBGColor 392 | menu.normalSize = titleSizeNormal 393 | menu.selectedSize = titleSizeSelected 394 | menu.normalColor = titleColorNormal 395 | menu.selectedColor = titleColorSelected 396 | menu.style = menuViewStyle 397 | menu.progressHeight = progressHeight 398 | menu.progressColor = progressColor 399 | menu.fontName = titleFontName 400 | menu.contentMargin = menuViewContentMargin 401 | if showOnNavigationBar && (navigationController?.navigationBar != nil) { 402 | navigationItem.titleView = menu 403 | } else { 404 | view.addSubview(menu) 405 | } 406 | menuView = menu 407 | } 408 | 409 | fileprivate func postMovedToSuperViewNotificationWithIndex(_ index: Int) { 410 | guard postNotification else { return } 411 | let info = ["index": index, "title": titleAtIndex(index)] as [String : Any] 412 | NotificationCenter.default.post(name: Notification.Name(rawValue: WMPageControllerDidMovedToSuperViewNotification), object: info) 413 | } 414 | 415 | fileprivate func postFullyDisplayedNotificationWithIndex(_ index: Int) { 416 | guard postNotification else { return } 417 | let info = ["index": index, "title": titleAtIndex(index)] as [String : Any] 418 | NotificationCenter.default.post(name: Notification.Name(rawValue: WMPageControllerDidFullyDisplayedNotification), object: info) 419 | } 420 | 421 | fileprivate func layoutChildViewControllers() { 422 | let currentPage = Int(contentView!.contentOffset.x / viewWidth) 423 | let start = currentPage == 0 ? currentPage : (currentPage - 1) 424 | let end = (currentPage == childControllersCount - 1) ? currentPage : (currentPage + 1) 425 | for index in start ... end { 426 | let viewControllerFrame = childViewFrames[index] 427 | var vc = displayingControllers.object(forKey: index) 428 | if inScreen(viewControllerFrame) { 429 | if vc == nil { 430 | vc = memCache.object(forKey: NSNumber(integerLiteral: index)) 431 | if let viewController = vc as? UIViewController { 432 | addCachedViewController(viewController, atIndex: index) 433 | } else { 434 | addViewControllerAtIndex(index) 435 | } 436 | postMovedToSuperViewNotificationWithIndex(index) 437 | } 438 | } else { 439 | if let viewController = vc as? UIViewController { 440 | removeViewController(viewController, atIndex: index) 441 | } 442 | } 443 | } 444 | } 445 | 446 | fileprivate func removeSuperfluousViewControllersIfNeeded() { 447 | for (index, vc) in displayingControllers { 448 | 449 | let frame = childViewFrames[(index as AnyObject).intValue] 450 | if (inScreen(frame) == false) { 451 | removeViewController(vc as! UIViewController, atIndex: (index as AnyObject).intValue) 452 | } 453 | } 454 | } 455 | 456 | fileprivate func addCachedViewController(_ viewController: UIViewController, atIndex index: Int) { 457 | addChildViewController(viewController) 458 | viewController.view.frame = childViewFrames[index] 459 | viewController.didMove(toParentViewController: self) 460 | contentView?.addSubview(viewController.view) 461 | willEnterController(viewController, atIndex: index) 462 | displayingControllers.setObject(viewController, forKey: index as NSCopying) 463 | } 464 | 465 | fileprivate func addViewControllerAtIndex(_ index: Int) { 466 | initializedIndex = index 467 | let viewController = initializeViewControllerAtIndex(index) 468 | if let optionalKeys = keys { 469 | viewController.setValue(values?[index], forKey: optionalKeys[index]) 470 | } 471 | addChildViewController(viewController) 472 | viewController.view.frame = childViewFrames.count > 0 ? childViewFrames[index] : view.frame 473 | viewController.didMove(toParentViewController: self) 474 | contentView?.addSubview(viewController.view) 475 | willEnterController(viewController, atIndex: index) 476 | displayingControllers.setObject(viewController, forKey: index as NSCopying) 477 | } 478 | 479 | fileprivate func removeViewController(_ viewController: UIViewController, atIndex index: Int) { 480 | viewController.view.removeFromSuperview() 481 | viewController.willMove(toParentViewController: nil) 482 | viewController.removeFromParentViewController() 483 | displayingControllers.removeObject(forKey: index) 484 | if memCache.object(forKey: NSNumber(integerLiteral: index)) == nil { 485 | willCachedController(viewController, atIndex: index) 486 | memCache.setObject(viewController, forKey: NSNumber(integerLiteral: index)) 487 | } 488 | } 489 | 490 | fileprivate func inScreen(_ frame: CGRect) -> Bool { 491 | let x = frame.origin.x 492 | let ScreenWidth = contentView!.frame.size.width 493 | let contentOffsetX = contentView!.contentOffset.x 494 | if (frame.maxX > contentOffsetX) && (x - contentOffsetX < ScreenWidth) { 495 | return true 496 | } 497 | return false 498 | } 499 | 500 | fileprivate func resetMenuView() { 501 | if menuView == nil { 502 | addMenuView() 503 | return 504 | } 505 | menuView?.reload() 506 | guard selectedIndex != 0 else { return } 507 | menuView?.selectItemAtIndex(selectedIndex) 508 | view.bringSubview(toFront: menuView!) 509 | } 510 | 511 | @objc fileprivate func growCachePolicyAfterMemoryWarning() { 512 | cachePolicy = CachePolicy.balanced 513 | perform(#selector(PageController.growCachePolicyToHigh), with: nil, afterDelay: 2.0, inModes: [RunLoopMode.commonModes]) 514 | } 515 | 516 | @objc fileprivate func growCachePolicyToHigh() { 517 | cachePolicy = CachePolicy.high 518 | } 519 | 520 | // MARK: - Adjust Frame 521 | fileprivate func adjustScrollViewFrame() { 522 | shouldNotScroll = true 523 | var scrollFrame = CGRect(x: viewX, y: viewY + menuHeight, width: viewWidth, height: viewHeight) 524 | scrollFrame.origin.y -= showOnNavigationBar && (navigationController?.navigationBar != nil) ? menuHeight : 0 525 | contentView?.frame = scrollFrame 526 | contentView?.contentSize = CGSize(width: CGFloat(childControllersCount) * viewWidth, height: 0) 527 | contentView?.contentOffset = CGPoint(x: CGFloat(_selectedIndex) * viewWidth, y: 0) 528 | shouldNotScroll = false 529 | } 530 | 531 | fileprivate func adjustMenuViewFrame() { 532 | var realMenuHeight = menuHeight 533 | var menuX = viewX 534 | var menuY = viewY 535 | 536 | var rightWidth: CGFloat = 0.0 537 | if showOnNavigationBar && (navigationController?.navigationBar != nil) { 538 | for subview in (navigationController?.navigationBar.subviews)! { 539 | guard let UINavigationBarBackgroundClass = NSClassFromString("_UINavigationBarBackground") else { 540 | continue 541 | } 542 | 543 | guard !subview.isKind(of: UINavigationBarBackgroundClass) && !subview.isKind(of: MenuView.self) && (subview.alpha != 0) && (subview.isHidden == false) else { continue } 544 | 545 | let maxX = subview.frame.maxX 546 | if maxX < viewWidth / 2 { 547 | let leftWidth = maxX 548 | menuX = menuX > leftWidth ? menuX : leftWidth 549 | } 550 | let minX = subview.frame.minX 551 | if minX > viewWidth / 2 { 552 | let width = viewWidth - minX 553 | rightWidth = rightWidth > width ? rightWidth : width 554 | } 555 | 556 | } 557 | let naviHeight = navigationController!.navigationBar.frame.height 558 | realMenuHeight = menuHeight > naviHeight ? naviHeight : realMenuHeight 559 | menuY = (naviHeight - realMenuHeight) / 2 560 | } 561 | let menuWidth = viewWidth - menuX - rightWidth 562 | menuView?.frame = CGRect(x: menuX, y: menuY, width: menuWidth, height: realMenuHeight) 563 | menuView?.resetFrames() 564 | 565 | if _selectedIndex != 0 { 566 | menuView?.selectItemAtIndex(_selectedIndex) 567 | } 568 | } 569 | 570 | // MARK: - UIScrollView Delegate 571 | open func scrollViewDidScroll(_ scrollView: UIScrollView) { 572 | if shouldNotScroll || !hasInit { return } 573 | 574 | layoutChildViewControllers() 575 | guard startDragging else { return } 576 | var contentOffsetX = contentView!.contentOffset.x 577 | if contentOffsetX < 0.0 { 578 | contentOffsetX = 0.0 579 | } 580 | if contentOffsetX > (scrollView.contentSize.width - viewWidth) { 581 | contentOffsetX = scrollView.contentSize.width - viewWidth 582 | } 583 | let rate = contentOffsetX / viewWidth 584 | menuView?.slideMenuAtProgress(rate) 585 | 586 | if scrollView.contentOffset.y == 0 { return } 587 | var contentOffset = scrollView.contentOffset 588 | contentOffset.y = 0.0 589 | scrollView.contentOffset = contentOffset 590 | } 591 | 592 | open func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { 593 | startDragging = true 594 | menuView?.isUserInteractionEnabled = false 595 | } 596 | 597 | open func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { 598 | menuView?.isUserInteractionEnabled = true 599 | _selectedIndex = Int(contentView!.contentOffset.x / viewWidth) 600 | removeSuperfluousViewControllersIfNeeded() 601 | currentViewController = displayingControllers[_selectedIndex] as? UIViewController 602 | postFullyDisplayedNotificationWithIndex(_selectedIndex) 603 | didEnterController(currentViewController!, atIndex: _selectedIndex) 604 | } 605 | 606 | open func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) { 607 | _selectedIndex = Int(contentView!.contentOffset.x / viewWidth) 608 | removeSuperfluousViewControllersIfNeeded() 609 | currentViewController = displayingControllers[_selectedIndex] as? UIViewController 610 | postFullyDisplayedNotificationWithIndex(_selectedIndex) 611 | didEnterController(currentViewController!, atIndex: _selectedIndex) 612 | } 613 | 614 | open func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { 615 | guard decelerate == false else { return } 616 | menuView?.isUserInteractionEnabled = true 617 | let rate = targetX / viewWidth 618 | menuView?.slideMenuAtProgress(rate) 619 | } 620 | 621 | open func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) { 622 | targetX = targetContentOffset.pointee.x 623 | } 624 | 625 | // MARK: - MenuViewDelegate 626 | open func menuView(_ menuView: MenuView, didSelectedIndex index: Int, fromIndex currentIndex: Int) { 627 | guard hasInit else { return } 628 | startDragging = false 629 | let targetPoint = CGPoint(x: CGFloat(index) * viewWidth, y: 0) 630 | contentView?.setContentOffset(targetPoint, animated: pageAnimatable) 631 | if !pageAnimatable { 632 | removeSuperfluousViewControllersIfNeeded() 633 | if let viewController = displayingControllers[index] as? UIViewController { 634 | removeViewController(viewController, atIndex: index) 635 | } 636 | layoutChildViewControllers() 637 | currentViewController = displayingControllers[index] as? UIViewController 638 | postFullyDisplayedNotificationWithIndex(index) 639 | _selectedIndex = index 640 | didEnterController(currentViewController!, atIndex: _selectedIndex) 641 | } 642 | } 643 | 644 | open func menuView(_ menuView: MenuView, widthForItemAtIndex index: Int) -> CGFloat { 645 | if let widths = itemsWidths { 646 | return widths[index] 647 | } 648 | return menuItemWidth 649 | } 650 | 651 | open func menuView(_ menuView: MenuView, itemMarginAtIndex index: Int) -> CGFloat { 652 | if let margins = itemsMargins { 653 | return margins[index] 654 | } 655 | return itemMargin 656 | } 657 | 658 | // MARK: - MenuViewDataSource 659 | open func numbersOfTitlesInMenuView(_ menuView: MenuView) -> Int { 660 | return childControllersCount 661 | } 662 | 663 | open func menuView(_ menuView: MenuView, titleAtIndex index: Int) -> String { 664 | return titleAtIndex(index) 665 | } 666 | 667 | } 668 | -------------------------------------------------------------------------------- /PageController/ProgressView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProgressView.swift 3 | // PageController 4 | // 5 | // Created by Mark on 15/10/20. 6 | // Copyright © 2015年 Wecan Studio. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ProgressView: UIView { 12 | 13 | // MARK: - Public vars 14 | var itemFrames = [CGRect]() 15 | var progress: CGFloat = 0.0 { 16 | didSet { setNeedsDisplay() } 17 | } 18 | lazy var color: CGColor = UIColor.brown.cgColor 19 | 20 | // MARK: - Private vars 21 | weak fileprivate var link: CADisplayLink? 22 | fileprivate var gap: CGFloat = 0.0 23 | fileprivate var step: CGFloat = 0.0 24 | fileprivate var sign = 1 25 | 26 | // MARK: - Public funcs 27 | func moveToPosition(_ position: Int, animation: Bool) { 28 | if animation == false { 29 | progress = CGFloat(position) 30 | return 31 | } 32 | let pos = CGFloat(position) 33 | gap = fabs(progress - pos) 34 | sign = progress > pos ? -1 : 1 35 | step = gap / 15.0 36 | link?.remove(from: RunLoop.main, forMode: RunLoopMode.commonModes) 37 | let tempLink = CADisplayLink(target: self, selector: #selector(ProgressView.progressChanged)) 38 | tempLink.add(to: RunLoop.main, forMode: RunLoopMode.commonModes) 39 | link = tempLink 40 | } 41 | 42 | func progressChanged() { 43 | if gap > 0.000001 { 44 | gap -= step 45 | if gap < 0.0 { 46 | progress = blurredCeil(progress + CGFloat(sign) * step ) 47 | return 48 | } 49 | progress += CGFloat(sign) * step 50 | } else { 51 | progress = blurredCeil(progress) 52 | link?.invalidate() 53 | link = nil 54 | } 55 | } 56 | 57 | fileprivate func blurredCeil(_ num: CGFloat) -> CGFloat { 58 | let p = num + 0.5 59 | return floor(p) 60 | } 61 | 62 | // MARK: - Private funcs 63 | override func draw(_ rect: CGRect) { 64 | // Drawing code 65 | let ctx = UIGraphicsGetCurrentContext() 66 | let index = Int(progress) 67 | let rate = progress - CGFloat(index) 68 | let currentFrame = itemFrames[index] 69 | let currentWidth = currentFrame.size.width 70 | let nextIndex = (index + 1 < itemFrames.count) ? index + 1 : index 71 | let nextWidth = itemFrames[nextIndex].size.width 72 | let height = frame.size.height 73 | let constY = height / 2 74 | let currentX = currentFrame.origin.x 75 | let nextX = itemFrames[nextIndex].origin.x 76 | let startX = currentX + (nextX - currentX) * rate 77 | let endX = startX + currentWidth + (nextWidth - currentWidth) * rate 78 | ctx?.move(to: CGPoint(x: startX, y: constY)) 79 | ctx?.addLine(to: CGPoint(x: endX, y: constY)) 80 | ctx?.setLineWidth(height) 81 | ctx?.setStrokeColor(color) 82 | ctx?.strokePath() 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WMPageController-Swift 2 | [![Build Status](https://travis-ci.org/wangmchn/WMPageController-Swift.svg?branch=master)](https://travis-ci.org/wangmchn/WMPageController-Swift) 3 | [![Platform](http://img.shields.io/badge/platform-iOS-blue.svg?style=flat 4 | )](https://developer.apple.com/iphone/index.action) 5 | [![License](http://img.shields.io/badge/license-MIT-lightgrey.svg?style=flat 6 | )](http://mit-license.org) 7 | ![CocoaPods Version](https://img.shields.io/badge/pod-v0.36.4-brightgreen.svg) 8 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 9 | 10 | An easy solution to page controllers like NetEase News.(Swift Implementation)
11 | ## Objective-C Version 12 | Click here: https://github.com/wangmchn/WMPageController 13 | ## How to use 14 | [Objective-C README](https://github.com/wangmchn/WMPageController/blob/master/README.md) 15 | ## CocoaPods 16 | ``` 17 | pod 'WMPageController-Swift', '~> 1.3.3' 18 | ``` 19 | -------------------------------------------------------------------------------- /StoryboardExample/StoryboardExample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4DCCF83D1CE8558A00C31A07 /* FooldView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DCCF8381CE8558A00C31A07 /* FooldView.swift */; }; 11 | 4DCCF83E1CE8558A00C31A07 /* MenuItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DCCF8391CE8558A00C31A07 /* MenuItem.swift */; }; 12 | 4DCCF83F1CE8558A00C31A07 /* MenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DCCF83A1CE8558A00C31A07 /* MenuView.swift */; }; 13 | 4DCCF8401CE8558A00C31A07 /* PageController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DCCF83B1CE8558A00C31A07 /* PageController.swift */; }; 14 | 4DCCF8411CE8558A00C31A07 /* ProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DCCF83C1CE8558A00C31A07 /* ProgressView.swift */; }; 15 | 4DF0A9781C39847100731373 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DF0A9771C39847100731373 /* AppDelegate.swift */; }; 16 | 4DF0A97A1C39847100731373 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DF0A9791C39847100731373 /* ViewController.swift */; }; 17 | 4DF0A97D1C39847100731373 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4DF0A97B1C39847100731373 /* Main.storyboard */; }; 18 | 4DF0A97F1C39847100731373 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4DF0A97E1C39847100731373 /* Assets.xcassets */; }; 19 | 4DF0A9821C39847100731373 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4DF0A9801C39847100731373 /* LaunchScreen.storyboard */; }; 20 | 4DF0A98D1C39847100731373 /* StoryboardExampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DF0A98C1C39847100731373 /* StoryboardExampleTests.swift */; }; 21 | 4DF0A9981C39847100731373 /* StoryboardExampleUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DF0A9971C39847100731373 /* StoryboardExampleUITests.swift */; }; 22 | 4DF0A9B21C3984EB00731373 /* CustomPageController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DF0A9B11C3984EB00731373 /* CustomPageController.swift */; }; 23 | 4DF0A9B51C3986D600731373 /* TableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DF0A9B41C3986D600731373 /* TableViewController.swift */; }; 24 | /* End PBXBuildFile section */ 25 | 26 | /* Begin PBXContainerItemProxy section */ 27 | 4DF0A9891C39847100731373 /* PBXContainerItemProxy */ = { 28 | isa = PBXContainerItemProxy; 29 | containerPortal = 4DF0A96C1C39847100731373 /* Project object */; 30 | proxyType = 1; 31 | remoteGlobalIDString = 4DF0A9731C39847100731373; 32 | remoteInfo = StoryboardExample; 33 | }; 34 | 4DF0A9941C39847100731373 /* PBXContainerItemProxy */ = { 35 | isa = PBXContainerItemProxy; 36 | containerPortal = 4DF0A96C1C39847100731373 /* Project object */; 37 | proxyType = 1; 38 | remoteGlobalIDString = 4DF0A9731C39847100731373; 39 | remoteInfo = StoryboardExample; 40 | }; 41 | /* End PBXContainerItemProxy section */ 42 | 43 | /* Begin PBXFileReference section */ 44 | 4DCCF8381CE8558A00C31A07 /* FooldView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FooldView.swift; sourceTree = ""; }; 45 | 4DCCF8391CE8558A00C31A07 /* MenuItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuItem.swift; sourceTree = ""; }; 46 | 4DCCF83A1CE8558A00C31A07 /* MenuView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuView.swift; sourceTree = ""; }; 47 | 4DCCF83B1CE8558A00C31A07 /* PageController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PageController.swift; sourceTree = ""; }; 48 | 4DCCF83C1CE8558A00C31A07 /* ProgressView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressView.swift; sourceTree = ""; }; 49 | 4DF0A9741C39847100731373 /* StoryboardExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = StoryboardExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 50 | 4DF0A9771C39847100731373 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 51 | 4DF0A9791C39847100731373 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 52 | 4DF0A97C1C39847100731373 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 53 | 4DF0A97E1C39847100731373 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 54 | 4DF0A9811C39847100731373 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 55 | 4DF0A9831C39847100731373 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 56 | 4DF0A9881C39847100731373 /* StoryboardExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = StoryboardExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 57 | 4DF0A98C1C39847100731373 /* StoryboardExampleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoryboardExampleTests.swift; sourceTree = ""; }; 58 | 4DF0A98E1C39847100731373 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 59 | 4DF0A9931C39847100731373 /* StoryboardExampleUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = StoryboardExampleUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 60 | 4DF0A9971C39847100731373 /* StoryboardExampleUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoryboardExampleUITests.swift; sourceTree = ""; }; 61 | 4DF0A9991C39847100731373 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 62 | 4DF0A9B11C3984EB00731373 /* CustomPageController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CustomPageController.swift; path = ParentController/CustomPageController.swift; sourceTree = ""; }; 63 | 4DF0A9B41C3986D600731373 /* TableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableViewController.swift; sourceTree = ""; }; 64 | /* End PBXFileReference section */ 65 | 66 | /* Begin PBXFrameworksBuildPhase section */ 67 | 4DF0A9711C39847100731373 /* Frameworks */ = { 68 | isa = PBXFrameworksBuildPhase; 69 | buildActionMask = 2147483647; 70 | files = ( 71 | ); 72 | runOnlyForDeploymentPostprocessing = 0; 73 | }; 74 | 4DF0A9851C39847100731373 /* Frameworks */ = { 75 | isa = PBXFrameworksBuildPhase; 76 | buildActionMask = 2147483647; 77 | files = ( 78 | ); 79 | runOnlyForDeploymentPostprocessing = 0; 80 | }; 81 | 4DF0A9901C39847100731373 /* Frameworks */ = { 82 | isa = PBXFrameworksBuildPhase; 83 | buildActionMask = 2147483647; 84 | files = ( 85 | ); 86 | runOnlyForDeploymentPostprocessing = 0; 87 | }; 88 | /* End PBXFrameworksBuildPhase section */ 89 | 90 | /* Begin PBXGroup section */ 91 | 4DCCF8371CE8558A00C31A07 /* PageController */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 4DCCF8381CE8558A00C31A07 /* FooldView.swift */, 95 | 4DCCF8391CE8558A00C31A07 /* MenuItem.swift */, 96 | 4DCCF83A1CE8558A00C31A07 /* MenuView.swift */, 97 | 4DCCF83B1CE8558A00C31A07 /* PageController.swift */, 98 | 4DCCF83C1CE8558A00C31A07 /* ProgressView.swift */, 99 | ); 100 | name = PageController; 101 | path = ../../PageController; 102 | sourceTree = ""; 103 | }; 104 | 4DF0A96B1C39847100731373 = { 105 | isa = PBXGroup; 106 | children = ( 107 | 4DF0A9761C39847100731373 /* StoryboardExample */, 108 | 4DF0A98B1C39847100731373 /* StoryboardExampleTests */, 109 | 4DF0A9961C39847100731373 /* StoryboardExampleUITests */, 110 | 4DF0A9751C39847100731373 /* Products */, 111 | ); 112 | sourceTree = ""; 113 | }; 114 | 4DF0A9751C39847100731373 /* Products */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | 4DF0A9741C39847100731373 /* StoryboardExample.app */, 118 | 4DF0A9881C39847100731373 /* StoryboardExampleTests.xctest */, 119 | 4DF0A9931C39847100731373 /* StoryboardExampleUITests.xctest */, 120 | ); 121 | name = Products; 122 | sourceTree = ""; 123 | }; 124 | 4DF0A9761C39847100731373 /* StoryboardExample */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | 4DCCF8371CE8558A00C31A07 /* PageController */, 128 | 4DF0A9B31C3986B800731373 /* ChildControllers */, 129 | 4DF0A9B01C3984BA00731373 /* ParentController */, 130 | 4DF0A9771C39847100731373 /* AppDelegate.swift */, 131 | 4DF0A97B1C39847100731373 /* Main.storyboard */, 132 | 4DF0A97E1C39847100731373 /* Assets.xcassets */, 133 | 4DF0A9801C39847100731373 /* LaunchScreen.storyboard */, 134 | 4DF0A9831C39847100731373 /* Info.plist */, 135 | ); 136 | path = StoryboardExample; 137 | sourceTree = ""; 138 | }; 139 | 4DF0A98B1C39847100731373 /* StoryboardExampleTests */ = { 140 | isa = PBXGroup; 141 | children = ( 142 | 4DF0A98C1C39847100731373 /* StoryboardExampleTests.swift */, 143 | 4DF0A98E1C39847100731373 /* Info.plist */, 144 | ); 145 | path = StoryboardExampleTests; 146 | sourceTree = ""; 147 | }; 148 | 4DF0A9961C39847100731373 /* StoryboardExampleUITests */ = { 149 | isa = PBXGroup; 150 | children = ( 151 | 4DF0A9971C39847100731373 /* StoryboardExampleUITests.swift */, 152 | 4DF0A9991C39847100731373 /* Info.plist */, 153 | ); 154 | path = StoryboardExampleUITests; 155 | sourceTree = ""; 156 | }; 157 | 4DF0A9B01C3984BA00731373 /* ParentController */ = { 158 | isa = PBXGroup; 159 | children = ( 160 | 4DF0A9B11C3984EB00731373 /* CustomPageController.swift */, 161 | ); 162 | name = ParentController; 163 | sourceTree = ""; 164 | }; 165 | 4DF0A9B31C3986B800731373 /* ChildControllers */ = { 166 | isa = PBXGroup; 167 | children = ( 168 | 4DF0A9791C39847100731373 /* ViewController.swift */, 169 | 4DF0A9B41C3986D600731373 /* TableViewController.swift */, 170 | ); 171 | name = ChildControllers; 172 | sourceTree = ""; 173 | }; 174 | /* End PBXGroup section */ 175 | 176 | /* Begin PBXNativeTarget section */ 177 | 4DF0A9731C39847100731373 /* StoryboardExample */ = { 178 | isa = PBXNativeTarget; 179 | buildConfigurationList = 4DF0A99C1C39847100731373 /* Build configuration list for PBXNativeTarget "StoryboardExample" */; 180 | buildPhases = ( 181 | 4DF0A9701C39847100731373 /* Sources */, 182 | 4DF0A9711C39847100731373 /* Frameworks */, 183 | 4DF0A9721C39847100731373 /* Resources */, 184 | ); 185 | buildRules = ( 186 | ); 187 | dependencies = ( 188 | ); 189 | name = StoryboardExample; 190 | productName = StoryboardExample; 191 | productReference = 4DF0A9741C39847100731373 /* StoryboardExample.app */; 192 | productType = "com.apple.product-type.application"; 193 | }; 194 | 4DF0A9871C39847100731373 /* StoryboardExampleTests */ = { 195 | isa = PBXNativeTarget; 196 | buildConfigurationList = 4DF0A99F1C39847100731373 /* Build configuration list for PBXNativeTarget "StoryboardExampleTests" */; 197 | buildPhases = ( 198 | 4DF0A9841C39847100731373 /* Sources */, 199 | 4DF0A9851C39847100731373 /* Frameworks */, 200 | 4DF0A9861C39847100731373 /* Resources */, 201 | ); 202 | buildRules = ( 203 | ); 204 | dependencies = ( 205 | 4DF0A98A1C39847100731373 /* PBXTargetDependency */, 206 | ); 207 | name = StoryboardExampleTests; 208 | productName = StoryboardExampleTests; 209 | productReference = 4DF0A9881C39847100731373 /* StoryboardExampleTests.xctest */; 210 | productType = "com.apple.product-type.bundle.unit-test"; 211 | }; 212 | 4DF0A9921C39847100731373 /* StoryboardExampleUITests */ = { 213 | isa = PBXNativeTarget; 214 | buildConfigurationList = 4DF0A9A21C39847100731373 /* Build configuration list for PBXNativeTarget "StoryboardExampleUITests" */; 215 | buildPhases = ( 216 | 4DF0A98F1C39847100731373 /* Sources */, 217 | 4DF0A9901C39847100731373 /* Frameworks */, 218 | 4DF0A9911C39847100731373 /* Resources */, 219 | ); 220 | buildRules = ( 221 | ); 222 | dependencies = ( 223 | 4DF0A9951C39847100731373 /* PBXTargetDependency */, 224 | ); 225 | name = StoryboardExampleUITests; 226 | productName = StoryboardExampleUITests; 227 | productReference = 4DF0A9931C39847100731373 /* StoryboardExampleUITests.xctest */; 228 | productType = "com.apple.product-type.bundle.ui-testing"; 229 | }; 230 | /* End PBXNativeTarget section */ 231 | 232 | /* Begin PBXProject section */ 233 | 4DF0A96C1C39847100731373 /* Project object */ = { 234 | isa = PBXProject; 235 | attributes = { 236 | LastSwiftUpdateCheck = 0720; 237 | LastUpgradeCheck = 0720; 238 | ORGANIZATIONNAME = "Wecan Studio"; 239 | TargetAttributes = { 240 | 4DF0A9731C39847100731373 = { 241 | CreatedOnToolsVersion = 7.2; 242 | }; 243 | 4DF0A9871C39847100731373 = { 244 | CreatedOnToolsVersion = 7.2; 245 | TestTargetID = 4DF0A9731C39847100731373; 246 | }; 247 | 4DF0A9921C39847100731373 = { 248 | CreatedOnToolsVersion = 7.2; 249 | TestTargetID = 4DF0A9731C39847100731373; 250 | }; 251 | }; 252 | }; 253 | buildConfigurationList = 4DF0A96F1C39847100731373 /* Build configuration list for PBXProject "StoryboardExample" */; 254 | compatibilityVersion = "Xcode 3.2"; 255 | developmentRegion = English; 256 | hasScannedForEncodings = 0; 257 | knownRegions = ( 258 | en, 259 | Base, 260 | ); 261 | mainGroup = 4DF0A96B1C39847100731373; 262 | productRefGroup = 4DF0A9751C39847100731373 /* Products */; 263 | projectDirPath = ""; 264 | projectRoot = ""; 265 | targets = ( 266 | 4DF0A9731C39847100731373 /* StoryboardExample */, 267 | 4DF0A9871C39847100731373 /* StoryboardExampleTests */, 268 | 4DF0A9921C39847100731373 /* StoryboardExampleUITests */, 269 | ); 270 | }; 271 | /* End PBXProject section */ 272 | 273 | /* Begin PBXResourcesBuildPhase section */ 274 | 4DF0A9721C39847100731373 /* Resources */ = { 275 | isa = PBXResourcesBuildPhase; 276 | buildActionMask = 2147483647; 277 | files = ( 278 | 4DF0A9821C39847100731373 /* LaunchScreen.storyboard in Resources */, 279 | 4DF0A97F1C39847100731373 /* Assets.xcassets in Resources */, 280 | 4DF0A97D1C39847100731373 /* Main.storyboard in Resources */, 281 | ); 282 | runOnlyForDeploymentPostprocessing = 0; 283 | }; 284 | 4DF0A9861C39847100731373 /* Resources */ = { 285 | isa = PBXResourcesBuildPhase; 286 | buildActionMask = 2147483647; 287 | files = ( 288 | ); 289 | runOnlyForDeploymentPostprocessing = 0; 290 | }; 291 | 4DF0A9911C39847100731373 /* Resources */ = { 292 | isa = PBXResourcesBuildPhase; 293 | buildActionMask = 2147483647; 294 | files = ( 295 | ); 296 | runOnlyForDeploymentPostprocessing = 0; 297 | }; 298 | /* End PBXResourcesBuildPhase section */ 299 | 300 | /* Begin PBXSourcesBuildPhase section */ 301 | 4DF0A9701C39847100731373 /* Sources */ = { 302 | isa = PBXSourcesBuildPhase; 303 | buildActionMask = 2147483647; 304 | files = ( 305 | 4DCCF83F1CE8558A00C31A07 /* MenuView.swift in Sources */, 306 | 4DF0A9B21C3984EB00731373 /* CustomPageController.swift in Sources */, 307 | 4DCCF83D1CE8558A00C31A07 /* FooldView.swift in Sources */, 308 | 4DCCF8401CE8558A00C31A07 /* PageController.swift in Sources */, 309 | 4DF0A97A1C39847100731373 /* ViewController.swift in Sources */, 310 | 4DF0A9B51C3986D600731373 /* TableViewController.swift in Sources */, 311 | 4DCCF83E1CE8558A00C31A07 /* MenuItem.swift in Sources */, 312 | 4DCCF8411CE8558A00C31A07 /* ProgressView.swift in Sources */, 313 | 4DF0A9781C39847100731373 /* AppDelegate.swift in Sources */, 314 | ); 315 | runOnlyForDeploymentPostprocessing = 0; 316 | }; 317 | 4DF0A9841C39847100731373 /* Sources */ = { 318 | isa = PBXSourcesBuildPhase; 319 | buildActionMask = 2147483647; 320 | files = ( 321 | 4DF0A98D1C39847100731373 /* StoryboardExampleTests.swift in Sources */, 322 | ); 323 | runOnlyForDeploymentPostprocessing = 0; 324 | }; 325 | 4DF0A98F1C39847100731373 /* Sources */ = { 326 | isa = PBXSourcesBuildPhase; 327 | buildActionMask = 2147483647; 328 | files = ( 329 | 4DF0A9981C39847100731373 /* StoryboardExampleUITests.swift in Sources */, 330 | ); 331 | runOnlyForDeploymentPostprocessing = 0; 332 | }; 333 | /* End PBXSourcesBuildPhase section */ 334 | 335 | /* Begin PBXTargetDependency section */ 336 | 4DF0A98A1C39847100731373 /* PBXTargetDependency */ = { 337 | isa = PBXTargetDependency; 338 | target = 4DF0A9731C39847100731373 /* StoryboardExample */; 339 | targetProxy = 4DF0A9891C39847100731373 /* PBXContainerItemProxy */; 340 | }; 341 | 4DF0A9951C39847100731373 /* PBXTargetDependency */ = { 342 | isa = PBXTargetDependency; 343 | target = 4DF0A9731C39847100731373 /* StoryboardExample */; 344 | targetProxy = 4DF0A9941C39847100731373 /* PBXContainerItemProxy */; 345 | }; 346 | /* End PBXTargetDependency section */ 347 | 348 | /* Begin PBXVariantGroup section */ 349 | 4DF0A97B1C39847100731373 /* Main.storyboard */ = { 350 | isa = PBXVariantGroup; 351 | children = ( 352 | 4DF0A97C1C39847100731373 /* Base */, 353 | ); 354 | name = Main.storyboard; 355 | sourceTree = ""; 356 | }; 357 | 4DF0A9801C39847100731373 /* LaunchScreen.storyboard */ = { 358 | isa = PBXVariantGroup; 359 | children = ( 360 | 4DF0A9811C39847100731373 /* Base */, 361 | ); 362 | name = LaunchScreen.storyboard; 363 | sourceTree = ""; 364 | }; 365 | /* End PBXVariantGroup section */ 366 | 367 | /* Begin XCBuildConfiguration section */ 368 | 4DF0A99A1C39847100731373 /* Debug */ = { 369 | isa = XCBuildConfiguration; 370 | buildSettings = { 371 | ALWAYS_SEARCH_USER_PATHS = NO; 372 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 373 | CLANG_CXX_LIBRARY = "libc++"; 374 | CLANG_ENABLE_MODULES = YES; 375 | CLANG_ENABLE_OBJC_ARC = YES; 376 | CLANG_WARN_BOOL_CONVERSION = YES; 377 | CLANG_WARN_CONSTANT_CONVERSION = YES; 378 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 379 | CLANG_WARN_EMPTY_BODY = YES; 380 | CLANG_WARN_ENUM_CONVERSION = YES; 381 | CLANG_WARN_INT_CONVERSION = YES; 382 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 383 | CLANG_WARN_UNREACHABLE_CODE = YES; 384 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 385 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 386 | COPY_PHASE_STRIP = NO; 387 | DEBUG_INFORMATION_FORMAT = dwarf; 388 | ENABLE_STRICT_OBJC_MSGSEND = YES; 389 | ENABLE_TESTABILITY = YES; 390 | GCC_C_LANGUAGE_STANDARD = gnu99; 391 | GCC_DYNAMIC_NO_PIC = NO; 392 | GCC_NO_COMMON_BLOCKS = YES; 393 | GCC_OPTIMIZATION_LEVEL = 0; 394 | GCC_PREPROCESSOR_DEFINITIONS = ( 395 | "DEBUG=1", 396 | "$(inherited)", 397 | ); 398 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 399 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 400 | GCC_WARN_UNDECLARED_SELECTOR = YES; 401 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 402 | GCC_WARN_UNUSED_FUNCTION = YES; 403 | GCC_WARN_UNUSED_VARIABLE = YES; 404 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 405 | MTL_ENABLE_DEBUG_INFO = YES; 406 | ONLY_ACTIVE_ARCH = YES; 407 | SDKROOT = iphoneos; 408 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 409 | }; 410 | name = Debug; 411 | }; 412 | 4DF0A99B1C39847100731373 /* Release */ = { 413 | isa = XCBuildConfiguration; 414 | buildSettings = { 415 | ALWAYS_SEARCH_USER_PATHS = NO; 416 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 417 | CLANG_CXX_LIBRARY = "libc++"; 418 | CLANG_ENABLE_MODULES = YES; 419 | CLANG_ENABLE_OBJC_ARC = YES; 420 | CLANG_WARN_BOOL_CONVERSION = YES; 421 | CLANG_WARN_CONSTANT_CONVERSION = YES; 422 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 423 | CLANG_WARN_EMPTY_BODY = YES; 424 | CLANG_WARN_ENUM_CONVERSION = YES; 425 | CLANG_WARN_INT_CONVERSION = YES; 426 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 427 | CLANG_WARN_UNREACHABLE_CODE = YES; 428 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 429 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 430 | COPY_PHASE_STRIP = NO; 431 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 432 | ENABLE_NS_ASSERTIONS = NO; 433 | ENABLE_STRICT_OBJC_MSGSEND = YES; 434 | GCC_C_LANGUAGE_STANDARD = gnu99; 435 | GCC_NO_COMMON_BLOCKS = YES; 436 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 437 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 438 | GCC_WARN_UNDECLARED_SELECTOR = YES; 439 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 440 | GCC_WARN_UNUSED_FUNCTION = YES; 441 | GCC_WARN_UNUSED_VARIABLE = YES; 442 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 443 | MTL_ENABLE_DEBUG_INFO = NO; 444 | SDKROOT = iphoneos; 445 | VALIDATE_PRODUCT = YES; 446 | }; 447 | name = Release; 448 | }; 449 | 4DF0A99D1C39847100731373 /* Debug */ = { 450 | isa = XCBuildConfiguration; 451 | buildSettings = { 452 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 453 | INFOPLIST_FILE = StoryboardExample/Info.plist; 454 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 455 | PRODUCT_BUNDLE_IDENTIFIER = com.wecan.StoryboardExample; 456 | PRODUCT_NAME = "$(TARGET_NAME)"; 457 | }; 458 | name = Debug; 459 | }; 460 | 4DF0A99E1C39847100731373 /* Release */ = { 461 | isa = XCBuildConfiguration; 462 | buildSettings = { 463 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 464 | INFOPLIST_FILE = StoryboardExample/Info.plist; 465 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 466 | PRODUCT_BUNDLE_IDENTIFIER = com.wecan.StoryboardExample; 467 | PRODUCT_NAME = "$(TARGET_NAME)"; 468 | }; 469 | name = Release; 470 | }; 471 | 4DF0A9A01C39847100731373 /* Debug */ = { 472 | isa = XCBuildConfiguration; 473 | buildSettings = { 474 | BUNDLE_LOADER = "$(TEST_HOST)"; 475 | INFOPLIST_FILE = StoryboardExampleTests/Info.plist; 476 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 477 | PRODUCT_BUNDLE_IDENTIFIER = com.wecan.StoryboardExampleTests; 478 | PRODUCT_NAME = "$(TARGET_NAME)"; 479 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/StoryboardExample.app/StoryboardExample"; 480 | }; 481 | name = Debug; 482 | }; 483 | 4DF0A9A11C39847100731373 /* Release */ = { 484 | isa = XCBuildConfiguration; 485 | buildSettings = { 486 | BUNDLE_LOADER = "$(TEST_HOST)"; 487 | INFOPLIST_FILE = StoryboardExampleTests/Info.plist; 488 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 489 | PRODUCT_BUNDLE_IDENTIFIER = com.wecan.StoryboardExampleTests; 490 | PRODUCT_NAME = "$(TARGET_NAME)"; 491 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/StoryboardExample.app/StoryboardExample"; 492 | }; 493 | name = Release; 494 | }; 495 | 4DF0A9A31C39847100731373 /* Debug */ = { 496 | isa = XCBuildConfiguration; 497 | buildSettings = { 498 | INFOPLIST_FILE = StoryboardExampleUITests/Info.plist; 499 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 500 | PRODUCT_BUNDLE_IDENTIFIER = com.wecan.StoryboardExampleUITests; 501 | PRODUCT_NAME = "$(TARGET_NAME)"; 502 | TEST_TARGET_NAME = StoryboardExample; 503 | USES_XCTRUNNER = YES; 504 | }; 505 | name = Debug; 506 | }; 507 | 4DF0A9A41C39847100731373 /* Release */ = { 508 | isa = XCBuildConfiguration; 509 | buildSettings = { 510 | INFOPLIST_FILE = StoryboardExampleUITests/Info.plist; 511 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 512 | PRODUCT_BUNDLE_IDENTIFIER = com.wecan.StoryboardExampleUITests; 513 | PRODUCT_NAME = "$(TARGET_NAME)"; 514 | TEST_TARGET_NAME = StoryboardExample; 515 | USES_XCTRUNNER = YES; 516 | }; 517 | name = Release; 518 | }; 519 | /* End XCBuildConfiguration section */ 520 | 521 | /* Begin XCConfigurationList section */ 522 | 4DF0A96F1C39847100731373 /* Build configuration list for PBXProject "StoryboardExample" */ = { 523 | isa = XCConfigurationList; 524 | buildConfigurations = ( 525 | 4DF0A99A1C39847100731373 /* Debug */, 526 | 4DF0A99B1C39847100731373 /* Release */, 527 | ); 528 | defaultConfigurationIsVisible = 0; 529 | defaultConfigurationName = Release; 530 | }; 531 | 4DF0A99C1C39847100731373 /* Build configuration list for PBXNativeTarget "StoryboardExample" */ = { 532 | isa = XCConfigurationList; 533 | buildConfigurations = ( 534 | 4DF0A99D1C39847100731373 /* Debug */, 535 | 4DF0A99E1C39847100731373 /* Release */, 536 | ); 537 | defaultConfigurationIsVisible = 0; 538 | defaultConfigurationName = Release; 539 | }; 540 | 4DF0A99F1C39847100731373 /* Build configuration list for PBXNativeTarget "StoryboardExampleTests" */ = { 541 | isa = XCConfigurationList; 542 | buildConfigurations = ( 543 | 4DF0A9A01C39847100731373 /* Debug */, 544 | 4DF0A9A11C39847100731373 /* Release */, 545 | ); 546 | defaultConfigurationIsVisible = 0; 547 | defaultConfigurationName = Release; 548 | }; 549 | 4DF0A9A21C39847100731373 /* Build configuration list for PBXNativeTarget "StoryboardExampleUITests" */ = { 550 | isa = XCConfigurationList; 551 | buildConfigurations = ( 552 | 4DF0A9A31C39847100731373 /* Debug */, 553 | 4DF0A9A41C39847100731373 /* Release */, 554 | ); 555 | defaultConfigurationIsVisible = 0; 556 | defaultConfigurationName = Release; 557 | }; 558 | /* End XCConfigurationList section */ 559 | }; 560 | rootObject = 4DF0A96C1C39847100731373 /* Project object */; 561 | } 562 | -------------------------------------------------------------------------------- /StoryboardExample/StoryboardExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /StoryboardExample/StoryboardExample.xcodeproj/project.xcworkspace/xcuserdata/Mark.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangmchn/WMPageController-Swift/4c68bdc69568c02809b06e1c403050ecb967ac46/StoryboardExample/StoryboardExample.xcodeproj/project.xcworkspace/xcuserdata/Mark.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /StoryboardExample/StoryboardExample.xcodeproj/xcshareddata/xcschemes/StoryboardExample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /StoryboardExample/StoryboardExample.xcodeproj/xcuserdata/Mark.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /StoryboardExample/StoryboardExample.xcodeproj/xcuserdata/Mark.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | StoryboardExample.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 4DF0A9731C39847100731373 16 | 17 | primary 18 | 19 | 20 | 4DF0A9871C39847100731373 21 | 22 | primary 23 | 24 | 25 | 4DF0A9921C39847100731373 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /StoryboardExample/StoryboardExample/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // StoryboardExample 4 | // 5 | // Created by Mark on 16/1/4. 6 | // Copyright © 2016年 Wecan Studio. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 18 | // Override point for customization after application launch. 19 | self.window?.backgroundColor = .whiteColor() 20 | return true 21 | } 22 | 23 | func applicationWillResignActive(application: UIApplication) { 24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | func applicationDidEnterBackground(application: UIApplication) { 29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | func applicationWillEnterForeground(application: UIApplication) { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | func applicationDidBecomeActive(application: UIApplication) { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | func applicationWillTerminate(application: UIApplication) { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | 46 | } 47 | 48 | -------------------------------------------------------------------------------- /StoryboardExample/StoryboardExample/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /StoryboardExample/StoryboardExample/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /StoryboardExample/StoryboardExample/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /StoryboardExample/StoryboardExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /StoryboardExample/StoryboardExample/ParentController/CustomPageController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CustomPageController.swift 3 | // StoryboardExample 4 | // 5 | // Created by Mark on 16/1/4. 6 | // Copyright © 2016年 Wecan Studio. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class CustomPageController: PageController { 12 | 13 | var vcTitles = ["use", "storyboard", "xib"] 14 | 15 | required init?(coder aDecoder: NSCoder) { 16 | super.init(coder: aDecoder) 17 | dataSource = self 18 | delegate = self 19 | preloadPolicy = PreloadPolicy.Neighbour 20 | menuViewContentMargin = 10 21 | } 22 | 23 | override func viewDidLoad() { 24 | super.viewDidLoad() 25 | 26 | // Do any additional setup after loading the view. 27 | menuView?.leftView = customButtonWithTitle("Left") 28 | menuView?.rightView = customButtonWithTitle("Right") 29 | 30 | let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(5.0 * Double(NSEC_PER_SEC))) 31 | dispatch_after(delayTime, dispatch_get_main_queue()) { 32 | self.vcTitles = ["Test", "Test", "Test", "Test", "Test", "Test"] 33 | self.reloadData() 34 | } 35 | } 36 | 37 | private func customButtonWithTitle(title: String) -> UIButton { 38 | let button = UIButton(frame: CGRect(x: 0, y: 0, width: 60, height: menuHeight)) 39 | button.addTarget(self, action: #selector(CustomPageController.buttonPressed(_:)), forControlEvents: UIControlEvents.TouchUpInside) 40 | button.setTitle(title, forState: UIControlState.Normal) 41 | button.setTitleColor(.blueColor(), forState: UIControlState.Normal) 42 | return button 43 | } 44 | 45 | @objc private func buttonPressed(sender: UIButton) { 46 | print(sender) 47 | } 48 | 49 | override func didReceiveMemoryWarning() { 50 | super.didReceiveMemoryWarning() 51 | // Dispose of any resources that can be recreated. 52 | } 53 | 54 | // MARK: - PageController DataSource 55 | func numberOfControllersInPageController(pageController: PageController) -> Int { 56 | return vcTitles.count 57 | } 58 | 59 | func pageController(pageController: PageController, titleAtIndex index: Int) -> String { 60 | return vcTitles[index] 61 | } 62 | 63 | func pageController(pageController: PageController, viewControllerAtIndex index: Int) -> UIViewController { 64 | let sb = UIStoryboard(name: "Main", bundle: nil) 65 | switch index { 66 | case 0: return sb.instantiateViewControllerWithIdentifier("ViewController") 67 | case 1: return sb.instantiateViewControllerWithIdentifier("TableViewController") 68 | default: return UIViewController() 69 | } 70 | } 71 | 72 | func pageController(pageController: PageController, lazyLoadViewController viewController: UIViewController, withInfo info: NSDictionary) { 73 | print(info) 74 | } 75 | 76 | override func menuView(menuView: MenuView, widthForItemAtIndex index: Int) -> CGFloat { 77 | if index == 1 { 78 | return 100 79 | } 80 | return 60 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /StoryboardExample/StoryboardExample/TableViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TableViewController.swift 3 | // StoryboardExample 4 | // 5 | // Created by Mark on 16/1/4. 6 | // Copyright © 2016年 Wecan Studio. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class TableViewController: UITableViewController { 12 | 13 | let reuseIdentifier = "reuseIdentifier" 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | 17 | tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: reuseIdentifier) 18 | } 19 | 20 | override func didReceiveMemoryWarning() { 21 | super.didReceiveMemoryWarning() 22 | // Dispose of any resources that can be recreated. 23 | } 24 | 25 | // MARK: - Table view data source 26 | 27 | override func numberOfSectionsInTableView(tableView: UITableView) -> Int { 28 | return 1 29 | } 30 | 31 | override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 32 | return 100 33 | } 34 | 35 | override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 36 | let cell = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier, forIndexPath: indexPath) 37 | cell.textLabel?.text = "This is a TableViewController from Storyboard" 38 | cell.textLabel?.font = UIFont.systemFontOfSize(15) 39 | return cell 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /StoryboardExample/StoryboardExample/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // StoryboardExample 4 | // 5 | // Created by Mark on 16/1/4. 6 | // Copyright © 2016年 Wecan Studio. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | // Do any additional setup after loading the view, typically from a nib. 16 | } 17 | 18 | override func didReceiveMemoryWarning() { 19 | super.didReceiveMemoryWarning() 20 | // Dispose of any resources that can be recreated. 21 | } 22 | 23 | 24 | } 25 | 26 | -------------------------------------------------------------------------------- /StoryboardExample/StoryboardExampleTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /StoryboardExample/StoryboardExampleTests/StoryboardExampleTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StoryboardExampleTests.swift 3 | // StoryboardExampleTests 4 | // 5 | // Created by Mark on 16/1/4. 6 | // Copyright © 2016年 Wecan Studio. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import StoryboardExample 11 | 12 | class StoryboardExampleTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measureBlock { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /StoryboardExample/StoryboardExampleUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /StoryboardExample/StoryboardExampleUITests/StoryboardExampleUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StoryboardExampleUITests.swift 3 | // StoryboardExampleUITests 4 | // 5 | // Created by Mark on 16/1/4. 6 | // Copyright © 2016年 Wecan Studio. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class StoryboardExampleUITests: XCTestCase { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | 18 | // In UI tests it is usually best to stop immediately when a failure occurs. 19 | continueAfterFailure = false 20 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 21 | XCUIApplication().launch() 22 | 23 | // In UI tests it’s 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. 24 | } 25 | 26 | override func tearDown() { 27 | // Put teardown code here. This method is called after the invocation of each test method in the class. 28 | super.tearDown() 29 | } 30 | 31 | func testExample() { 32 | // Use recording to get started writing UI tests. 33 | // Use XCTAssert and related functions to verify your tests produce the correct results. 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /WMPageController-Swift.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "WMPageController-Swift" 3 | s.version = "1.4.0" 4 | s.summary = "An easy solution to page controllers like NetEase News.(Swift Implementation)" 5 | s.homepage = "https://github.com/wangmchn/WMPageController-Swift" 6 | s.license = 'MIT (LICENSE)' 7 | s.author = { "wangmchn" => "wangmchn@163.com" } 8 | s.source = { :git => "https://github.com/wangmchn/WMPageController-Swift.git", :tag => "1.4.0" } 9 | s.platform = :ios, '8.0' 10 | 11 | s.source_files = 'PageController', 'PageController/**/*.{swift}' 12 | s.exclude_files = 'Example' 13 | 14 | s.frameworks = 'Foundation', 'CoreGraphics', 'UIKit' 15 | s.requires_arc = true 16 | end -------------------------------------------------------------------------------- /WMPageController-Swift.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4D45BF191CC7A10B003F0151 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D45BF181CC7A10B003F0151 /* AppDelegate.swift */; }; 11 | 4D45BF1B1CC7A10B003F0151 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D45BF1A1CC7A10B003F0151 /* ViewController.swift */; }; 12 | 4D45BF1E1CC7A10B003F0151 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4D45BF1C1CC7A10B003F0151 /* Main.storyboard */; }; 13 | 4D45BF201CC7A10B003F0151 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4D45BF1F1CC7A10B003F0151 /* Assets.xcassets */; }; 14 | 4D45BF231CC7A10B003F0151 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4D45BF211CC7A10B003F0151 /* LaunchScreen.storyboard */; }; 15 | 4D45BF2E1CC7A10B003F0151 /* WMPageController_SwiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D45BF2D1CC7A10B003F0151 /* WMPageController_SwiftTests.swift */; }; 16 | 4D45BF391CC7A10B003F0151 /* WMPageController_SwiftUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D45BF381CC7A10B003F0151 /* WMPageController_SwiftUITests.swift */; }; 17 | 4D45BF521CC7A1EB003F0151 /* TableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D45BF511CC7A1EB003F0151 /* TableViewController.swift */; }; 18 | 4D45BF661CC7BC12003F0151 /* WMPageControllerSwiftFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D45BF651CC7BC12003F0151 /* WMPageControllerSwiftFramework.h */; settings = {ATTRIBUTES = (Public, ); }; }; 19 | 4D45BF6A1CC7BC12003F0151 /* WMPageControllerSwiftFramework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D45BF631CC7BC12003F0151 /* WMPageControllerSwiftFramework.framework */; }; 20 | 4D45BF6B1CC7BC12003F0151 /* WMPageControllerSwiftFramework.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4D45BF631CC7BC12003F0151 /* WMPageControllerSwiftFramework.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 21 | 4DCCF8481CE855F200C31A07 /* FloodView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DCCF8431CE855F200C31A07 /* FloodView.swift */; }; 22 | 4DCCF8491CE855F200C31A07 /* MenuItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DCCF8441CE855F200C31A07 /* MenuItem.swift */; }; 23 | 4DCCF84A1CE855F200C31A07 /* MenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DCCF8451CE855F200C31A07 /* MenuView.swift */; }; 24 | 4DCCF84B1CE855F200C31A07 /* PageController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DCCF8461CE855F200C31A07 /* PageController.swift */; }; 25 | 4DCCF84C1CE855F200C31A07 /* ProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DCCF8471CE855F200C31A07 /* ProgressView.swift */; }; 26 | F73DD37B1F403F3500FAC00A /* FloodView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DCCF8431CE855F200C31A07 /* FloodView.swift */; }; 27 | F73DD37C1F403F3500FAC00A /* MenuItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DCCF8441CE855F200C31A07 /* MenuItem.swift */; }; 28 | F73DD37D1F403F3500FAC00A /* MenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DCCF8451CE855F200C31A07 /* MenuView.swift */; }; 29 | F73DD37E1F403F3500FAC00A /* PageController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DCCF8461CE855F200C31A07 /* PageController.swift */; }; 30 | F73DD37F1F403F3500FAC00A /* ProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DCCF8471CE855F200C31A07 /* ProgressView.swift */; }; 31 | /* End PBXBuildFile section */ 32 | 33 | /* Begin PBXContainerItemProxy section */ 34 | 4D45BF2A1CC7A10B003F0151 /* PBXContainerItemProxy */ = { 35 | isa = PBXContainerItemProxy; 36 | containerPortal = 4D45BF0D1CC7A10B003F0151 /* Project object */; 37 | proxyType = 1; 38 | remoteGlobalIDString = 4D45BF141CC7A10B003F0151; 39 | remoteInfo = "WMPageController-Swift"; 40 | }; 41 | 4D45BF351CC7A10B003F0151 /* PBXContainerItemProxy */ = { 42 | isa = PBXContainerItemProxy; 43 | containerPortal = 4D45BF0D1CC7A10B003F0151 /* Project object */; 44 | proxyType = 1; 45 | remoteGlobalIDString = 4D45BF141CC7A10B003F0151; 46 | remoteInfo = "WMPageController-Swift"; 47 | }; 48 | 4D45BF681CC7BC12003F0151 /* PBXContainerItemProxy */ = { 49 | isa = PBXContainerItemProxy; 50 | containerPortal = 4D45BF0D1CC7A10B003F0151 /* Project object */; 51 | proxyType = 1; 52 | remoteGlobalIDString = 4D45BF621CC7BC12003F0151; 53 | remoteInfo = WMPageControllerSwiftFramework; 54 | }; 55 | /* End PBXContainerItemProxy section */ 56 | 57 | /* Begin PBXCopyFilesBuildPhase section */ 58 | 4D45BF6F1CC7BC12003F0151 /* Embed Frameworks */ = { 59 | isa = PBXCopyFilesBuildPhase; 60 | buildActionMask = 2147483647; 61 | dstPath = ""; 62 | dstSubfolderSpec = 10; 63 | files = ( 64 | 4D45BF6B1CC7BC12003F0151 /* WMPageControllerSwiftFramework.framework in Embed Frameworks */, 65 | ); 66 | name = "Embed Frameworks"; 67 | runOnlyForDeploymentPostprocessing = 0; 68 | }; 69 | /* End PBXCopyFilesBuildPhase section */ 70 | 71 | /* Begin PBXFileReference section */ 72 | 4D45BF151CC7A10B003F0151 /* WMPageController-Swift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "WMPageController-Swift.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 73 | 4D45BF181CC7A10B003F0151 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 74 | 4D45BF1A1CC7A10B003F0151 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 75 | 4D45BF1D1CC7A10B003F0151 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 76 | 4D45BF1F1CC7A10B003F0151 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 77 | 4D45BF221CC7A10B003F0151 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 78 | 4D45BF241CC7A10B003F0151 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 79 | 4D45BF291CC7A10B003F0151 /* WMPageController-SwiftTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "WMPageController-SwiftTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 80 | 4D45BF2D1CC7A10B003F0151 /* WMPageController_SwiftTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WMPageController_SwiftTests.swift; sourceTree = ""; }; 81 | 4D45BF2F1CC7A10B003F0151 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 82 | 4D45BF341CC7A10B003F0151 /* WMPageController-SwiftUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "WMPageController-SwiftUITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 83 | 4D45BF381CC7A10B003F0151 /* WMPageController_SwiftUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WMPageController_SwiftUITests.swift; sourceTree = ""; }; 84 | 4D45BF3A1CC7A10B003F0151 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 85 | 4D45BF511CC7A1EB003F0151 /* TableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableViewController.swift; sourceTree = ""; }; 86 | 4D45BF631CC7BC12003F0151 /* WMPageControllerSwiftFramework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = WMPageControllerSwiftFramework.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 87 | 4D45BF651CC7BC12003F0151 /* WMPageControllerSwiftFramework.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WMPageControllerSwiftFramework.h; sourceTree = ""; }; 88 | 4D45BF671CC7BC12003F0151 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 89 | 4DCCF8431CE855F200C31A07 /* FloodView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FloodView.swift; sourceTree = ""; }; 90 | 4DCCF8441CE855F200C31A07 /* MenuItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuItem.swift; sourceTree = ""; }; 91 | 4DCCF8451CE855F200C31A07 /* MenuView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuView.swift; sourceTree = ""; }; 92 | 4DCCF8461CE855F200C31A07 /* PageController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PageController.swift; sourceTree = ""; }; 93 | 4DCCF8471CE855F200C31A07 /* ProgressView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressView.swift; sourceTree = ""; }; 94 | /* End PBXFileReference section */ 95 | 96 | /* Begin PBXFrameworksBuildPhase section */ 97 | 4D45BF121CC7A10B003F0151 /* Frameworks */ = { 98 | isa = PBXFrameworksBuildPhase; 99 | buildActionMask = 2147483647; 100 | files = ( 101 | 4D45BF6A1CC7BC12003F0151 /* WMPageControllerSwiftFramework.framework in Frameworks */, 102 | ); 103 | runOnlyForDeploymentPostprocessing = 0; 104 | }; 105 | 4D45BF261CC7A10B003F0151 /* Frameworks */ = { 106 | isa = PBXFrameworksBuildPhase; 107 | buildActionMask = 2147483647; 108 | files = ( 109 | ); 110 | runOnlyForDeploymentPostprocessing = 0; 111 | }; 112 | 4D45BF311CC7A10B003F0151 /* Frameworks */ = { 113 | isa = PBXFrameworksBuildPhase; 114 | buildActionMask = 2147483647; 115 | files = ( 116 | ); 117 | runOnlyForDeploymentPostprocessing = 0; 118 | }; 119 | 4D45BF5F1CC7BC12003F0151 /* Frameworks */ = { 120 | isa = PBXFrameworksBuildPhase; 121 | buildActionMask = 2147483647; 122 | files = ( 123 | ); 124 | runOnlyForDeploymentPostprocessing = 0; 125 | }; 126 | /* End PBXFrameworksBuildPhase section */ 127 | 128 | /* Begin PBXGroup section */ 129 | 4D45BF0C1CC7A10B003F0151 = { 130 | isa = PBXGroup; 131 | children = ( 132 | 4D45BF171CC7A10B003F0151 /* WMPageController-Swift */, 133 | 4D45BF2C1CC7A10B003F0151 /* WMPageController-SwiftTests */, 134 | 4D45BF371CC7A10B003F0151 /* WMPageController-SwiftUITests */, 135 | 4D45BF641CC7BC12003F0151 /* WMPageControllerSwiftFramework */, 136 | 4D45BF161CC7A10B003F0151 /* Products */, 137 | ); 138 | sourceTree = ""; 139 | }; 140 | 4D45BF161CC7A10B003F0151 /* Products */ = { 141 | isa = PBXGroup; 142 | children = ( 143 | 4D45BF151CC7A10B003F0151 /* WMPageController-Swift.app */, 144 | 4D45BF291CC7A10B003F0151 /* WMPageController-SwiftTests.xctest */, 145 | 4D45BF341CC7A10B003F0151 /* WMPageController-SwiftUITests.xctest */, 146 | 4D45BF631CC7BC12003F0151 /* WMPageControllerSwiftFramework.framework */, 147 | ); 148 | name = Products; 149 | sourceTree = ""; 150 | }; 151 | 4D45BF171CC7A10B003F0151 /* WMPageController-Swift */ = { 152 | isa = PBXGroup; 153 | children = ( 154 | 4DCCF8421CE855F200C31A07 /* PageController */, 155 | 4D45BF181CC7A10B003F0151 /* AppDelegate.swift */, 156 | 4D45BF1A1CC7A10B003F0151 /* ViewController.swift */, 157 | 4D45BF511CC7A1EB003F0151 /* TableViewController.swift */, 158 | 4D45BF1C1CC7A10B003F0151 /* Main.storyboard */, 159 | 4D45BF1F1CC7A10B003F0151 /* Assets.xcassets */, 160 | 4D45BF211CC7A10B003F0151 /* LaunchScreen.storyboard */, 161 | 4D45BF241CC7A10B003F0151 /* Info.plist */, 162 | ); 163 | path = "WMPageController-Swift"; 164 | sourceTree = ""; 165 | }; 166 | 4D45BF2C1CC7A10B003F0151 /* WMPageController-SwiftTests */ = { 167 | isa = PBXGroup; 168 | children = ( 169 | 4D45BF2D1CC7A10B003F0151 /* WMPageController_SwiftTests.swift */, 170 | 4D45BF2F1CC7A10B003F0151 /* Info.plist */, 171 | ); 172 | path = "WMPageController-SwiftTests"; 173 | sourceTree = ""; 174 | }; 175 | 4D45BF371CC7A10B003F0151 /* WMPageController-SwiftUITests */ = { 176 | isa = PBXGroup; 177 | children = ( 178 | 4D45BF381CC7A10B003F0151 /* WMPageController_SwiftUITests.swift */, 179 | 4D45BF3A1CC7A10B003F0151 /* Info.plist */, 180 | ); 181 | path = "WMPageController-SwiftUITests"; 182 | sourceTree = ""; 183 | }; 184 | 4D45BF641CC7BC12003F0151 /* WMPageControllerSwiftFramework */ = { 185 | isa = PBXGroup; 186 | children = ( 187 | 4D45BF651CC7BC12003F0151 /* WMPageControllerSwiftFramework.h */, 188 | 4D45BF671CC7BC12003F0151 /* Info.plist */, 189 | ); 190 | path = WMPageControllerSwiftFramework; 191 | sourceTree = ""; 192 | }; 193 | 4DCCF8421CE855F200C31A07 /* PageController */ = { 194 | isa = PBXGroup; 195 | children = ( 196 | 4DCCF8431CE855F200C31A07 /* FloodView.swift */, 197 | 4DCCF8441CE855F200C31A07 /* MenuItem.swift */, 198 | 4DCCF8451CE855F200C31A07 /* MenuView.swift */, 199 | 4DCCF8461CE855F200C31A07 /* PageController.swift */, 200 | 4DCCF8471CE855F200C31A07 /* ProgressView.swift */, 201 | ); 202 | path = PageController; 203 | sourceTree = SOURCE_ROOT; 204 | }; 205 | /* End PBXGroup section */ 206 | 207 | /* Begin PBXHeadersBuildPhase section */ 208 | 4D45BF601CC7BC12003F0151 /* Headers */ = { 209 | isa = PBXHeadersBuildPhase; 210 | buildActionMask = 2147483647; 211 | files = ( 212 | 4D45BF661CC7BC12003F0151 /* WMPageControllerSwiftFramework.h in Headers */, 213 | ); 214 | runOnlyForDeploymentPostprocessing = 0; 215 | }; 216 | /* End PBXHeadersBuildPhase section */ 217 | 218 | /* Begin PBXNativeTarget section */ 219 | 4D45BF141CC7A10B003F0151 /* WMPageController-Swift */ = { 220 | isa = PBXNativeTarget; 221 | buildConfigurationList = 4D45BF3D1CC7A10B003F0151 /* Build configuration list for PBXNativeTarget "WMPageController-Swift" */; 222 | buildPhases = ( 223 | 4D45BF111CC7A10B003F0151 /* Sources */, 224 | 4D45BF121CC7A10B003F0151 /* Frameworks */, 225 | 4D45BF131CC7A10B003F0151 /* Resources */, 226 | 4D45BF6F1CC7BC12003F0151 /* Embed Frameworks */, 227 | ); 228 | buildRules = ( 229 | ); 230 | dependencies = ( 231 | 4D45BF691CC7BC12003F0151 /* PBXTargetDependency */, 232 | ); 233 | name = "WMPageController-Swift"; 234 | productName = "WMPageController-Swift"; 235 | productReference = 4D45BF151CC7A10B003F0151 /* WMPageController-Swift.app */; 236 | productType = "com.apple.product-type.application"; 237 | }; 238 | 4D45BF281CC7A10B003F0151 /* WMPageController-SwiftTests */ = { 239 | isa = PBXNativeTarget; 240 | buildConfigurationList = 4D45BF401CC7A10B003F0151 /* Build configuration list for PBXNativeTarget "WMPageController-SwiftTests" */; 241 | buildPhases = ( 242 | 4D45BF251CC7A10B003F0151 /* Sources */, 243 | 4D45BF261CC7A10B003F0151 /* Frameworks */, 244 | 4D45BF271CC7A10B003F0151 /* Resources */, 245 | ); 246 | buildRules = ( 247 | ); 248 | dependencies = ( 249 | 4D45BF2B1CC7A10B003F0151 /* PBXTargetDependency */, 250 | ); 251 | name = "WMPageController-SwiftTests"; 252 | productName = "WMPageController-SwiftTests"; 253 | productReference = 4D45BF291CC7A10B003F0151 /* WMPageController-SwiftTests.xctest */; 254 | productType = "com.apple.product-type.bundle.unit-test"; 255 | }; 256 | 4D45BF331CC7A10B003F0151 /* WMPageController-SwiftUITests */ = { 257 | isa = PBXNativeTarget; 258 | buildConfigurationList = 4D45BF431CC7A10B003F0151 /* Build configuration list for PBXNativeTarget "WMPageController-SwiftUITests" */; 259 | buildPhases = ( 260 | 4D45BF301CC7A10B003F0151 /* Sources */, 261 | 4D45BF311CC7A10B003F0151 /* Frameworks */, 262 | 4D45BF321CC7A10B003F0151 /* Resources */, 263 | ); 264 | buildRules = ( 265 | ); 266 | dependencies = ( 267 | 4D45BF361CC7A10B003F0151 /* PBXTargetDependency */, 268 | ); 269 | name = "WMPageController-SwiftUITests"; 270 | productName = "WMPageController-SwiftUITests"; 271 | productReference = 4D45BF341CC7A10B003F0151 /* WMPageController-SwiftUITests.xctest */; 272 | productType = "com.apple.product-type.bundle.ui-testing"; 273 | }; 274 | 4D45BF621CC7BC12003F0151 /* WMPageControllerSwiftFramework */ = { 275 | isa = PBXNativeTarget; 276 | buildConfigurationList = 4D45BF6E1CC7BC12003F0151 /* Build configuration list for PBXNativeTarget "WMPageControllerSwiftFramework" */; 277 | buildPhases = ( 278 | 4D45BF5E1CC7BC12003F0151 /* Sources */, 279 | 4D45BF5F1CC7BC12003F0151 /* Frameworks */, 280 | 4D45BF601CC7BC12003F0151 /* Headers */, 281 | 4D45BF611CC7BC12003F0151 /* Resources */, 282 | ); 283 | buildRules = ( 284 | ); 285 | dependencies = ( 286 | ); 287 | name = WMPageControllerSwiftFramework; 288 | productName = WMPageControllerSwiftFramework; 289 | productReference = 4D45BF631CC7BC12003F0151 /* WMPageControllerSwiftFramework.framework */; 290 | productType = "com.apple.product-type.framework"; 291 | }; 292 | /* End PBXNativeTarget section */ 293 | 294 | /* Begin PBXProject section */ 295 | 4D45BF0D1CC7A10B003F0151 /* Project object */ = { 296 | isa = PBXProject; 297 | attributes = { 298 | LastSwiftUpdateCheck = 0730; 299 | LastUpgradeCheck = 0830; 300 | ORGANIZATIONNAME = "Wecan Studio"; 301 | TargetAttributes = { 302 | 4D45BF141CC7A10B003F0151 = { 303 | CreatedOnToolsVersion = 7.3; 304 | LastSwiftMigration = 0800; 305 | }; 306 | 4D45BF281CC7A10B003F0151 = { 307 | CreatedOnToolsVersion = 7.3; 308 | LastSwiftMigration = 0800; 309 | TestTargetID = 4D45BF141CC7A10B003F0151; 310 | }; 311 | 4D45BF331CC7A10B003F0151 = { 312 | CreatedOnToolsVersion = 7.3; 313 | LastSwiftMigration = 0800; 314 | TestTargetID = 4D45BF141CC7A10B003F0151; 315 | }; 316 | 4D45BF621CC7BC12003F0151 = { 317 | CreatedOnToolsVersion = 7.3; 318 | LastSwiftMigration = 0830; 319 | }; 320 | }; 321 | }; 322 | buildConfigurationList = 4D45BF101CC7A10B003F0151 /* Build configuration list for PBXProject "WMPageController-Swift" */; 323 | compatibilityVersion = "Xcode 3.2"; 324 | developmentRegion = English; 325 | hasScannedForEncodings = 0; 326 | knownRegions = ( 327 | en, 328 | Base, 329 | ); 330 | mainGroup = 4D45BF0C1CC7A10B003F0151; 331 | productRefGroup = 4D45BF161CC7A10B003F0151 /* Products */; 332 | projectDirPath = ""; 333 | projectRoot = ""; 334 | targets = ( 335 | 4D45BF141CC7A10B003F0151 /* WMPageController-Swift */, 336 | 4D45BF281CC7A10B003F0151 /* WMPageController-SwiftTests */, 337 | 4D45BF331CC7A10B003F0151 /* WMPageController-SwiftUITests */, 338 | 4D45BF621CC7BC12003F0151 /* WMPageControllerSwiftFramework */, 339 | ); 340 | }; 341 | /* End PBXProject section */ 342 | 343 | /* Begin PBXResourcesBuildPhase section */ 344 | 4D45BF131CC7A10B003F0151 /* Resources */ = { 345 | isa = PBXResourcesBuildPhase; 346 | buildActionMask = 2147483647; 347 | files = ( 348 | 4D45BF231CC7A10B003F0151 /* LaunchScreen.storyboard in Resources */, 349 | 4D45BF201CC7A10B003F0151 /* Assets.xcassets in Resources */, 350 | 4D45BF1E1CC7A10B003F0151 /* Main.storyboard in Resources */, 351 | ); 352 | runOnlyForDeploymentPostprocessing = 0; 353 | }; 354 | 4D45BF271CC7A10B003F0151 /* Resources */ = { 355 | isa = PBXResourcesBuildPhase; 356 | buildActionMask = 2147483647; 357 | files = ( 358 | ); 359 | runOnlyForDeploymentPostprocessing = 0; 360 | }; 361 | 4D45BF321CC7A10B003F0151 /* Resources */ = { 362 | isa = PBXResourcesBuildPhase; 363 | buildActionMask = 2147483647; 364 | files = ( 365 | ); 366 | runOnlyForDeploymentPostprocessing = 0; 367 | }; 368 | 4D45BF611CC7BC12003F0151 /* Resources */ = { 369 | isa = PBXResourcesBuildPhase; 370 | buildActionMask = 2147483647; 371 | files = ( 372 | ); 373 | runOnlyForDeploymentPostprocessing = 0; 374 | }; 375 | /* End PBXResourcesBuildPhase section */ 376 | 377 | /* Begin PBXSourcesBuildPhase section */ 378 | 4D45BF111CC7A10B003F0151 /* Sources */ = { 379 | isa = PBXSourcesBuildPhase; 380 | buildActionMask = 2147483647; 381 | files = ( 382 | 4D45BF1B1CC7A10B003F0151 /* ViewController.swift in Sources */, 383 | 4DCCF84A1CE855F200C31A07 /* MenuView.swift in Sources */, 384 | 4DCCF8481CE855F200C31A07 /* FloodView.swift in Sources */, 385 | 4DCCF84B1CE855F200C31A07 /* PageController.swift in Sources */, 386 | 4D45BF521CC7A1EB003F0151 /* TableViewController.swift in Sources */, 387 | 4DCCF84C1CE855F200C31A07 /* ProgressView.swift in Sources */, 388 | 4D45BF191CC7A10B003F0151 /* AppDelegate.swift in Sources */, 389 | 4DCCF8491CE855F200C31A07 /* MenuItem.swift in Sources */, 390 | ); 391 | runOnlyForDeploymentPostprocessing = 0; 392 | }; 393 | 4D45BF251CC7A10B003F0151 /* Sources */ = { 394 | isa = PBXSourcesBuildPhase; 395 | buildActionMask = 2147483647; 396 | files = ( 397 | 4D45BF2E1CC7A10B003F0151 /* WMPageController_SwiftTests.swift in Sources */, 398 | ); 399 | runOnlyForDeploymentPostprocessing = 0; 400 | }; 401 | 4D45BF301CC7A10B003F0151 /* Sources */ = { 402 | isa = PBXSourcesBuildPhase; 403 | buildActionMask = 2147483647; 404 | files = ( 405 | 4D45BF391CC7A10B003F0151 /* WMPageController_SwiftUITests.swift in Sources */, 406 | ); 407 | runOnlyForDeploymentPostprocessing = 0; 408 | }; 409 | 4D45BF5E1CC7BC12003F0151 /* Sources */ = { 410 | isa = PBXSourcesBuildPhase; 411 | buildActionMask = 2147483647; 412 | files = ( 413 | F73DD37B1F403F3500FAC00A /* FloodView.swift in Sources */, 414 | F73DD37C1F403F3500FAC00A /* MenuItem.swift in Sources */, 415 | F73DD37D1F403F3500FAC00A /* MenuView.swift in Sources */, 416 | F73DD37E1F403F3500FAC00A /* PageController.swift in Sources */, 417 | F73DD37F1F403F3500FAC00A /* ProgressView.swift in Sources */, 418 | ); 419 | runOnlyForDeploymentPostprocessing = 0; 420 | }; 421 | /* End PBXSourcesBuildPhase section */ 422 | 423 | /* Begin PBXTargetDependency section */ 424 | 4D45BF2B1CC7A10B003F0151 /* PBXTargetDependency */ = { 425 | isa = PBXTargetDependency; 426 | target = 4D45BF141CC7A10B003F0151 /* WMPageController-Swift */; 427 | targetProxy = 4D45BF2A1CC7A10B003F0151 /* PBXContainerItemProxy */; 428 | }; 429 | 4D45BF361CC7A10B003F0151 /* PBXTargetDependency */ = { 430 | isa = PBXTargetDependency; 431 | target = 4D45BF141CC7A10B003F0151 /* WMPageController-Swift */; 432 | targetProxy = 4D45BF351CC7A10B003F0151 /* PBXContainerItemProxy */; 433 | }; 434 | 4D45BF691CC7BC12003F0151 /* PBXTargetDependency */ = { 435 | isa = PBXTargetDependency; 436 | target = 4D45BF621CC7BC12003F0151 /* WMPageControllerSwiftFramework */; 437 | targetProxy = 4D45BF681CC7BC12003F0151 /* PBXContainerItemProxy */; 438 | }; 439 | /* End PBXTargetDependency section */ 440 | 441 | /* Begin PBXVariantGroup section */ 442 | 4D45BF1C1CC7A10B003F0151 /* Main.storyboard */ = { 443 | isa = PBXVariantGroup; 444 | children = ( 445 | 4D45BF1D1CC7A10B003F0151 /* Base */, 446 | ); 447 | name = Main.storyboard; 448 | sourceTree = ""; 449 | }; 450 | 4D45BF211CC7A10B003F0151 /* LaunchScreen.storyboard */ = { 451 | isa = PBXVariantGroup; 452 | children = ( 453 | 4D45BF221CC7A10B003F0151 /* Base */, 454 | ); 455 | name = LaunchScreen.storyboard; 456 | sourceTree = ""; 457 | }; 458 | /* End PBXVariantGroup section */ 459 | 460 | /* Begin XCBuildConfiguration section */ 461 | 4D45BF3B1CC7A10B003F0151 /* Debug */ = { 462 | isa = XCBuildConfiguration; 463 | buildSettings = { 464 | ALWAYS_SEARCH_USER_PATHS = NO; 465 | CLANG_ANALYZER_NONNULL = YES; 466 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 467 | CLANG_CXX_LIBRARY = "libc++"; 468 | CLANG_ENABLE_MODULES = YES; 469 | CLANG_ENABLE_OBJC_ARC = YES; 470 | CLANG_WARN_BOOL_CONVERSION = YES; 471 | CLANG_WARN_CONSTANT_CONVERSION = YES; 472 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 473 | CLANG_WARN_EMPTY_BODY = YES; 474 | CLANG_WARN_ENUM_CONVERSION = YES; 475 | CLANG_WARN_INFINITE_RECURSION = YES; 476 | CLANG_WARN_INT_CONVERSION = YES; 477 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 478 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 479 | CLANG_WARN_UNREACHABLE_CODE = YES; 480 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 481 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 482 | COPY_PHASE_STRIP = NO; 483 | DEBUG_INFORMATION_FORMAT = dwarf; 484 | ENABLE_STRICT_OBJC_MSGSEND = YES; 485 | ENABLE_TESTABILITY = YES; 486 | GCC_C_LANGUAGE_STANDARD = gnu99; 487 | GCC_DYNAMIC_NO_PIC = NO; 488 | GCC_NO_COMMON_BLOCKS = YES; 489 | GCC_OPTIMIZATION_LEVEL = 0; 490 | GCC_PREPROCESSOR_DEFINITIONS = ( 491 | "DEBUG=1", 492 | "$(inherited)", 493 | ); 494 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 495 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 496 | GCC_WARN_UNDECLARED_SELECTOR = YES; 497 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 498 | GCC_WARN_UNUSED_FUNCTION = YES; 499 | GCC_WARN_UNUSED_VARIABLE = YES; 500 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 501 | MTL_ENABLE_DEBUG_INFO = YES; 502 | ONLY_ACTIVE_ARCH = YES; 503 | SDKROOT = iphoneos; 504 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 505 | }; 506 | name = Debug; 507 | }; 508 | 4D45BF3C1CC7A10B003F0151 /* Release */ = { 509 | isa = XCBuildConfiguration; 510 | buildSettings = { 511 | ALWAYS_SEARCH_USER_PATHS = NO; 512 | CLANG_ANALYZER_NONNULL = YES; 513 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 514 | CLANG_CXX_LIBRARY = "libc++"; 515 | CLANG_ENABLE_MODULES = YES; 516 | CLANG_ENABLE_OBJC_ARC = YES; 517 | CLANG_WARN_BOOL_CONVERSION = YES; 518 | CLANG_WARN_CONSTANT_CONVERSION = YES; 519 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 520 | CLANG_WARN_EMPTY_BODY = YES; 521 | CLANG_WARN_ENUM_CONVERSION = YES; 522 | CLANG_WARN_INFINITE_RECURSION = YES; 523 | CLANG_WARN_INT_CONVERSION = YES; 524 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 525 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 526 | CLANG_WARN_UNREACHABLE_CODE = YES; 527 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 528 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 529 | COPY_PHASE_STRIP = NO; 530 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 531 | ENABLE_NS_ASSERTIONS = NO; 532 | ENABLE_STRICT_OBJC_MSGSEND = YES; 533 | GCC_C_LANGUAGE_STANDARD = gnu99; 534 | GCC_NO_COMMON_BLOCKS = YES; 535 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 536 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 537 | GCC_WARN_UNDECLARED_SELECTOR = YES; 538 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 539 | GCC_WARN_UNUSED_FUNCTION = YES; 540 | GCC_WARN_UNUSED_VARIABLE = YES; 541 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 542 | MTL_ENABLE_DEBUG_INFO = NO; 543 | SDKROOT = iphoneos; 544 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 545 | VALIDATE_PRODUCT = YES; 546 | }; 547 | name = Release; 548 | }; 549 | 4D45BF3E1CC7A10B003F0151 /* Debug */ = { 550 | isa = XCBuildConfiguration; 551 | buildSettings = { 552 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 553 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 554 | INFOPLIST_FILE = "WMPageController-Swift/Info.plist"; 555 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 556 | PRODUCT_BUNDLE_IDENTIFIER = "com.wecan.WMPageController-Swift"; 557 | PRODUCT_NAME = "$(TARGET_NAME)"; 558 | SWIFT_VERSION = 3.0; 559 | }; 560 | name = Debug; 561 | }; 562 | 4D45BF3F1CC7A10B003F0151 /* Release */ = { 563 | isa = XCBuildConfiguration; 564 | buildSettings = { 565 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 566 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 567 | INFOPLIST_FILE = "WMPageController-Swift/Info.plist"; 568 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 569 | PRODUCT_BUNDLE_IDENTIFIER = "com.wecan.WMPageController-Swift"; 570 | PRODUCT_NAME = "$(TARGET_NAME)"; 571 | SWIFT_VERSION = 3.0; 572 | }; 573 | name = Release; 574 | }; 575 | 4D45BF411CC7A10B003F0151 /* Debug */ = { 576 | isa = XCBuildConfiguration; 577 | buildSettings = { 578 | BUNDLE_LOADER = "$(TEST_HOST)"; 579 | INFOPLIST_FILE = "WMPageController-SwiftTests/Info.plist"; 580 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 581 | PRODUCT_BUNDLE_IDENTIFIER = "com.wecan.WMPageController-SwiftTests"; 582 | PRODUCT_NAME = "$(TARGET_NAME)"; 583 | SWIFT_VERSION = 3.0; 584 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/WMPageController-Swift.app/WMPageController-Swift"; 585 | }; 586 | name = Debug; 587 | }; 588 | 4D45BF421CC7A10B003F0151 /* Release */ = { 589 | isa = XCBuildConfiguration; 590 | buildSettings = { 591 | BUNDLE_LOADER = "$(TEST_HOST)"; 592 | INFOPLIST_FILE = "WMPageController-SwiftTests/Info.plist"; 593 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 594 | PRODUCT_BUNDLE_IDENTIFIER = "com.wecan.WMPageController-SwiftTests"; 595 | PRODUCT_NAME = "$(TARGET_NAME)"; 596 | SWIFT_VERSION = 3.0; 597 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/WMPageController-Swift.app/WMPageController-Swift"; 598 | }; 599 | name = Release; 600 | }; 601 | 4D45BF441CC7A10B003F0151 /* Debug */ = { 602 | isa = XCBuildConfiguration; 603 | buildSettings = { 604 | INFOPLIST_FILE = "WMPageController-SwiftUITests/Info.plist"; 605 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 606 | PRODUCT_BUNDLE_IDENTIFIER = "com.wecan.WMPageController-SwiftUITests"; 607 | PRODUCT_NAME = "$(TARGET_NAME)"; 608 | SWIFT_VERSION = 3.0; 609 | TEST_TARGET_NAME = "WMPageController-Swift"; 610 | }; 611 | name = Debug; 612 | }; 613 | 4D45BF451CC7A10B003F0151 /* Release */ = { 614 | isa = XCBuildConfiguration; 615 | buildSettings = { 616 | INFOPLIST_FILE = "WMPageController-SwiftUITests/Info.plist"; 617 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 618 | PRODUCT_BUNDLE_IDENTIFIER = "com.wecan.WMPageController-SwiftUITests"; 619 | PRODUCT_NAME = "$(TARGET_NAME)"; 620 | SWIFT_VERSION = 3.0; 621 | TEST_TARGET_NAME = "WMPageController-Swift"; 622 | }; 623 | name = Release; 624 | }; 625 | 4D45BF6C1CC7BC12003F0151 /* Debug */ = { 626 | isa = XCBuildConfiguration; 627 | buildSettings = { 628 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 629 | CURRENT_PROJECT_VERSION = 1; 630 | DEFINES_MODULE = YES; 631 | DYLIB_COMPATIBILITY_VERSION = 1; 632 | DYLIB_CURRENT_VERSION = 1; 633 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 634 | INFOPLIST_FILE = WMPageControllerSwiftFramework/Info.plist; 635 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 636 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 637 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 638 | PRODUCT_BUNDLE_IDENTIFIER = com.wecan.WMPageControllerSwiftFramework; 639 | PRODUCT_MODULE_NAME = WMPageControllerSwiftFramework; 640 | PRODUCT_NAME = WMPageControllerSwiftFramework; 641 | SKIP_INSTALL = YES; 642 | SWIFT_VERSION = 3.0; 643 | TARGETED_DEVICE_FAMILY = "1,2"; 644 | VERSIONING_SYSTEM = "apple-generic"; 645 | VERSION_INFO_PREFIX = ""; 646 | }; 647 | name = Debug; 648 | }; 649 | 4D45BF6D1CC7BC12003F0151 /* Release */ = { 650 | isa = XCBuildConfiguration; 651 | buildSettings = { 652 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 653 | CURRENT_PROJECT_VERSION = 1; 654 | DEFINES_MODULE = YES; 655 | DYLIB_COMPATIBILITY_VERSION = 1; 656 | DYLIB_CURRENT_VERSION = 1; 657 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 658 | INFOPLIST_FILE = WMPageControllerSwiftFramework/Info.plist; 659 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 660 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 661 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 662 | PRODUCT_BUNDLE_IDENTIFIER = com.wecan.WMPageControllerSwiftFramework; 663 | PRODUCT_MODULE_NAME = WMPageControllerSwiftFramework; 664 | PRODUCT_NAME = WMPageControllerSwiftFramework; 665 | SKIP_INSTALL = YES; 666 | SWIFT_VERSION = 3.0; 667 | TARGETED_DEVICE_FAMILY = "1,2"; 668 | VERSIONING_SYSTEM = "apple-generic"; 669 | VERSION_INFO_PREFIX = ""; 670 | }; 671 | name = Release; 672 | }; 673 | /* End XCBuildConfiguration section */ 674 | 675 | /* Begin XCConfigurationList section */ 676 | 4D45BF101CC7A10B003F0151 /* Build configuration list for PBXProject "WMPageController-Swift" */ = { 677 | isa = XCConfigurationList; 678 | buildConfigurations = ( 679 | 4D45BF3B1CC7A10B003F0151 /* Debug */, 680 | 4D45BF3C1CC7A10B003F0151 /* Release */, 681 | ); 682 | defaultConfigurationIsVisible = 0; 683 | defaultConfigurationName = Release; 684 | }; 685 | 4D45BF3D1CC7A10B003F0151 /* Build configuration list for PBXNativeTarget "WMPageController-Swift" */ = { 686 | isa = XCConfigurationList; 687 | buildConfigurations = ( 688 | 4D45BF3E1CC7A10B003F0151 /* Debug */, 689 | 4D45BF3F1CC7A10B003F0151 /* Release */, 690 | ); 691 | defaultConfigurationIsVisible = 0; 692 | defaultConfigurationName = Release; 693 | }; 694 | 4D45BF401CC7A10B003F0151 /* Build configuration list for PBXNativeTarget "WMPageController-SwiftTests" */ = { 695 | isa = XCConfigurationList; 696 | buildConfigurations = ( 697 | 4D45BF411CC7A10B003F0151 /* Debug */, 698 | 4D45BF421CC7A10B003F0151 /* Release */, 699 | ); 700 | defaultConfigurationIsVisible = 0; 701 | defaultConfigurationName = Release; 702 | }; 703 | 4D45BF431CC7A10B003F0151 /* Build configuration list for PBXNativeTarget "WMPageController-SwiftUITests" */ = { 704 | isa = XCConfigurationList; 705 | buildConfigurations = ( 706 | 4D45BF441CC7A10B003F0151 /* Debug */, 707 | 4D45BF451CC7A10B003F0151 /* Release */, 708 | ); 709 | defaultConfigurationIsVisible = 0; 710 | defaultConfigurationName = Release; 711 | }; 712 | 4D45BF6E1CC7BC12003F0151 /* Build configuration list for PBXNativeTarget "WMPageControllerSwiftFramework" */ = { 713 | isa = XCConfigurationList; 714 | buildConfigurations = ( 715 | 4D45BF6C1CC7BC12003F0151 /* Debug */, 716 | 4D45BF6D1CC7BC12003F0151 /* Release */, 717 | ); 718 | defaultConfigurationIsVisible = 0; 719 | defaultConfigurationName = Release; 720 | }; 721 | /* End XCConfigurationList section */ 722 | }; 723 | rootObject = 4D45BF0D1CC7A10B003F0151 /* Project object */; 724 | } 725 | -------------------------------------------------------------------------------- /WMPageController-Swift.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /WMPageController-Swift.xcodeproj/project.xcworkspace/xcuserdata/Mark.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangmchn/WMPageController-Swift/4c68bdc69568c02809b06e1c403050ecb967ac46/WMPageController-Swift.xcodeproj/project.xcworkspace/xcuserdata/Mark.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /WMPageController-Swift.xcodeproj/xcshareddata/xcschemes/WMPageController-Swift.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /WMPageController-Swift.xcodeproj/xcshareddata/xcschemes/WMPageControllerSwiftFramework.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /WMPageController-Swift.xcodeproj/xcuserdata/Mark.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | WMPageController-Swift.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | WMPageControllerSwiftFramework.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 1 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | 4D45BF141CC7A10B003F0151 21 | 22 | primary 23 | 24 | 25 | 4D45BF281CC7A10B003F0151 26 | 27 | primary 28 | 29 | 30 | 4D45BF331CC7A10B003F0151 31 | 32 | primary 33 | 34 | 35 | 4D45BF621CC7BC12003F0151 36 | 37 | primary 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /WMPageController-Swift/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Example 4 | // 5 | // Created by Mark on 15/12/1. 6 | // Copyright © 2015年 Wecan Studio. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | let pageController = customedPageController() 20 | window?.rootViewController = UINavigationController(rootViewController: pageController) 21 | // reloadPageController(pageController, afterDelay: 5.0) 22 | // updatePageController(pageController, title: "hahahahaha", afterDelay: 5.0) 23 | return true 24 | } 25 | 26 | func applicationWillResignActive(_ application: UIApplication) { 27 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 28 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 29 | } 30 | 31 | func applicationDidEnterBackground(_ application: UIApplication) { 32 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 33 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 34 | } 35 | 36 | func applicationWillEnterForeground(_ application: UIApplication) { 37 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | func applicationDidBecomeActive(_ application: UIApplication) { 41 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 42 | } 43 | 44 | func applicationWillTerminate(_ application: UIApplication) { 45 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 46 | } 47 | 48 | // MARK: - An example of `PageController` 49 | fileprivate func customedPageController() -> PageController { 50 | let vcClasses: [UIViewController.Type] = [ViewController.self, TableViewController.self] 51 | let titles = ["Hello", "World"] 52 | let pageController = PageController(vcClasses: vcClasses, theirTitles: titles) 53 | pageController.pageAnimatable = true 54 | pageController.menuViewStyle = MenuViewStyle.line 55 | pageController.bounces = true 56 | pageController.menuHeight = 44 57 | pageController.titleSizeSelected = 15 58 | pageController.values = ["Hello", "I'm Mark"] // pass values 59 | pageController.keys = ["type", "text"] // keys 60 | pageController.title = "Test" 61 | pageController.menuBGColor = .clear 62 | pageController.showOnNavigationBar = true 63 | // pageController.selectedIndex = 1 64 | // pageController.progressColor = .blackColor() 65 | // pageController.viewFrame = CGRect(x: 50, y: 100, width: 320, height: 500) 66 | // pageController.itemsWidths = [100, 50] 67 | // pageController.itemsMargins = [100, 10, 100] 68 | // pageController.titleSizeNormal = 12 69 | // pageController.titleSizeSelected = 14 70 | // pageController.titleColorNormal = UIColor.brownColor() 71 | // pageController.titleColorSelected = UIColor.blackColor() 72 | return pageController 73 | } 74 | 75 | fileprivate func reloadPageController(_ pageController: PageController, afterDelay delay: TimeInterval) { 76 | let delayTime = DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC) 77 | DispatchQueue.main.asyncAfter(deadline: delayTime) { 78 | pageController.titles = ["Hello", "World", "Reload"] 79 | pageController.viewControllerClasses = [ViewController.self, TableViewController.self, ViewController.self] 80 | pageController.values = ["Hello", "I'm Mark", "Reload"] 81 | pageController.keys = ["type", "text", "type"] 82 | pageController.reloadData() 83 | } 84 | } 85 | 86 | fileprivate func updatePageController(_ pageController: PageController, title: String, afterDelay delay: TimeInterval) { 87 | let delayTime = DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC) 88 | DispatchQueue.main.asyncAfter(deadline: delayTime) { 89 | pageController.updateTitle(title, atIndex: 1, andWidth: 150) 90 | } 91 | } 92 | 93 | } 94 | 95 | -------------------------------------------------------------------------------- /WMPageController-Swift/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /WMPageController-Swift/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /WMPageController-Swift/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /WMPageController-Swift/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /WMPageController-Swift/TableViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TableViewController.swift 3 | // PageController 4 | // 5 | // Created by Mark on 15/10/31. 6 | // Copyright © 2015年 Wecan Studio. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class TableViewController: UITableViewController { 12 | 13 | var text = "" 14 | fileprivate let cellReuseIdentifier = "cellReuseIdentifier" 15 | 16 | override func viewDidLoad() { 17 | super.viewDidLoad() 18 | tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellReuseIdentifier) 19 | tableView.rowHeight = 60 20 | } 21 | 22 | override func didReceiveMemoryWarning() { 23 | super.didReceiveMemoryWarning() 24 | // Dispose of any resources that can be recreated. 25 | } 26 | 27 | // MARK: - Table view data source 28 | 29 | override func numberOfSections(in tableView: UITableView) -> Int { 30 | return 1 31 | } 32 | 33 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 34 | return 20 35 | } 36 | 37 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 38 | let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier, for: indexPath) 39 | cell.selectionStyle = UITableViewCellSelectionStyle.none 40 | cell.imageView?.image = UIImage(named: "github") 41 | cell.textLabel?.text = text 42 | 43 | return cell 44 | } 45 | 46 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 47 | // let vc = ViewController() 48 | let vc = customedPageController() 49 | vc.title = "Push" 50 | // vc.type = "Bye bye" 51 | navigationController?.pushViewController(vc, animated: true) 52 | } 53 | 54 | // MARK: - An example of `PageController` 55 | fileprivate func customedPageController() -> PageController { 56 | let vcClasses: [UIViewController.Type] = [ViewController.self, TableViewController.self] 57 | let titles = ["Hello", "World"] 58 | let pageController = PageController(vcClasses: vcClasses, theirTitles: titles) 59 | pageController.pageAnimatable = true 60 | pageController.menuViewStyle = MenuViewStyle.line 61 | pageController.bounces = true 62 | pageController.menuHeight = 44 63 | pageController.titleSizeSelected = 15 64 | pageController.values = ["Hello", "I'm Mark"] // pass values 65 | pageController.keys = ["type", "text"] // keys 66 | pageController.title = "Test" 67 | pageController.menuBGColor = .clear 68 | // pageController.selectedIndex = 1 69 | // pageController.progressColor = .blackColor() 70 | // pageController.viewFrame = CGRect(x: 50, y: 100, width: 320, height: 500) 71 | // pageController.itemsWidths = [100, 50] 72 | // pageController.itemsMargins = [50, 10, 100] 73 | // pageController.titleSizeNormal = 12 74 | // pageController.titleSizeSelected = 14 75 | // pageController.titleColorNormal = UIColor.brownColor() 76 | // pageController.titleColorSelected = UIColor.blackColor() 77 | return pageController 78 | } 79 | 80 | override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { 81 | if (indexPath as NSIndexPath).row % 2 == 0 { 82 | return true 83 | } 84 | return false 85 | } 86 | 87 | override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { 88 | 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /WMPageController-Swift/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // PageController 4 | // 5 | // Created by Mark on 15/10/20. 6 | // Copyright © 2015年 Wecan Studio. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController, UITableViewDelegate { 12 | 13 | var type = "" 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | view.backgroundColor = .white 18 | createLabel() 19 | } 20 | 21 | fileprivate func createLabel() { 22 | let label = UILabel(frame: CGRect(x: 0, y: 100, width: view.bounds.size.width, height: 100)) 23 | label.text = type 24 | label.font = UIFont.systemFont(ofSize: 22) 25 | label.textAlignment = .center 26 | view.addSubview(label) 27 | } 28 | 29 | override func didReceiveMemoryWarning() { 30 | super.didReceiveMemoryWarning() 31 | // Dispose of any resources that can be recreated. 32 | } 33 | 34 | } 35 | 36 | -------------------------------------------------------------------------------- /WMPageController-SwiftTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /WMPageController-SwiftTests/WMPageController_SwiftTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WMPageController_SwiftTests.swift 3 | // WMPageController-SwiftTests 4 | // 5 | // Created by Mark on 16/4/20. 6 | // Copyright © 2016年 Wecan Studio. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import WMPageController_Swift 11 | 12 | class WMPageController_SwiftTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /WMPageController-SwiftUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /WMPageController-SwiftUITests/WMPageController_SwiftUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WMPageController_SwiftUITests.swift 3 | // WMPageController-SwiftUITests 4 | // 5 | // Created by Mark on 16/4/20. 6 | // Copyright © 2016年 Wecan Studio. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class WMPageController_SwiftUITests: XCTestCase { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | 18 | // In UI tests it is usually best to stop immediately when a failure occurs. 19 | continueAfterFailure = false 20 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 21 | XCUIApplication().launch() 22 | 23 | // In UI tests it’s 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. 24 | } 25 | 26 | override func tearDown() { 27 | // Put teardown code here. This method is called after the invocation of each test method in the class. 28 | super.tearDown() 29 | } 30 | 31 | func testExample() { 32 | // Use recording to get started writing UI tests. 33 | // Use XCTAssert and related functions to verify your tests produce the correct results. 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /WMPageControllerSwiftFramework/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.5.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /WMPageControllerSwiftFramework/WMPageControllerSwiftFramework.h: -------------------------------------------------------------------------------- 1 | // 2 | // WMPageControllerSwiftFramework.h 3 | // WMPageControllerSwiftFramework 4 | // 5 | // Created by Mark on 16/4/20. 6 | // Copyright © 2016年 Wecan Studio. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for WMPageControllerSwiftFramework. 12 | FOUNDATION_EXPORT double WMPageControllerSwiftFrameworkVersionNumber; 13 | 14 | //! Project version string for WMPageControllerSwiftFramework. 15 | FOUNDATION_EXPORT const unsigned char WMPageControllerSwiftFrameworkVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | --------------------------------------------------------------------------------