├── PageMenuKit ├── Info.plist ├── PMKPageMenuController.swift ├── PMKPageMenuControllerDelegate.swift ├── PMKPageMenuItem.swift ├── PMKPageMenuItemEllipse.swift ├── PMKPageMenuItemHacka.swift ├── PMKPageMenuItemNHK.swift ├── PMKPageMenuItemNetLab.swift ├── PMKPageMenuItemPlain.swift ├── PMKPageMenuItemSmart.swift ├── PMKPageMenuItemSuite.swift ├── PMKPageMenuItemTab.swift ├── PMKPageMenuItemWeb.swift └── PageMenuKit.h ├── PageMenuKitDemo ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ └── LaunchScreen.storyboard ├── BaseViewController.swift ├── DataViewController.swift ├── Info.plist └── RootViewController.swift ├── PageMenuKitSwift.xcodeproj └── project.pbxproj ├── README.md └── screenshots ├── ex_Ellipse.png ├── ex_Hacka.png ├── ex_NHK.png ├── ex_NetLab.png ├── ex_Plain.png ├── ex_Smart.png ├── ex_Suite.png ├── ex_Tab.png ├── ex_Web.png ├── tab_Ellipse.png ├── tab_Hacka.png ├── tab_NHK.png ├── tab_NetLab.png ├── tab_Plain.png ├── tab_Smart.png ├── tab_Suite.png ├── tab_Tab.png └── tab_Web.png /PageMenuKit/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.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSHumanReadableCopyright 22 | (c) 2016-2020 MagickWorX All Rights Reserved. 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /PageMenuKit/PMKPageMenuController.swift: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * FILE: PMKPageMenuController.swift 4 | * DESCRIPTION: PageMenuKit: Paging Menu View Controller 5 | * DATE: Fri, Jun 2 2017 6 | * UPDATED: Sun, May 19 2019 7 | * AUTHOR: Kouichi ABE (WALL) / 阿部康一 8 | * E-MAIL: kouichi@MagickWorX.COM 9 | * URL: http://www.MagickWorX.COM/ 10 | * COPYRIGHT: (c) 2017-2019 阿部康一/Kouichi ABE (WALL), All rights reserved. 11 | * LICENSE: 12 | * 13 | * Copyright (c) 2017-2019 Kouichi ABE (WALL) , 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted provided that the following conditions 18 | * are met: 19 | * 20 | * 1. Redistributions of source code must retain the above copyright 21 | * notice, this list of conditions and the following disclaimer. 22 | * 23 | * 2. Redistributions in binary form must reproduce the above copyright 24 | * notice, this list of conditions and the following disclaimer in the 25 | * documentation and/or other materials provided with the distribution. 26 | * 27 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 28 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 29 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 31 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 37 | * THE POSSIBILITY OF SUCH DAMAGE. 38 | * 39 | *****************************************************************************/ 40 | 41 | import Foundation 42 | import UIKit 43 | 44 | // http://stackoverflow.com/questions/1560081/how-can-i-create-a-uicolor-from-a-hex-string 45 | public extension UIColor { 46 | class func hexColor(_ hex: UInt32) -> UIColor { 47 | let r = CGFloat((hex & 0xff0000) >> 16) / 255.0 48 | let g = CGFloat((hex & 0xff00) >> 8) / 255.0 49 | let b = CGFloat((hex & 0xff)) / 255.0 50 | return UIColor(red:r, green:g, blue: b, alpha:1.0) 51 | } 52 | } 53 | 54 | let kMenuItemWidth: CGFloat = 90.0 55 | let kMenuItemHeight: CGFloat = 40.0 56 | let kMenuItemMargin: CGFloat = 10.0 57 | let kSmartTabMargin: CGFloat = 8.0 58 | let kSeparatorHeight: CGFloat = 2.0 59 | let kIndicatorHeight: CGFloat = kSeparatorHeight 60 | 61 | let kMenuItemBaseTag: Int = 170602 62 | 63 | let kHackaHexColor: UInt32 = 0x66cdaa 64 | let kJCNewsHexColor: UInt32 = 0x3fa9f5 65 | let kNetLabHexColor: UInt32 = 0x8e0c4e 66 | let kNHKNewsHexColor: UInt32 = 0x0387d2 67 | 68 | public class PMKPageMenuController: UIViewController, UIScrollViewDelegate 69 | { 70 | public weak var delegate: PMKPageMenuControllerDelegate? = nil 71 | 72 | public internal(set) var menuStyle: PMKPageMenuControllerStyle = .plain 73 | public internal(set) var titles: [String] = [] 74 | public internal(set) var childControllers: [UIViewController] = [] 75 | public internal(set) var menuColors: [UIColor] = [] 76 | 77 | private var startIndex: Int = 0 78 | 79 | private var topBarHeight: CGFloat = 40.0 80 | private var itemMargin: CGFloat = 0.0 81 | private var separatorHeight: CGFloat = kSeparatorHeight 82 | private var indicatorHeight: CGFloat = kIndicatorHeight 83 | 84 | private var menuSeparator: CALayer = { 85 | let layer: CALayer = CALayer() 86 | layer.actions = [ "backgroundColor" : NSNull() ] 87 | return layer 88 | }() 89 | private var menuIndicator: UIView = UIView() 90 | private var menuItems: [PMKPageMenuItem] = [] 91 | 92 | private lazy var pageViewController: UIPageViewController = { 93 | let style: UIPageViewController.TransitionStyle = .scroll 94 | let pageViewController = UIPageViewController(transitionStyle: style, navigationOrientation: .horizontal, options: nil) 95 | pageViewController.delegate = self 96 | pageViewController.dataSource = self 97 | return pageViewController 98 | }() 99 | 100 | private lazy var scrollView: UIScrollView = { 101 | let scrollView = UIScrollView() 102 | scrollView.backgroundColor = .clear 103 | scrollView.delegate = self 104 | scrollView.bounces = false 105 | scrollView.scrollsToTop = false 106 | scrollView.isPagingEnabled = false 107 | scrollView.showsHorizontalScrollIndicator = false 108 | return scrollView 109 | }() 110 | 111 | public static let standardColors: [UIColor] = [ 112 | UIColor.hexColor(0xff7f7f), 113 | UIColor.hexColor(0xbf7fff), 114 | UIColor.hexColor(0x7f7fff), 115 | UIColor.hexColor(0x7fbfff), 116 | UIColor.hexColor(0x7fff7f), 117 | UIColor.hexColor(0xffbf7f) 118 | ] 119 | 120 | // Designated Initializer 121 | public required init(coder aDecoder: NSCoder) { 122 | fatalError("NSCoding not supported") 123 | } 124 | 125 | public init(controllers: [UIViewController], 126 | menuStyle: PMKPageMenuControllerStyle, 127 | menuColors: [UIColor] = PMKPageMenuController.standardColors, 128 | startIndex: Int = 1, 129 | topBarHeight: CGFloat) { 130 | super.init(nibName: nil, bundle: nil) 131 | 132 | self.menuStyle = menuStyle 133 | self.menuColors = menuColors 134 | self.startIndex = startIndex > 0 && startIndex < controllers.count 135 | ? startIndex - 1 136 | : 0 137 | self.topBarHeight = topBarHeight 138 | self.currentIndex = 0 139 | 140 | self.childControllers = controllers 141 | 142 | self.titles = controllers.enumerated().map { 143 | // $0.0 ... index 144 | // $0.1 ... UIViewController 145 | if let title = $0.1.value(forKey: "title") as? String, title.count > 0 { 146 | return title 147 | } 148 | else { 149 | return String(format: "Title%zd", $0.0 + 1) 150 | } 151 | } 152 | 153 | prepareForMenuStyle(menuStyle) 154 | } 155 | 156 | public override func loadView() { 157 | super.loadView() 158 | 159 | let width: CGFloat = self.view.bounds.size.width 160 | 161 | let x: CGFloat = 0.0 162 | let y: CGFloat = topBarHeight 163 | let w: CGFloat = width 164 | let h: CGFloat = kMenuItemHeight + separatorHeight 165 | 166 | scrollView.frame = CGRect(x: x, y: y, width: w, height: h) 167 | self.view.addSubview(scrollView) 168 | 169 | prepareForMenuItems() 170 | prepareForMenuSeparator() 171 | prepareForMenuIndicator() 172 | } 173 | 174 | public override func viewDidLoad() { 175 | super.viewDidLoad() 176 | 177 | changeMenuItem(at: startIndex) 178 | 179 | self.addChild(pageViewController) 180 | self.view.addSubview(pageViewController.view) 181 | 182 | let width: CGFloat = self.view.bounds.size.width 183 | let height: CGFloat = self.view.bounds.size.height 184 | 185 | let x: CGFloat = 0.0 186 | let y: CGFloat = topBarHeight + scrollView.frame.size.height 187 | let w: CGFloat = width 188 | let h: CGFloat = height - y 189 | pageViewController.view.frame = CGRect(x: x, y: y, width: w, height: h) 190 | pageViewController.didMove(toParent: self) 191 | 192 | delegate?.pageMenuController(self, didPrepare: menuItems) 193 | } 194 | 195 | 196 | // MARK: convenient method 197 | func menuColor(at index: Int) -> UIColor { 198 | let numberOfColors: Int = menuColors.count 199 | guard numberOfColors > 0 else { 200 | return PMKPageMenuController.standardColors[index % PMKPageMenuController.standardColors.count] 201 | } 202 | return menuColors[index % numberOfColors] 203 | } 204 | 205 | // MARK: - Properties 206 | var currentIndex: Int = 0 { 207 | willSet { 208 | let index = currentIndex 209 | let viewController: UIViewController = self.childControllers[index] 210 | delegate?.pageMenuController(self, didMoveTo: viewController, at: index) 211 | 212 | // タブの形状を復元 213 | let item: PMKPageMenuItem = self.menuItems[index] 214 | item.isSelected = false 215 | } 216 | didSet { 217 | self.moveIndicator(at: currentIndex) 218 | } 219 | } 220 | 221 | // MARK: - Private Methods for Indicator 222 | func moveIndicator(at index: Int) { 223 | // まずはタブを移動させる 224 | self.willMoveIndicator(at: index) 225 | 226 | // そのあとタブの装飾をする 227 | let w: CGFloat = kMenuItemWidth + itemMargin 228 | let x: CGFloat = w * CGFloat(index) 229 | 230 | let item: PMKPageMenuItem = self.menuItems[index] 231 | switch (menuStyle) { 232 | case .plain, .suite: 233 | var frame: CGRect = menuIndicator.frame 234 | frame.origin.x = x 235 | menuIndicator.frame = frame 236 | case .tab: 237 | menuSeparator.backgroundColor = item.color.cgColor 238 | menuIndicator.backgroundColor = .clear 239 | case .smart: 240 | menuIndicator.backgroundColor = item.color 241 | case .hacka: 242 | menuIndicator.backgroundColor = .clear 243 | default: 244 | break 245 | } 246 | item.isSelected = true 247 | 248 | delegate?.pageMenuController(self, didSelect: item, at: index) 249 | } 250 | 251 | func willMoveIndicator(at index: Int) { 252 | let w: CGFloat = kMenuItemWidth + itemMargin 253 | var x: CGFloat = w * CGFloat(index) 254 | let y: CGFloat = 0.0 255 | 256 | let width: CGFloat = scrollView.frame.size.width 257 | // 選択したタブを中央寄せにする計算 258 | let size: CGSize = scrollView.contentSize 259 | let leftX: CGFloat = (width - w) * 0.5 // 画面幅の半分からタブ幅の半分を引く 260 | let tabN: CGFloat = ceil(width / w) // 画面内に見えるタブの数 261 | let rightX: CGFloat = size.width - floor((tabN * 0.5 + 0.5) * w) 262 | if (x < leftX) { x = 0.0 } 263 | else if (x > rightX) { x = size.width - width } 264 | else { x -= leftX } 265 | scrollView.setContentOffset(CGPoint(x: x, y: y), animated: true) 266 | } 267 | } 268 | 269 | // MARK: - Prepartions 270 | extension PMKPageMenuController 271 | { 272 | // CUSTOM: Add the settings for your custom menu style here. 273 | func prepareForMenuStyle(_ menuStyle: PMKPageMenuControllerStyle) { 274 | switch (menuStyle) { 275 | case .plain: 276 | itemMargin = kMenuItemMargin 277 | separatorHeight = 1.0 278 | indicatorHeight = 3.0 279 | case .tab: 280 | itemMargin = 0.0 281 | separatorHeight = 4.0 282 | indicatorHeight = 4.0 283 | case .smart: 284 | itemMargin = 0.0 285 | separatorHeight = 0.0 286 | case .hacka: 287 | itemMargin = kMenuItemMargin * 0.4 288 | case .web: 289 | itemMargin = 0.0 290 | separatorHeight = 4.0 291 | indicatorHeight = 0.0 292 | case .ellipse, .netlab: 293 | itemMargin = 0.0 294 | separatorHeight = 0.0 295 | indicatorHeight = 0.0 296 | case .suite: 297 | itemMargin = 0.0 298 | separatorHeight = 0.0 299 | indicatorHeight = 4.0 300 | case .nhk: 301 | itemMargin = 0.0 302 | separatorHeight = 2.0 303 | indicatorHeight = 0.0 304 | } 305 | } 306 | 307 | // CUSTOM: Add the separator color for your custom menu style if needed. 308 | func prepareForMenuSeparator() { 309 | let color: UIColor = { 310 | if let firstColor: UIColor = menuColors.first { return firstColor } 311 | switch (menuStyle) { 312 | case .plain, .web: return .orange 313 | case .hacka: return UIColor.hexColor(kHackaHexColor) 314 | case .nhk: return UIColor.hexColor(kNHKNewsHexColor) 315 | default: return PMKPageMenuController.standardColors.first! 316 | } 317 | }() 318 | let width: CGFloat = scrollView.contentSize.width 319 | let height: CGFloat = scrollView.frame.size.height 320 | 321 | let w: CGFloat = width 322 | let h: CGFloat = separatorHeight 323 | let x: CGFloat = 0.0 324 | let y: CGFloat = height - h 325 | 326 | menuSeparator.frame = CGRect(x: x, y: y, width: w, height: h) 327 | menuSeparator.backgroundColor = color.cgColor 328 | scrollView.layer.addSublayer(menuSeparator) 329 | } 330 | 331 | // CUSTOM: Add the indicator color for your custom menu style if needed. 332 | func prepareForMenuIndicator() { 333 | let x: CGFloat = 0.0 334 | let y: CGFloat = scrollView.frame.size.height - indicatorHeight 335 | let w: CGFloat = menuStyle == .tab || menuStyle == .smart 336 | ? scrollView.contentSize.width 337 | : kMenuItemWidth 338 | let h: CGFloat = indicatorHeight 339 | 340 | let color: UIColor = { 341 | if let firstColor: UIColor = menuColors.first { return firstColor } 342 | switch (menuStyle) { 343 | case .plain: return .orange 344 | case .hacka: return UIColor.hexColor(kHackaHexColor) 345 | case .suite: return UIColor.hexColor(0x7ab7cc) 346 | default: return PMKPageMenuController.standardColors.first! 347 | } 348 | }() 349 | 350 | menuIndicator.frame = CGRect(x: x, y: y, width: w, height: h) 351 | menuIndicator.backgroundColor = color 352 | scrollView.addSubview(menuIndicator) 353 | } 354 | 355 | fileprivate func changeMenuItem(at index: Int) { 356 | let viewController: UIViewController = self.childControllers[index] 357 | let viewControllers: [UIViewController] = [viewController] 358 | let direction: UIPageViewController.NavigationDirection = (index > currentIndex) ? .forward : .reverse 359 | self.currentIndex = index 360 | pageViewController.setViewControllers(viewControllers, direction: direction, animated: true, completion: nil) 361 | } 362 | 363 | @objc func handleSingleTap(_ gesture: UITapGestureRecognizer) { 364 | if var index: Int = gesture.view?.tag { 365 | index -= kMenuItemBaseTag 366 | changeMenuItem(at: index) 367 | } 368 | } 369 | 370 | /* 371 | * swift3 - how to create instance of a class from a string in swift 3 372 | * https://stackoverflow.com/questions/40373030/how-to-create-instance-of-a-class-from-a-string-in-swift-3 373 | */ 374 | func stringClassFromString(_ className: String) -> AnyClass! { 375 | // get namespace 376 | let namespace = Bundle.main.infoDictionary!["CFBundleExecutable"] as! String 377 | // XXX: 順に "namespace" を変更して探索を試みる 378 | if let cls: AnyClass = NSClassFromString("PageMenuKitSwift.\(className)") { 379 | return cls 380 | } 381 | if let cls: AnyClass = NSClassFromString("PageMenuKit.\(className)") { 382 | return cls 383 | } 384 | // get 'anyClass' with classname and namespace 385 | let cls: AnyClass = NSClassFromString("\(namespace).\(className)")! 386 | // return AnyClass 387 | return cls 388 | } 389 | 390 | // CUSTOM: Add the code to create instance of your custom menu style. 391 | func prepareForMenuItems() { 392 | self.menuItems = [] 393 | 394 | var x: CGFloat = 0.0 395 | let y: CGFloat = menuStyle == .smart || menuStyle == .hacka 396 | ? kSmartTabMargin 397 | : 0.0 398 | let w: CGFloat = kMenuItemWidth 399 | let h: CGFloat = kMenuItemHeight - y 400 | 401 | let count: Int = self.titles.count 402 | for i in 0 ..< count { 403 | let frame: CGRect = CGRect(x: x, y: y, width: w, height: h) 404 | let title: String = self.titles[i] 405 | let color: UIColor = { 406 | if menuColors.count == 0 { // 色指定がない場合はデフォルト色を使用 407 | switch (menuStyle) { 408 | case .plain: return .orange 409 | case .hacka: return UIColor.hexColor(kHackaHexColor) 410 | case .ellipse: return UIColor.hexColor(kJCNewsHexColor) 411 | case .netlab: return UIColor.hexColor(kNetLabHexColor) 412 | case .nhk: return UIColor.hexColor(kNHKNewsHexColor) 413 | default: return self.menuColor(at: i) 414 | } 415 | } 416 | switch (menuStyle) { 417 | case .plain, .hacka, .ellipse, .netlab, .nhk: 418 | return self.menuColor(at: 0) 419 | default: 420 | return self.menuColor(at: i) 421 | } 422 | }() 423 | 424 | let design = PMKPageMenuItemDesign(themeColor: color) 425 | switch (menuStyle) { // set default design 426 | case .web: 427 | design.inactive.isEnabled = true 428 | design.inactive.backgroundColor = UIColor.hexColor(0x332f2e) 429 | case .suite: 430 | design.titleColor = .white 431 | design.gradientColors = [ 432 | UIColor.hexColor(0x445a66).cgColor, 433 | UIColor.hexColor(0x677983).cgColor 434 | ] 435 | design.inactive.isEnabled = true 436 | design.inactive.titleColor = .lightGray 437 | case .netlab: 438 | design.backgroundColor = UIColor.hexColor(0xcb8fad) 439 | default: 440 | break 441 | } 442 | 443 | let className = menuStyle.className() 444 | let classType = stringClassFromString(className) as! PMKPageMenuItem.Type 445 | let item: PMKPageMenuItem = classType.init(frame: frame, title: title, design: design) 446 | item.tag = kMenuItemBaseTag + i 447 | scrollView.addSubview(item) 448 | x += (w + itemMargin) 449 | 450 | item.isSelected = (i == 0) 451 | self.menuItems.append(item) 452 | 453 | let tapGesture: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleSingleTap(_:))) 454 | item.addGestureRecognizer(tapGesture) 455 | } 456 | 457 | let width: CGFloat = scrollView.bounds.size.width 458 | let height: CGFloat = scrollView.bounds.size.height 459 | scrollView.contentSize = CGSize(width: x, height: height) 460 | 461 | var frame: CGRect = scrollView.frame 462 | if (width > x) { // 項目が少ないのね 463 | frame.origin.x = floor((width - x) * 0.5) 464 | frame.size.width = x 465 | } 466 | else { 467 | frame.origin.x = 0.0 468 | frame.size.width = width 469 | } 470 | scrollView.frame = frame 471 | } 472 | 473 | } 474 | 475 | // MARK: - Public Methods 476 | extension PMKPageMenuController 477 | { 478 | public func setMenuSeparatorColor(_ color: UIColor) { 479 | menuSeparator.backgroundColor = color.cgColor 480 | } 481 | 482 | public func setMenuIndicatorColor(_ color: UIColor) { 483 | menuIndicator.backgroundColor = color 484 | } 485 | 486 | } 487 | 488 | /* 489 | * MARK: - UIPageViewControllerDelegate 490 | */ 491 | extension PMKPageMenuController: UIPageViewControllerDelegate 492 | { 493 | // MARK - UIPageViewControllerDelegate (optional) 494 | public func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) { 495 | if let viewController: UIViewController = pendingViewControllers.last { 496 | if let index = self.childControllers.firstIndex(of: viewController) { 497 | if index != currentIndex { 498 | self.willMoveIndicator(at: index) 499 | } 500 | delegate?.pageMenuController(self, willMoveTo: viewController, at: index) 501 | } 502 | } 503 | } 504 | 505 | // MARK - UIPageViewControllerDelegate (optional) 506 | public func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { 507 | if let viewController: UIViewController = pageViewController.viewControllers?.last { 508 | guard let index = self.childControllers.firstIndex(of: viewController) else { return } 509 | if completed { 510 | self.currentIndex = index 511 | } 512 | else { 513 | self.willMoveIndicator(at: index) 514 | } 515 | } 516 | } 517 | 518 | // MARK - UIPageViewControllerDelegate (optional) 519 | public func pageViewController(_ pageViewController: UIPageViewController, spineLocationFor orientation: UIInterfaceOrientation) -> UIPageViewController.SpineLocation { 520 | if orientation.isPortrait || UIDevice.current.userInterfaceIdiom == .phone { 521 | if let currentViewController: UIViewController = pageViewController.viewControllers?.first { 522 | let viewControllers: [UIViewController] = [currentViewController] 523 | pageViewController.setViewControllers(viewControllers, direction: .forward, animated: true, completion: nil) 524 | } 525 | pageViewController.isDoubleSided = false 526 | return .min 527 | } 528 | return .none 529 | } 530 | 531 | } 532 | 533 | /* 534 | * MARK: - UIPageViewControllerDataSource 535 | */ 536 | extension PMKPageMenuController: UIPageViewControllerDataSource 537 | { 538 | // MARK - UIPageViewControllerDataSource (required) 539 | public func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { 540 | if let index = self.childControllers.firstIndex(of: viewController) { 541 | if index != 0 && index != NSNotFound { 542 | return self.childControllers[index - 1] 543 | } 544 | } 545 | return nil 546 | } 547 | 548 | // MARK - UIPageViewControllerDataSource (required) 549 | public func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { 550 | if let index = self.childControllers.firstIndex(of: viewController) { 551 | let count: Int = self.childControllers.count 552 | if index != NSNotFound && index + 1 < count { 553 | return self.childControllers[index + 1] 554 | } 555 | } 556 | return nil 557 | } 558 | 559 | } 560 | -------------------------------------------------------------------------------- /PageMenuKit/PMKPageMenuControllerDelegate.swift: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * FILE: PMKPageMenuControllerDelegate.swift 4 | * DESCRIPTION: PageMenuKit: Delegate for PageMenuController 5 | * DATE: Fri, Jun 2 2017 6 | * UPDATED: Thu, Jun 8 2017 7 | * AUTHOR: Kouichi ABE (WALL) / 阿部康一 8 | * E-MAIL: kouichi@MagickWorX.COM 9 | * URL: http://www.MagickWorX.COM/ 10 | * COPYRIGHT: (c) 2017 阿部康一/Kouichi ABE (WALL), All rights reserved. 11 | * LICENSE: 12 | * 13 | * Copyright (c) 2017 Kouichi ABE (WALL) , 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted provided that the following conditions 18 | * are met: 19 | * 20 | * 1. Redistributions of source code must retain the above copyright 21 | * notice, this list of conditions and the following disclaimer. 22 | * 23 | * 2. Redistributions in binary form must reproduce the above copyright 24 | * notice, this list of conditions and the following disclaimer in the 25 | * documentation and/or other materials provided with the distribution. 26 | * 27 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 28 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 29 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 31 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 37 | * THE POSSIBILITY OF SUCH DAMAGE. 38 | * 39 | *****************************************************************************/ 40 | 41 | import UIKit 42 | 43 | public protocol PMKPageMenuControllerDelegate: class 44 | { 45 | // ページ画面上でスワイプ操作による切り替えが行われる前に呼び出される 46 | func pageMenuController(_ pageMenuController: PMKPageMenuController, willMoveTo viewController: UIViewController, at menuIndex: Int) 47 | // ページの切り替えが完了した際に呼び出される 48 | func pageMenuController(_ pageMenuController: PMKPageMenuController, didMoveTo viewController: UIViewController, at menuIndex: Int) 49 | 50 | // メニュー項目の作成などが完了した際に呼び出される 51 | func pageMenuController(_ pageMenuController: PMKPageMenuController, didPrepare menuItems: [PMKPageMenuItem]) 52 | // メニューがタップされた際に呼び出される 53 | func pageMenuController(_ pageMenuController: PMKPageMenuController, didSelect menuItem: PMKPageMenuItem, at menuIndex: Int) 54 | } 55 | -------------------------------------------------------------------------------- /PageMenuKit/PMKPageMenuItem.swift: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * FILE: PMKPageMenuItem.swift 4 | * DESCRIPTION: PageMenuKit: Base MenuItem Class for PageMenuController 5 | * DATE: Fri, Jun 2 2017 6 | * UPDATED: Thu, Nov 15 2018 7 | * AUTHOR: Kouichi ABE (WALL) / 阿部康一 8 | * E-MAIL: kouichi@MagickWorX.COM 9 | * URL: http://www.MagickWorX.COM/ 10 | * COPYRIGHT: (c) 2017-2018 阿部康一/Kouichi ABE (WALL), All rights reserved. 11 | * LICENSE: 12 | * 13 | * Copyright (c) 2017-2018 Kouichi ABE (WALL) , 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted provided that the following conditions 18 | * are met: 19 | * 20 | * 1. Redistributions of source code must retain the above copyright 21 | * notice, this list of conditions and the following disclaimer. 22 | * 23 | * 2. Redistributions in binary form must reproduce the above copyright 24 | * notice, this list of conditions and the following disclaimer in the 25 | * documentation and/or other materials provided with the distribution. 26 | * 27 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 28 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 29 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 31 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 37 | * THE POSSIBILITY OF SUCH DAMAGE. 38 | * 39 | *****************************************************************************/ 40 | 41 | import UIKit 42 | import QuartzCore 43 | 44 | // CUSTOM: Add your custom menu style here. 45 | public enum PMKPageMenuControllerStyle: Int { 46 | case plain = 1 // NewsPass [https://itunes.apple.com/jp/app/id1106788059] 47 | case tab = 2 // Gunosy [https://itunes.apple.com/jp/app/id590384791] 48 | case smart = 3 // SmartNews [https://itunes.apple.com/jp/app/id579581125] 49 | case hacka = 4 // Hackadoll [https://itunes.apple.com/jp/app/id888231424] 50 | case web = 5 // JCNews [https://jcnews.tokyo/) 51 | case ellipse = 6 // JCNews [https://itunes.apple.com/jp/app/id1024341813] 52 | case suite = 7 // NewsSuite [https://itunes.apple.com/jp/app/id1176431318] 53 | case netlab = 8 // NLab [https://itunes.apple.com/jp/app/id949325541] 54 | case nhk = 9 // NHK NEWS [https://itunes.apple.com/jp/app/id1121104608] 55 | 56 | /// メニュー画面のスタイル毎のクラス名を返す 57 | /// 58 | /// - Returns: クラス名 59 | func className() -> String { 60 | switch self { 61 | case .plain: return "PMKPageMenuItemPlain" 62 | case .tab: return "PMKPageMenuItemTab" 63 | case .smart: return "PMKPageMenuItemSmart" 64 | case .hacka: return "PMKPageMenuItemHacka" 65 | case .web: return "PMKPageMenuItemWeb" 66 | case .ellipse: return "PMKPageMenuItemEllipse" 67 | case .suite: return "PMKPageMenuItemSuite" 68 | case .netlab: return "PMKPageMenuItemNetLab" 69 | case .nhk: return "PMKPageMenuItemNHK" 70 | } 71 | } 72 | } 73 | 74 | 75 | protocol Design { 76 | var themeColor: UIColor { get set } 77 | var titleColor: UIColor { get set } 78 | var backgroundColor: UIColor { get set } 79 | } 80 | 81 | public class PMKPageMenuItemDesign: Design { 82 | var themeColor: UIColor = .clear // 通常は titleColor と同じはず 83 | var titleColor: UIColor = .black 84 | var backgroundColor: UIColor = .clear 85 | var gradientColors: [CGColor] = [] 86 | 87 | struct InactiveDesign { // inactive を有効にする場合は isEnabled = true にする 88 | var isEnabled: Bool = false 89 | var titleColor: UIColor = .lightGray 90 | var backgroundColor: UIColor = .clear 91 | } 92 | var inactive: InactiveDesign = PMKPageMenuItemDesign.InactiveDesign() 93 | 94 | public init(themeColor: UIColor) { 95 | self.themeColor = themeColor 96 | self.titleColor = themeColor 97 | } 98 | 99 | public init() { 100 | } 101 | } 102 | 103 | 104 | protocol Item { 105 | var title: String { get set } 106 | var isEnabled: Bool { get set } 107 | } 108 | 109 | protocol MenuItem: Item { 110 | var color: UIColor { get set } // メニューの基本色 111 | var titleColor: UIColor { get set } 112 | var borderColor: UIColor { get set } // メニュー枠の色 113 | var isSelected: Bool { get set } 114 | 115 | /// メニュー画面を装飾 116 | /// 117 | /// - Rarameters: 118 | /// - active: メニュー選択時 = true, 非選択時 = false 119 | /// - Returns: なし 120 | func render(active: Bool) 121 | } 122 | 123 | public class PMKPageMenuItem: UIView, MenuItem { 124 | let kBorderLayerKey: String = "kBorderLayerKey" 125 | 126 | public internal(set) var color: UIColor = .clear 127 | public internal(set) var design: PMKPageMenuItemDesign = PMKPageMenuItemDesign() 128 | public internal(set) var style: PMKPageMenuControllerStyle = .plain 129 | 130 | lazy var label: UILabel = { 131 | let label = UILabel() 132 | label.text = self.title 133 | label.textAlignment = .center 134 | label.backgroundColor = .clear 135 | label.autoresizingMask = [ .flexibleWidth, .flexibleHeight ] 136 | return label 137 | }() 138 | 139 | public required init(coder aDecoder: NSCoder) { 140 | fatalError("init(coder:) has not been implemented") 141 | } 142 | 143 | override init(frame: CGRect) { 144 | super.init(frame: frame) 145 | } 146 | 147 | public required init(frame: CGRect, title: String, design: PMKPageMenuItemDesign) { 148 | super.init(frame: frame) 149 | 150 | self.backgroundColor = .clear 151 | self.isUserInteractionEnabled = true 152 | self.autoresizesSubviews = true 153 | 154 | self.title = title 155 | self.color = design.themeColor 156 | self.design = design 157 | 158 | label.frame = self.bounds 159 | self.addSubview(label) 160 | } 161 | 162 | 163 | /* 164 | * Properties 165 | */ 166 | public var title: String = "" { 167 | willSet { 168 | if title != newValue { 169 | label.text = newValue 170 | } 171 | } 172 | } 173 | 174 | public var isEnabled: Bool = true { 175 | willSet { 176 | label.isUserInteractionEnabled = newValue 177 | label.alpha = newValue ? 1.0 : 0.5 178 | } 179 | } 180 | 181 | var titleColor: UIColor = .black { 182 | willSet { 183 | label.textColor = newValue 184 | } 185 | } 186 | 187 | var borderColor: UIColor = .clear 188 | 189 | public var isSelected: Bool = false { 190 | willSet { 191 | self.render(active: newValue) 192 | } 193 | } 194 | 195 | public var badgeValue: String? = nil // XXX: Override Point 196 | 197 | // MARK: - Overriden Functions 198 | func render(active: Bool) { 199 | } 200 | 201 | // 左上と右上の角を丸める 202 | func roundCorners(of label: UILabel) { 203 | autoreleasepool { 204 | let maskPath: UIBezierPath = UIBezierPath(roundedRect: label.bounds, byRoundingCorners: [ .topLeft, .topRight ], cornerRadii: CGSize(width: 5.0, height: 5.0)) 205 | let maskLayer: CAShapeLayer = CAShapeLayer() 206 | maskLayer.frame = label.bounds 207 | maskLayer.path = maskPath.cgPath 208 | label.layer.mask = maskLayer 209 | } 210 | } 211 | } 212 | 213 | // MARK: - Private Methods 214 | extension PMKPageMenuItem { 215 | public var borderLayer: CAShapeLayer? { 216 | return label.layer.value(forKey: kBorderLayerKey) as? CAShapeLayer 217 | } 218 | 219 | // 左端と上と右端のみ枠線を付ける 220 | func addBorders(to label: UILabel) { 221 | autoreleasepool { 222 | let w: CGFloat = label.frame.size.width 223 | let h: CGFloat = label.frame.size.height 224 | var x: CGFloat = 0.0 225 | var y: CGFloat = h 226 | let bezierPath: UIBezierPath = UIBezierPath() 227 | bezierPath.move(to: CGPoint(x: x, y: y)); y = 0.0 228 | bezierPath.addLine(to: CGPoint(x: x, y: y)); x = w 229 | bezierPath.addLine(to: CGPoint(x: x, y: y)); y = h 230 | bezierPath.addLine(to: CGPoint(x: x, y: y)) 231 | let shapeLayer: CAShapeLayer = CAShapeLayer() 232 | shapeLayer.frame = label.bounds 233 | shapeLayer.path = bezierPath.cgPath 234 | shapeLayer.fillColor = UIColor.clear.cgColor 235 | shapeLayer.strokeColor = self.borderColor.cgColor 236 | shapeLayer.lineWidth = 1.0 237 | /* 238 | * XXX: Disable implicit animation for hidden of CAShapeLayer. 239 | * http://stackoverflow.com/questions/5833488/how-to-disable-calayer-implicit-animations 240 | */ 241 | shapeLayer.actions = [ "hidden" : NSNull() ] 242 | label.layer.addSublayer(shapeLayer) 243 | label.layer.setValue(shapeLayer, forKey:kBorderLayerKey) 244 | } 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /PageMenuKit/PMKPageMenuItemEllipse.swift: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * FILE: PMKPageMenuItemEllipse.swift 4 | * DESCRIPTION: PageMenuKit: PageMenuItem Class like "JCNews" iOS App 5 | * DATE: Wed, Jun 7 2017 6 | * UPDATED: Thu, Nov 15 2018 7 | * AUTHOR: Kouichi ABE (WALL) / 阿部康一 8 | * E-MAIL: kouichi@MagickWorX.COM 9 | * URL: http://www.MagickWorX.COM/ 10 | * COPYRIGHT: (c) 2017-2018 阿部康一/Kouichi ABE (WALL), All rights reserved. 11 | * LICENSE: 12 | * 13 | * Copyright (c) 2017-2018 Kouichi ABE (WALL) , 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted provided that the following conditions 18 | * are met: 19 | * 20 | * 1. Redistributions of source code must retain the above copyright 21 | * notice, this list of conditions and the following disclaimer. 22 | * 23 | * 2. Redistributions in binary form must reproduce the above copyright 24 | * notice, this list of conditions and the following disclaimer in the 25 | * documentation and/or other materials provided with the distribution. 26 | * 27 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 28 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 29 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 31 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 37 | * THE POSSIBILITY OF SUCH DAMAGE. 38 | * 39 | *****************************************************************************/ 40 | 41 | import UIKit 42 | import QuartzCore 43 | 44 | public class PMKPageMenuItemEllipse: PMKPageMenuItem { 45 | public required init(coder aDecoder: NSCoder) { 46 | fatalError("init(coder:) has not been implemented") 47 | } 48 | 49 | public required init(frame: CGRect, title: String, design: PMKPageMenuItemDesign) { 50 | super.init(frame: frame, title: title, design: design) 51 | 52 | self.style = .ellipse 53 | 54 | self.backgroundColor = design.themeColor // ベースの背景色は固定 55 | } 56 | 57 | override func render(active: Bool) { 58 | if active { 59 | self.label.textColor = self.design.themeColor 60 | self.label.backgroundColor = .white 61 | self.roundCorners(of: self.label) 62 | } 63 | else { 64 | self.label.textColor = .white 65 | self.label.backgroundColor = self.design.themeColor 66 | self.label.layer.mask = nil 67 | } 68 | } 69 | 70 | override func roundCorners(of label: UILabel) { 71 | autoreleasepool { 72 | let radius: CGFloat = 10.0 73 | let bounds: CGRect = label.bounds.insetBy(dx: 4.0, dy: 6.0) 74 | let maskPath: UIBezierPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: [ .allCorners ], cornerRadii: CGSize(width: radius, height: radius)) 75 | let maskLayer: CAShapeLayer = CAShapeLayer() 76 | maskLayer.frame = label.bounds 77 | maskLayer.path = maskPath.cgPath 78 | label.layer.mask = maskLayer 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /PageMenuKit/PMKPageMenuItemHacka.swift: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * FILE: PMKPageMenuItemHacka.swift 4 | * DESCRIPTION: PageMenuKit: PageMenuItem Class like "ハッカドール" iOS App 5 | * DATE: Fri, Jun 2 2017 6 | * UPDATED: Thu, Nov 15 2018 7 | * AUTHOR: Kouichi ABE (WALL) / 阿部康一 8 | * E-MAIL: kouichi@MagickWorX.COM 9 | * URL: http://www.MagickWorX.COM/ 10 | * COPYRIGHT: (c) 2017-2018 阿部康一/Kouichi ABE (WALL), All rights reserved. 11 | * LICENSE: 12 | * 13 | * Copyright (c) 2017-2018 Kouichi ABE (WALL) , 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted provided that the following conditions 18 | * are met: 19 | * 20 | * 1. Redistributions of source code must retain the above copyright 21 | * notice, this list of conditions and the following disclaimer. 22 | * 23 | * 2. Redistributions in binary form must reproduce the above copyright 24 | * notice, this list of conditions and the following disclaimer in the 25 | * documentation and/or other materials provided with the distribution. 26 | * 27 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 28 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 29 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 31 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 37 | * THE POSSIBILITY OF SUCH DAMAGE. 38 | * 39 | *****************************************************************************/ 40 | 41 | import UIKit 42 | import QuartzCore 43 | 44 | public class PMKPageMenuItemHacka: PMKPageMenuItem { 45 | let kBadgeLayerKey: String = "kBadgeLayerKey" 46 | 47 | public required init(coder aDecoder: NSCoder) { 48 | fatalError("init(coder:) has not been implemented") 49 | } 50 | 51 | public required init(frame: CGRect, title: String, design: PMKPageMenuItemDesign) { 52 | super.init(frame: frame, title: title, design: design) 53 | 54 | self.style = .hacka 55 | self.titleColor = design.themeColor 56 | self.borderColor = design.themeColor 57 | 58 | self.addBorders(to: self.label) 59 | } 60 | 61 | override func render(active: Bool) { 62 | var frame: CGRect = self.frame 63 | if active { 64 | self.label.textColor = .white 65 | self.label.backgroundColor = self.design.themeColor 66 | self.borderLayer?.isHidden = true 67 | frame.origin.y = 0.0 68 | frame.size.height = kMenuItemHeight 69 | } 70 | else { 71 | self.label.textColor = self.design.themeColor 72 | self.label.backgroundColor = .clear 73 | self.borderLayer?.isHidden = false 74 | frame.origin.y = kSmartTabMargin 75 | frame.size.height = kMenuItemHeight - kSmartTabMargin 76 | } 77 | self.frame = frame 78 | 79 | if let textLayer = self.label.layer.value(forKey: kBadgeLayerKey) as? CATextLayer { 80 | textLayer.isHidden = (self.badgeValue == nil || active) 81 | } 82 | } 83 | 84 | override var borderColor: UIColor { 85 | willSet { 86 | self.borderLayer?.strokeColor = newValue.cgColor 87 | } 88 | } 89 | 90 | override public var badgeValue: String? { 91 | willSet { 92 | let textLayer: CATextLayer = { 93 | if let textLayer = self.label.layer.value(forKey: kBadgeLayerKey) as? CATextLayer { 94 | return textLayer 95 | } 96 | let w: CGFloat = 16.0 97 | let h: CGFloat = w 98 | let x: CGFloat = self.label.frame.size.width - w - 4.0 99 | let y: CGFloat = -kSmartTabMargin 100 | let textLayer = CATextLayer() 101 | textLayer.frame = CGRect(x: x, y: y, width: w, height: h) 102 | textLayer.fontSize = 12.0 103 | textLayer.foregroundColor = UIColor.white.cgColor 104 | textLayer.backgroundColor = UIColor.red.cgColor 105 | textLayer.cornerRadius = w * 0.5 106 | textLayer.masksToBounds = true 107 | textLayer.alignmentMode = .center 108 | textLayer.contentsScale = UIScreen.main.scale 109 | textLayer.actions = [ "hidden" : NSNull() ] 110 | self.label.layer.addSublayer(textLayer) 111 | self.label.layer.setValue(textLayer, forKey: kBadgeLayerKey) 112 | return textLayer 113 | }() 114 | textLayer.string = newValue 115 | textLayer.isHidden = (newValue == nil || isSelected) 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /PageMenuKit/PMKPageMenuItemNHK.swift: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * FILE: PMKPageMenuItemNHK.swift 4 | * DESCRIPTION: PageMenuKit: PageMenuItem Class like "NHK ニュース防災" 5 | * DATE: Fri, Jun 2 2017 6 | * UPDATED: Thu, Nov 15 2018 7 | * AUTHOR: Kouichi ABE (WALL) / 阿部康一 8 | * E-MAIL: kouichi@MagickWorX.COM 9 | * URL: http://www.MagickWorX.COM/ 10 | * COPYRIGHT: (c) 2017-2018 阿部康一/Kouichi ABE (WALL), All rights reserved. 11 | * LICENSE: 12 | * 13 | * Copyright (c) 2017-2018 Kouichi ABE (WALL) , 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted provided that the following conditions 18 | * are met: 19 | * 20 | * 1. Redistributions of source code must retain the above copyright 21 | * notice, this list of conditions and the following disclaimer. 22 | * 23 | * 2. Redistributions in binary form must reproduce the above copyright 24 | * notice, this list of conditions and the following disclaimer in the 25 | * documentation and/or other materials provided with the distribution. 26 | * 27 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 28 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 29 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 31 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 37 | * THE POSSIBILITY OF SUCH DAMAGE. 38 | * 39 | *****************************************************************************/ 40 | 41 | import UIKit 42 | import QuartzCore 43 | 44 | public class PMKPageMenuItemNHK: PMKPageMenuItem { 45 | public required init(coder aDecoder: NSCoder) { 46 | fatalError("init(coder:) has not been implemented") 47 | } 48 | 49 | public required init(frame: CGRect, title: String, design: PMKPageMenuItemDesign) { 50 | super.init(frame: frame, title: title, design: design) 51 | 52 | self.style = .nhk 53 | } 54 | 55 | override func render(active: Bool) { 56 | if active { 57 | self.label.textColor = .white 58 | self.label.backgroundColor = self.design.themeColor 59 | } 60 | else { 61 | self.label.textColor = self.design.themeColor 62 | self.label.backgroundColor = .clear 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /PageMenuKit/PMKPageMenuItemNetLab.swift: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * FILE: PMKPageMenuItemNetLab.swift 4 | * DESCRIPTION: PageMenuKit: PageMenuItem Class like "ねとらぼ" iOS App 5 | * DATE: Thu, Jun 8 2017 6 | * UPDATED: Thu, Nov 15 2018 7 | * AUTHOR: Kouichi ABE (WALL) / 阿部康一 8 | * E-MAIL: kouichi@MagickWorX.COM 9 | * URL: http://www.MagickWorX.COM/ 10 | * COPYRIGHT: (c) 2017-2018 阿部康一/Kouichi ABE (WALL), All rights reserved. 11 | * LICENSE: 12 | * 13 | * Copyright (c) 2017-2018 Kouichi ABE (WALL) , 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted provided that the following conditions 18 | * are met: 19 | * 20 | * 1. Redistributions of source code must retain the above copyright 21 | * notice, this list of conditions and the following disclaimer. 22 | * 23 | * 2. Redistributions in binary form must reproduce the above copyright 24 | * notice, this list of conditions and the following disclaimer in the 25 | * documentation and/or other materials provided with the distribution. 26 | * 27 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 28 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 29 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 31 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 37 | * THE POSSIBILITY OF SUCH DAMAGE. 38 | * 39 | *****************************************************************************/ 40 | 41 | import UIKit 42 | import QuartzCore 43 | 44 | public class PMKPageMenuItemNetLab: PMKPageMenuItem { 45 | public required init(coder aDecoder: NSCoder) { 46 | fatalError("init(coder:) has not been implemented") 47 | } 48 | 49 | public required init(frame: CGRect, title: String, design: PMKPageMenuItemDesign) { 50 | super.init(frame: frame, title: title, design: design) 51 | 52 | self.style = .netlab 53 | } 54 | 55 | override func render(active: Bool) { 56 | if active { 57 | self.label.textColor = .white 58 | self.label.backgroundColor = self.design.backgroundColor 59 | self.roundCorners(of: self.label) 60 | } 61 | else { 62 | self.label.textColor = self.design.titleColor 63 | self.label.backgroundColor = .clear 64 | self.label.layer.mask = nil 65 | } 66 | } 67 | 68 | override func roundCorners(of label: UILabel) { 69 | autoreleasepool { 70 | let radius: CGFloat = 5.0 71 | let bounds: CGRect = label.bounds.insetBy(dx: 4.0, dy: 6.0) 72 | let maskPath: UIBezierPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: [ .allCorners ], cornerRadii: CGSize(width: radius, height: radius)) 73 | let maskLayer: CAShapeLayer = CAShapeLayer() 74 | maskLayer.frame = label.bounds 75 | maskLayer.path = maskPath.cgPath 76 | label.layer.mask = maskLayer 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /PageMenuKit/PMKPageMenuItemPlain.swift: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * FILE: PMKPageMenuItemPlain.swift 4 | * DESCRIPTION: PageMenuKit: PageMenuItem Class like "ニュースパス" 5 | * DATE: Fri, Jun 2 2017 6 | * UPDATED: Thu, Nov 15 2018 7 | * AUTHOR: Kouichi ABE (WALL) / 阿部康一 8 | * E-MAIL: kouichi@MagickWorX.COM 9 | * URL: http://www.MagickWorX.COM/ 10 | * COPYRIGHT: (c) 2017-2018 阿部康一/Kouichi ABE (WALL), All rights reserved. 11 | * LICENSE: 12 | * 13 | * Copyright (c) 2017-2018 Kouichi ABE (WALL) , 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted provided that the following conditions 18 | * are met: 19 | * 20 | * 1. Redistributions of source code must retain the above copyright 21 | * notice, this list of conditions and the following disclaimer. 22 | * 23 | * 2. Redistributions in binary form must reproduce the above copyright 24 | * notice, this list of conditions and the following disclaimer in the 25 | * documentation and/or other materials provided with the distribution. 26 | * 27 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 28 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 29 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 31 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 37 | * THE POSSIBILITY OF SUCH DAMAGE. 38 | * 39 | *****************************************************************************/ 40 | 41 | import UIKit 42 | import QuartzCore 43 | 44 | public class PMKPageMenuItemPlain: PMKPageMenuItem { 45 | public required init(coder aDecoder: NSCoder) { 46 | fatalError("init(coder:) has not been implemented") 47 | } 48 | 49 | public required init(frame: CGRect, title: String, design: PMKPageMenuItemDesign) { 50 | super.init(frame: frame, title: title, design: design) 51 | 52 | self.style = .plain 53 | 54 | self.titleColor = design.titleColor 55 | } 56 | 57 | override func render(active: Bool) { 58 | self.label.textColor = active ? self.design.titleColor : .darkGray 59 | self.label.backgroundColor = .clear 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /PageMenuKit/PMKPageMenuItemSmart.swift: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * FILE: PMKPageMenuItemSmart.swift 4 | * DESCRIPTION: PageMenuKit: PageMenuItem Class like "SmartNews" 5 | * DATE: Fri, Jun 2 2017 6 | * UPDATED: Thu, Nov 15 2018 7 | * AUTHOR: Kouichi ABE (WALL) / 阿部康一 8 | * E-MAIL: kouichi@MagickWorX.COM 9 | * URL: http://www.MagickWorX.COM/ 10 | * COPYRIGHT: (c) 2017-2018 阿部康一/Kouichi ABE (WALL), All rights reserved. 11 | * LICENSE: 12 | * 13 | * Copyright (c) 2017-2018 Kouichi ABE (WALL) , 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted provided that the following conditions 18 | * are met: 19 | * 20 | * 1. Redistributions of source code must retain the above copyright 21 | * notice, this list of conditions and the following disclaimer. 22 | * 23 | * 2. Redistributions in binary form must reproduce the above copyright 24 | * notice, this list of conditions and the following disclaimer in the 25 | * documentation and/or other materials provided with the distribution. 26 | * 27 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 28 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 29 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 31 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 37 | * THE POSSIBILITY OF SUCH DAMAGE. 38 | * 39 | *****************************************************************************/ 40 | 41 | import UIKit 42 | import QuartzCore 43 | 44 | public class PMKPageMenuItemSmart: PMKPageMenuItem { 45 | public required init(coder aDecoder: NSCoder) { 46 | fatalError("init(coder:) has not been implemented") 47 | } 48 | 49 | public required init(frame: CGRect, title: String, design: PMKPageMenuItemDesign) { 50 | super.init(frame: frame, title: title, design: design) 51 | 52 | self.style = .smart 53 | 54 | self.titleColor = .white 55 | self.label.backgroundColor = design.themeColor 56 | } 57 | 58 | override func render(active: Bool) { 59 | var frame: CGRect = self.frame 60 | if active { 61 | frame.origin.y = 0.0 62 | frame.size.height = kMenuItemHeight 63 | } 64 | else { 65 | frame.origin.y = kSmartTabMargin 66 | frame.size.height = kMenuItemHeight - kSmartTabMargin 67 | } 68 | self.frame = frame 69 | self.roundCorners(of: self.label) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /PageMenuKit/PMKPageMenuItemSuite.swift: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * FILE: PMKPageMenuItemSuite.swift 4 | * DESCRIPTION: PageMenuKit: PageMenuItem Class like "ニュース(News Suite)" 5 | * DATE: Wed, Jun 7 2017 6 | * UPDATED: Thu, Nov 15 2018 7 | * AUTHOR: Kouichi ABE (WALL) / 阿部康一 8 | * E-MAIL: kouichi@MagickWorX.COM 9 | * URL: http://www.MagickWorX.COM/ 10 | * COPYRIGHT: (c) 2017-2018 阿部康一/Kouichi ABE (WALL), All rights reserved. 11 | * LICENSE: 12 | * 13 | * Copyright (c) 2017-2018 Kouichi ABE (WALL) , 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted provided that the following conditions 18 | * are met: 19 | * 20 | * 1. Redistributions of source code must retain the above copyright 21 | * notice, this list of conditions and the following disclaimer. 22 | * 23 | * 2. Redistributions in binary form must reproduce the above copyright 24 | * notice, this list of conditions and the following disclaimer in the 25 | * documentation and/or other materials provided with the distribution. 26 | * 27 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 28 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 29 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 31 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 37 | * THE POSSIBILITY OF SUCH DAMAGE. 38 | * 39 | *****************************************************************************/ 40 | 41 | import UIKit 42 | import QuartzCore 43 | 44 | public class PMKPageMenuItemSuite: PMKPageMenuItem { 45 | public required init(coder aDecoder: NSCoder) { 46 | fatalError("init(coder:) has not been implemented") 47 | } 48 | 49 | public required init(frame: CGRect, title: String, design: PMKPageMenuItemDesign) { 50 | super.init(frame: frame, title: title, design: design) 51 | 52 | self.style = .suite 53 | 54 | self.gradientBackground(of: self) 55 | } 56 | 57 | override func render(active: Bool) { 58 | self.label.textColor = { 59 | if active { 60 | return self.design.titleColor 61 | } 62 | else if self.design.inactive.isEnabled { 63 | return self.design.inactive.titleColor 64 | } 65 | else { 66 | return .lightGray 67 | } 68 | }() 69 | } 70 | 71 | func gradientBackground(of view: UIView) { 72 | let gradientColors: [CGColor] = { 73 | if self.design.gradientColors.count > 0 { 74 | return self.design.gradientColors 75 | } 76 | let topColor: UIColor = UIColor.hexColor(0x445a66) 77 | let bottomColor: UIColor = UIColor.hexColor(0x677983) 78 | return [ topColor.cgColor, bottomColor.cgColor ] 79 | }() 80 | let gradientLayer: CAGradientLayer = CAGradientLayer() 81 | gradientLayer.colors = gradientColors 82 | gradientLayer.frame = view.bounds 83 | view.layer.insertSublayer(gradientLayer, at: 0) 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /PageMenuKit/PMKPageMenuItemTab.swift: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * FILE: PMKPageMenuItemTab.swift 4 | * DESCRIPTION: PageMenuKit: PageMenuItem Class like "グノシー" 5 | * DATE: Fri, Jun 2 2017 6 | * UPDATED: Thu, Nov 15 2018 7 | * AUTHOR: Kouichi ABE (WALL) / 阿部康一 8 | * E-MAIL: kouichi@MagickWorX.COM 9 | * URL: http://www.MagickWorX.COM/ 10 | * COPYRIGHT: (c) 2017-2018 阿部康一/Kouichi ABE (WALL), All rights reserved. 11 | * LICENSE: 12 | * 13 | * Copyright (c) 2017-2018 Kouichi ABE (WALL) , 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted provided that the following conditions 18 | * are met: 19 | * 20 | * 1. Redistributions of source code must retain the above copyright 21 | * notice, this list of conditions and the following disclaimer. 22 | * 23 | * 2. Redistributions in binary form must reproduce the above copyright 24 | * notice, this list of conditions and the following disclaimer in the 25 | * documentation and/or other materials provided with the distribution. 26 | * 27 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 28 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 29 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 31 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 37 | * THE POSSIBILITY OF SUCH DAMAGE. 38 | * 39 | *****************************************************************************/ 40 | 41 | import UIKit 42 | import QuartzCore 43 | 44 | public class PMKPageMenuItemTab: PMKPageMenuItem { 45 | public required init(coder aDecoder: NSCoder) { 46 | fatalError("init(coder:) has not been implemented") 47 | } 48 | 49 | public required init(frame: CGRect, title: String, design: PMKPageMenuItemDesign) { 50 | super.init(frame: frame, title: title, design: design) 51 | 52 | self.style = .tab 53 | 54 | self.roundCorners(of: self.label) 55 | } 56 | 57 | override func render(active: Bool) { 58 | if active { 59 | self.label.textColor = .white 60 | self.label.backgroundColor = self.design.themeColor 61 | } 62 | else { 63 | self.label.textColor = self.design.themeColor 64 | self.label.backgroundColor = .clear 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /PageMenuKit/PMKPageMenuItemWeb.swift: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * FILE: PMKPageMenuItemWeb.swift 4 | * DESCRIPTION: PageMenuKit: PageMenuItem Class like "JCNews.tokyo" Web Site 5 | * DATE: Wed, Jun 7 2017 6 | * UPDATED: Thu, Nov 15 2018 7 | * AUTHOR: Kouichi ABE (WALL) / 阿部康一 8 | * E-MAIL: kouichi@MagickWorX.COM 9 | * URL: http://www.MagickWorX.COM/ 10 | * COPYRIGHT: (c) 2017-2018 阿部康一/Kouichi ABE (WALL), All rights reserved. 11 | * LICENSE: 12 | * 13 | * Copyright (c) 2017-2018 Kouichi ABE (WALL) , 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted provided that the following conditions 18 | * are met: 19 | * 20 | * 1. Redistributions of source code must retain the above copyright 21 | * notice, this list of conditions and the following disclaimer. 22 | * 23 | * 2. Redistributions in binary form must reproduce the above copyright 24 | * notice, this list of conditions and the following disclaimer in the 25 | * documentation and/or other materials provided with the distribution. 26 | * 27 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 28 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 29 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 31 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 37 | * THE POSSIBILITY OF SUCH DAMAGE. 38 | * 39 | *****************************************************************************/ 40 | 41 | import UIKit 42 | 43 | public class PMKPageMenuItemWeb: PMKPageMenuItem { 44 | public required init(coder aDecoder: NSCoder) { 45 | fatalError("init(coder:) has not been implemented") 46 | } 47 | 48 | public required init(frame: CGRect, title: String, design: PMKPageMenuItemDesign) { 49 | super.init(frame: frame, title: title, design: design) 50 | 51 | self.style = .web 52 | } 53 | 54 | override func render(active: Bool) { 55 | self.label.textColor = .white 56 | self.label.backgroundColor = { 57 | if active { 58 | return self.design.themeColor 59 | } 60 | else if self.design.inactive.isEnabled { 61 | return self.design.inactive.backgroundColor 62 | } 63 | else { 64 | return UIColor.hexColor(0x332f2e) 65 | } 66 | }() 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /PageMenuKit/PageMenuKit.h: -------------------------------------------------------------------------------- 1 | // 2 | // PageMenuKit.h 3 | // PageMenuKit 4 | // 5 | // Created by Kouichi ABE (WALL) on 2017/06/08. 6 | // Copyright © 2017年 Kouichi ABE (WALL). All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for PageMenuKit. 12 | FOUNDATION_EXPORT double PageMenuKitVersionNumber; 13 | 14 | //! Project version string for PageMenuKit. 15 | FOUNDATION_EXPORT const unsigned char PageMenuKitVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /PageMenuKitDemo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * FILE: AppDelegate.swift 4 | * DESCRIPTION: PageMenuKitDemo: Application Main Controller 5 | * DATE: Fri, Jun 2 2017 6 | * UPDATED: Thu, Nov 15 2018 7 | * AUTHOR: Kouichi ABE (WALL) / 阿部康一 8 | * E-MAIL: kouichi@MagickWorX.COM 9 | * URL: http://www.MagickWorX.COM/ 10 | * COPYRIGHT: (c) 2017-2018 阿部康一/Kouichi ABE (WALL), All rights reserved. 11 | * LICENSE: 12 | * 13 | * Copyright (c) 2017-2018 Kouichi ABE (WALL) , 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted provided that the following conditions 18 | * are met: 19 | * 20 | * 1. Redistributions of source code must retain the above copyright 21 | * notice, this list of conditions and the following disclaimer. 22 | * 23 | * 2. Redistributions in binary form must reproduce the above copyright 24 | * notice, this list of conditions and the following disclaimer in the 25 | * documentation and/or other materials provided with the distribution. 26 | * 27 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 28 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 29 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 31 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 37 | * THE POSSIBILITY OF SUCH DAMAGE. 38 | * 39 | * $Id: AppDelegate.m,v 1.6 2017/04/12 09:59:00 kouichi Exp $ 40 | * 41 | *****************************************************************************/ 42 | 43 | import UIKit 44 | 45 | @UIApplicationMain 46 | class AppDelegate: UIResponder, UIApplicationDelegate 47 | { 48 | open private(set) var themeColor: UIColor? = nil 49 | 50 | var window: UIWindow? 51 | 52 | override init() { 53 | super.init() 54 | } 55 | 56 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 57 | // Override point for customization after application launch. 58 | 59 | // Create full-screen window 60 | self.window = UIWindow(frame: UIScreen.main.bounds) 61 | self.window!.backgroundColor = .white 62 | 63 | // Make root view controller 64 | self.window!.rootViewController = RootViewController() 65 | 66 | // Show window 67 | self.window!.makeKeyAndVisible() 68 | 69 | return true 70 | } 71 | 72 | func applicationWillResignActive(_ application: UIApplication) { 73 | /* 74 | * Sent when the application is about to move from active to inactive state. 75 | * This can occur for certain types of temporary interruptions (such as an 76 | * incoming phone call or SMS message) or when the user quits 77 | * the application and it begins the transition to the background state. 78 | * Use this method to pause ongoing tasks, disable timers, and invalidate 79 | * graphics rendering callbacks. Games should use this method to pause 80 | * the game. 81 | */ 82 | } 83 | 84 | func applicationDidEnterBackground(_ application: UIApplication) { 85 | /* 86 | * Use this method to release shared resources, save user data, 87 | * invalidate timers, and store enough application state information 88 | * to restore your application to its current state in case it is 89 | * terminated later. 90 | * If your application supports background execution, this method is called 91 | * instead of applicationWillTerminate: when the user quits. 92 | */ 93 | } 94 | 95 | func applicationWillEnterForeground(_ application: UIApplication) { 96 | /* 97 | * Called as part of the transition from the background to the active state; 98 | * here you can undo many of the changes made on entering the background. 99 | */ 100 | } 101 | 102 | func applicationDidBecomeActive(_ application: UIApplication) { 103 | /* 104 | * Restart any tasks that were paused (or not yet started) 105 | * while the application was inactive. If the application was previously 106 | * in the background, optionally refresh the user interface. 107 | */ 108 | } 109 | 110 | func applicationWillTerminate(_ application: UIApplication) { 111 | /* 112 | * Called when the application is about to terminate. 113 | * Save data if appropriate. See also applicationDidEnterBackground:. 114 | */ 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /PageMenuKitDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /PageMenuKitDemo/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 | -------------------------------------------------------------------------------- /PageMenuKitDemo/BaseViewController.swift: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * FILE: BaseViewController.swift 4 | * DESCRIPTION: PageMenuKitDemo: Application Base View Controller 5 | * DATE: Fri, Jun 2 2017 6 | * UPDATED: Wed, Nov 29 2017 7 | * AUTHOR: Kouichi ABE (WALL) / 阿部康一 8 | * E-MAIL: kouichi@MagickWorX.COM 9 | * URL: http://www.MagickWorX.COM/ 10 | * COPYRIGHT: (c) 2017 阿部康一/Kouichi ABE (WALL), All rights reserved. 11 | * LICENSE: 12 | * 13 | * Copyright (c) 2017 Kouichi ABE (WALL) , 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted provided that the following conditions 18 | * are met: 19 | * 20 | * 1. Redistributions of source code must retain the above copyright 21 | * notice, this list of conditions and the following disclaimer. 22 | * 23 | * 2. Redistributions in binary form must reproduce the above copyright 24 | * notice, this list of conditions and the following disclaimer in the 25 | * documentation and/or other materials provided with the distribution. 26 | * 27 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 28 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 29 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 31 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 37 | * THE POSSIBILITY OF SUCH DAMAGE. 38 | * 39 | * $Id: AppDelegate.m,v 1.6 2017/04/12 09:59:00 kouichi Exp $ 40 | * 41 | *****************************************************************************/ 42 | 43 | import UIKit 44 | 45 | class BaseViewController: UIViewController 46 | { 47 | required init(coder aDecoder: NSCoder) { 48 | fatalError("NSCoding not supported") 49 | } 50 | 51 | init() { 52 | super.init(nibName: nil, bundle: nil) 53 | setup() 54 | } 55 | 56 | override func loadView() { 57 | super.loadView() 58 | 59 | self.edgesForExtendedLayout = [] 60 | self.extendedLayoutIncludesOpaqueBars = true 61 | 62 | self.view.backgroundColor = .white 63 | self.view.autoresizesSubviews = true 64 | self.view.autoresizingMask = [ .flexibleWidth, .flexibleHeight ] 65 | } 66 | 67 | func setup() { 68 | // actual contents of init(). subclass can override this. 69 | } 70 | 71 | override func viewDidLoad() { 72 | super.viewDidLoad() 73 | // Do any additional setup after loading the view, typically from a nib. 74 | } 75 | 76 | override func didReceiveMemoryWarning() { 77 | super.didReceiveMemoryWarning() 78 | // Dispose of any resources that can be recreated. 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /PageMenuKitDemo/DataViewController.swift: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * FILE: DataViewController.swift 4 | * DESCRIPTION: PageMenuKitDemo: Data View Controller 5 | * DATE: Mon, Jun 5 2017 6 | * UPDATED: Thu, Jun 8 2017 7 | * AUTHOR: Kouichi ABE (WALL) / 阿部康一 8 | * E-MAIL: kouichi@MagickWorX.COM 9 | * URL: http://www.MagickWorX.COM/ 10 | * COPYRIGHT: (c) 2017 阿部康一/Kouichi ABE (WALL), All rights reserved. 11 | * LICENSE: 12 | * 13 | * Copyright (c) 2017 Kouichi ABE (WALL) , 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted provided that the following conditions 18 | * are met: 19 | * 20 | * 1. Redistributions of source code must retain the above copyright 21 | * notice, this list of conditions and the following disclaimer. 22 | * 23 | * 2. Redistributions in binary form must reproduce the above copyright 24 | * notice, this list of conditions and the following disclaimer in the 25 | * documentation and/or other materials provided with the distribution. 26 | * 27 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 28 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 29 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 31 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 37 | * THE POSSIBILITY OF SUCH DAMAGE. 38 | * 39 | * $Id: AppDelegate.m,v 1.6 2017/04/12 09:59:00 kouichi Exp $ 40 | * 41 | *****************************************************************************/ 42 | 43 | import UIKit 44 | 45 | class DataViewController: BaseViewController 46 | { 47 | public private(set) var textLabel: UILabel? = nil 48 | 49 | override func setup() { 50 | super.setup() 51 | 52 | self.title = "Demo" 53 | } 54 | 55 | override func didReceiveMemoryWarning() { 56 | super.didReceiveMemoryWarning() 57 | // Dispose of any resources that can be recreated. 58 | } 59 | 60 | override func loadView() { 61 | super.loadView() 62 | 63 | let label = UILabel(frame: self.view.bounds) 64 | label.backgroundColor = UIColor.hexColor(0xccccff) 65 | label.font = UIFont.systemFont(ofSize: 64.0) 66 | label.textAlignment = .center 67 | label.adjustsFontSizeToFitWidth = true 68 | self.view.addSubview(label) 69 | self.textLabel = label 70 | } 71 | 72 | override func viewDidLoad() { 73 | super.viewDidLoad() 74 | } 75 | 76 | override func viewWillAppear(_ animated: Bool) { 77 | super.viewWillAppear(animated) 78 | 79 | self.textLabel?.text = self.title 80 | 81 | self.navigationController?.navigationBar.isHidden = true 82 | } 83 | 84 | override func viewWillDisappear(_ animated: Bool) { 85 | super.viewWillDisappear(animated) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /PageMenuKitDemo/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 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIRequiredDeviceCapabilities 26 | 27 | armv7 28 | 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | 33 | UISupportedInterfaceOrientations~ipad 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationPortraitUpsideDown 37 | UIInterfaceOrientationLandscapeLeft 38 | UIInterfaceOrientationLandscapeRight 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /PageMenuKitDemo/RootViewController.swift: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * FILE: RootViewController.swift 4 | * DESCRIPTION: PageMenuKitDemo: Application Root View Controller 5 | * DATE: Fri, Jun 2 2017 6 | * UPDATED: Mon, Feb 18 2019 7 | * AUTHOR: Kouichi ABE (WALL) / 阿部康一 8 | * E-MAIL: kouichi@MagickWorX.COM 9 | * URL: http://www.MagickWorX.COM/ 10 | * COPYRIGHT: (c) 2017-2019 阿部康一/Kouichi ABE (WALL), All rights reserved. 11 | * LICENSE: 12 | * 13 | * Copyright (c) 2017-2019 Kouichi ABE (WALL) , 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted provided that the following conditions 18 | * are met: 19 | * 20 | * 1. Redistributions of source code must retain the above copyright 21 | * notice, this list of conditions and the following disclaimer. 22 | * 23 | * 2. Redistributions in binary form must reproduce the above copyright 24 | * notice, this list of conditions and the following disclaimer in the 25 | * documentation and/or other materials provided with the distribution. 26 | * 27 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 28 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 29 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 31 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 37 | * THE POSSIBILITY OF SUCH DAMAGE. 38 | * 39 | * $Id: AppDelegate.m,v 1.6 2017/04/12 09:59:00 kouichi Exp $ 40 | * 41 | *****************************************************************************/ 42 | 43 | import UIKit 44 | import PageMenuKit 45 | 46 | class RootViewController: BaseViewController 47 | { 48 | var pageMenuController: PMKPageMenuController? = nil 49 | 50 | override func setup() { 51 | super.setup() 52 | 53 | self.title = "PageMenuKit Frameworks" 54 | } 55 | 56 | override func didReceiveMemoryWarning() { 57 | super.didReceiveMemoryWarning() 58 | // Dispose of any resources that can be recreated. 59 | } 60 | 61 | override func loadView() { 62 | super.loadView() 63 | } 64 | 65 | override func viewDidLoad() { 66 | super.viewDidLoad() 67 | 68 | var controllers: [UIViewController] = [] 69 | let dateFormatter = DateFormatter() 70 | for month in dateFormatter.monthSymbols { 71 | let viewController: DataViewController = DataViewController() 72 | viewController.title = month 73 | controllers.append(viewController) 74 | } 75 | 76 | let statusBarHeight: CGFloat = UIApplication.shared.statusBarFrame.size.height 77 | /* 78 | * Available menuStyles: 79 | * .plain, .tab, .smart, .hacka, .ellipse, .web, .suite, .netlab, .nhk 80 | * See PMKPageMenuItem.swift in PageMenuKit folder. 81 | * "menuColors: []" means that we will use the default colors. 82 | * "startIndex" can be set 1...controllers.count. 83 | */ 84 | pageMenuController = PMKPageMenuController(controllers: controllers, menuStyle: .smart, menuColors: [], startIndex: 1, topBarHeight: statusBarHeight) 85 | // pageMenuController = PMKPageMenuController(controllers: controllers, menuStyle: .plain, menuColors: [.purple], startIndex: 8, topBarHeight: statusBarHeight) 86 | pageMenuController?.delegate = self 87 | self.addChild(pageMenuController!) 88 | self.view.addSubview(pageMenuController!.view) 89 | pageMenuController?.didMove(toParent: self) 90 | } 91 | 92 | override func viewWillAppear(_ animated: Bool) { 93 | super.viewWillAppear(animated) 94 | 95 | self.navigationController?.navigationBar.isHidden = false 96 | } 97 | } 98 | 99 | extension RootViewController: PMKPageMenuControllerDelegate 100 | { 101 | func pageMenuController(_ pageMenuController: PMKPageMenuController, willMoveTo viewController: UIViewController, at menuIndex: Int) { 102 | } 103 | 104 | func pageMenuController(_ pageMenuController: PMKPageMenuController, didMoveTo viewController: UIViewController, at menuIndex: Int) { 105 | } 106 | 107 | func pageMenuController(_ pageMenuController: PMKPageMenuController, didPrepare menuItems: [PMKPageMenuItem]) { 108 | // XXX: For .hacka style 109 | var i: Int = 1 110 | for item: PMKPageMenuItem in menuItems { 111 | item.badgeValue = String(format: "%zd", i) 112 | i += 1 113 | } 114 | } 115 | 116 | func pageMenuController(_ pageMenuController: PMKPageMenuController, didSelect menuItem: PMKPageMenuItem, at menuIndex: Int) { 117 | menuItem.badgeValue = nil // XXX: For .hacka style 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /PageMenuKitSwift.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXAggregateTarget section */ 10 | B33FF34C258B2415004DBC52 /* PageMenuKitSwiftXCFramework */ = { 11 | isa = PBXAggregateTarget; 12 | buildConfigurationList = B33FF34F258B2415004DBC52 /* Build configuration list for PBXAggregateTarget "PageMenuKitSwiftXCFramework" */; 13 | buildPhases = ( 14 | B33FF353258B2426004DBC52 /* ShellScript */, 15 | ); 16 | dependencies = ( 17 | ); 18 | name = PageMenuKitSwiftXCFramework; 19 | productName = PageMenuKitSwiftXCFramework; 20 | }; 21 | /* End PBXAggregateTarget section */ 22 | 23 | /* Begin PBXBuildFile section */ 24 | B3650E861EEA566500B3D2BB /* PMKPageMenuItemNHK.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3650E851EEA566500B3D2BB /* PMKPageMenuItemNHK.swift */; }; 25 | B3FA139D23A2A86D00F1C379 /* PageMenuKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B3FD5BAD1EE967A000842272 /* PageMenuKit.framework */; }; 26 | B3FA139E23A2A86E00F1C379 /* PageMenuKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B3FD5BAD1EE967A000842272 /* PageMenuKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 27 | B3FD5BB11EE967A000842272 /* PageMenuKit.h in Headers */ = {isa = PBXBuildFile; fileRef = B3FD5BAF1EE967A000842272 /* PageMenuKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; 28 | B3FD5BC71EE96AC100842272 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3FD5BC61EE96AC100842272 /* AppDelegate.swift */; }; 29 | B3FD5BCE1EE96AC100842272 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B3FD5BCD1EE96AC100842272 /* Assets.xcassets */; }; 30 | B3FD5BD11EE96AC100842272 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B3FD5BCF1EE96AC100842272 /* LaunchScreen.storyboard */; }; 31 | B3FD5BE11EE96B1500842272 /* PMKPageMenuController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3FD5BD61EE96B1500842272 /* PMKPageMenuController.swift */; }; 32 | B3FD5BE21EE96B1500842272 /* PMKPageMenuControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3FD5BD71EE96B1500842272 /* PMKPageMenuControllerDelegate.swift */; }; 33 | B3FD5BE31EE96B1500842272 /* PMKPageMenuItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3FD5BD81EE96B1500842272 /* PMKPageMenuItem.swift */; }; 34 | B3FD5BE41EE96B1500842272 /* PMKPageMenuItemEllipse.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3FD5BD91EE96B1500842272 /* PMKPageMenuItemEllipse.swift */; }; 35 | B3FD5BE51EE96B1500842272 /* PMKPageMenuItemHacka.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3FD5BDA1EE96B1500842272 /* PMKPageMenuItemHacka.swift */; }; 36 | B3FD5BE61EE96B1500842272 /* PMKPageMenuItemNetLab.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3FD5BDB1EE96B1500842272 /* PMKPageMenuItemNetLab.swift */; }; 37 | B3FD5BE71EE96B1500842272 /* PMKPageMenuItemPlain.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3FD5BDC1EE96B1500842272 /* PMKPageMenuItemPlain.swift */; }; 38 | B3FD5BE81EE96B1500842272 /* PMKPageMenuItemSmart.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3FD5BDD1EE96B1500842272 /* PMKPageMenuItemSmart.swift */; }; 39 | B3FD5BE91EE96B1500842272 /* PMKPageMenuItemSuite.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3FD5BDE1EE96B1500842272 /* PMKPageMenuItemSuite.swift */; }; 40 | B3FD5BEA1EE96B1500842272 /* PMKPageMenuItemTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3FD5BDF1EE96B1500842272 /* PMKPageMenuItemTab.swift */; }; 41 | B3FD5BEB1EE96B1500842272 /* PMKPageMenuItemWeb.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3FD5BE01EE96B1500842272 /* PMKPageMenuItemWeb.swift */; }; 42 | B3FD5BED1EE96DE100842272 /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3FD5BEC1EE96DE100842272 /* BaseViewController.swift */; }; 43 | B3FD5BEF1EE96DE800842272 /* RootViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3FD5BEE1EE96DE800842272 /* RootViewController.swift */; }; 44 | B3FD5BF11EE96DEF00842272 /* DataViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3FD5BF01EE96DEF00842272 /* DataViewController.swift */; }; 45 | /* End PBXBuildFile section */ 46 | 47 | /* Begin PBXContainerItemProxy section */ 48 | B3650E871EEA797500B3D2BB /* PBXContainerItemProxy */ = { 49 | isa = PBXContainerItemProxy; 50 | containerPortal = B3FD5B8B1EE966FB00842272 /* Project object */; 51 | proxyType = 1; 52 | remoteGlobalIDString = B3FD5BAC1EE967A000842272; 53 | remoteInfo = PageMenuKit; 54 | }; 55 | /* End PBXContainerItemProxy section */ 56 | 57 | /* Begin PBXCopyFilesBuildPhase section */ 58 | B3FA139F23A2A86E00F1C379 /* Embed Frameworks */ = { 59 | isa = PBXCopyFilesBuildPhase; 60 | buildActionMask = 2147483647; 61 | dstPath = ""; 62 | dstSubfolderSpec = 10; 63 | files = ( 64 | B3FA139E23A2A86E00F1C379 /* PageMenuKit.framework in Embed Frameworks */, 65 | ); 66 | name = "Embed Frameworks"; 67 | runOnlyForDeploymentPostprocessing = 0; 68 | }; 69 | /* End PBXCopyFilesBuildPhase section */ 70 | 71 | /* Begin PBXFileReference section */ 72 | B3650E851EEA566500B3D2BB /* PMKPageMenuItemNHK.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PMKPageMenuItemNHK.swift; sourceTree = ""; }; 73 | B3FD5BAD1EE967A000842272 /* PageMenuKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PageMenuKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 74 | B3FD5BAF1EE967A000842272 /* PageMenuKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PageMenuKit.h; sourceTree = ""; }; 75 | B3FD5BB01EE967A000842272 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 76 | B3FD5BC41EE96AC000842272 /* PageMenuKitDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PageMenuKitDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 77 | B3FD5BC61EE96AC100842272 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 78 | B3FD5BCD1EE96AC100842272 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 79 | B3FD5BD01EE96AC100842272 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 80 | B3FD5BD21EE96AC100842272 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 81 | B3FD5BD61EE96B1500842272 /* PMKPageMenuController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PMKPageMenuController.swift; sourceTree = ""; }; 82 | B3FD5BD71EE96B1500842272 /* PMKPageMenuControllerDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PMKPageMenuControllerDelegate.swift; sourceTree = ""; }; 83 | B3FD5BD81EE96B1500842272 /* PMKPageMenuItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PMKPageMenuItem.swift; sourceTree = ""; }; 84 | B3FD5BD91EE96B1500842272 /* PMKPageMenuItemEllipse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PMKPageMenuItemEllipse.swift; sourceTree = ""; }; 85 | B3FD5BDA1EE96B1500842272 /* PMKPageMenuItemHacka.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PMKPageMenuItemHacka.swift; sourceTree = ""; }; 86 | B3FD5BDB1EE96B1500842272 /* PMKPageMenuItemNetLab.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PMKPageMenuItemNetLab.swift; sourceTree = ""; }; 87 | B3FD5BDC1EE96B1500842272 /* PMKPageMenuItemPlain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PMKPageMenuItemPlain.swift; sourceTree = ""; }; 88 | B3FD5BDD1EE96B1500842272 /* PMKPageMenuItemSmart.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PMKPageMenuItemSmart.swift; sourceTree = ""; }; 89 | B3FD5BDE1EE96B1500842272 /* PMKPageMenuItemSuite.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PMKPageMenuItemSuite.swift; sourceTree = ""; }; 90 | B3FD5BDF1EE96B1500842272 /* PMKPageMenuItemTab.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PMKPageMenuItemTab.swift; sourceTree = ""; }; 91 | B3FD5BE01EE96B1500842272 /* PMKPageMenuItemWeb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PMKPageMenuItemWeb.swift; sourceTree = ""; }; 92 | B3FD5BEC1EE96DE100842272 /* BaseViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseViewController.swift; sourceTree = ""; }; 93 | B3FD5BEE1EE96DE800842272 /* RootViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootViewController.swift; sourceTree = ""; }; 94 | B3FD5BF01EE96DEF00842272 /* DataViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataViewController.swift; sourceTree = ""; }; 95 | /* End PBXFileReference section */ 96 | 97 | /* Begin PBXFrameworksBuildPhase section */ 98 | B3FD5BA91EE967A000842272 /* Frameworks */ = { 99 | isa = PBXFrameworksBuildPhase; 100 | buildActionMask = 2147483647; 101 | files = ( 102 | ); 103 | runOnlyForDeploymentPostprocessing = 0; 104 | }; 105 | B3FD5BC11EE96AC000842272 /* Frameworks */ = { 106 | isa = PBXFrameworksBuildPhase; 107 | buildActionMask = 2147483647; 108 | files = ( 109 | B3FA139D23A2A86D00F1C379 /* PageMenuKit.framework in Frameworks */, 110 | ); 111 | runOnlyForDeploymentPostprocessing = 0; 112 | }; 113 | /* End PBXFrameworksBuildPhase section */ 114 | 115 | /* Begin PBXGroup section */ 116 | B3FD5B8A1EE966FB00842272 = { 117 | isa = PBXGroup; 118 | children = ( 119 | B3FD5BAE1EE967A000842272 /* PageMenuKit */, 120 | B3FD5BC51EE96AC000842272 /* PageMenuKitDemo */, 121 | B3FD5B941EE966FB00842272 /* Products */, 122 | ); 123 | sourceTree = ""; 124 | }; 125 | B3FD5B941EE966FB00842272 /* Products */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | B3FD5BAD1EE967A000842272 /* PageMenuKit.framework */, 129 | B3FD5BC41EE96AC000842272 /* PageMenuKitDemo.app */, 130 | ); 131 | name = Products; 132 | sourceTree = ""; 133 | }; 134 | B3FD5BAE1EE967A000842272 /* PageMenuKit */ = { 135 | isa = PBXGroup; 136 | children = ( 137 | B3650E851EEA566500B3D2BB /* PMKPageMenuItemNHK.swift */, 138 | B3FD5BD61EE96B1500842272 /* PMKPageMenuController.swift */, 139 | B3FD5BD71EE96B1500842272 /* PMKPageMenuControllerDelegate.swift */, 140 | B3FD5BD81EE96B1500842272 /* PMKPageMenuItem.swift */, 141 | B3FD5BD91EE96B1500842272 /* PMKPageMenuItemEllipse.swift */, 142 | B3FD5BDA1EE96B1500842272 /* PMKPageMenuItemHacka.swift */, 143 | B3FD5BDB1EE96B1500842272 /* PMKPageMenuItemNetLab.swift */, 144 | B3FD5BDC1EE96B1500842272 /* PMKPageMenuItemPlain.swift */, 145 | B3FD5BDD1EE96B1500842272 /* PMKPageMenuItemSmart.swift */, 146 | B3FD5BDE1EE96B1500842272 /* PMKPageMenuItemSuite.swift */, 147 | B3FD5BDF1EE96B1500842272 /* PMKPageMenuItemTab.swift */, 148 | B3FD5BE01EE96B1500842272 /* PMKPageMenuItemWeb.swift */, 149 | B3FD5BAF1EE967A000842272 /* PageMenuKit.h */, 150 | B3FD5BB01EE967A000842272 /* Info.plist */, 151 | ); 152 | path = PageMenuKit; 153 | sourceTree = ""; 154 | }; 155 | B3FD5BC51EE96AC000842272 /* PageMenuKitDemo */ = { 156 | isa = PBXGroup; 157 | children = ( 158 | B3FD5BF01EE96DEF00842272 /* DataViewController.swift */, 159 | B3FD5BEE1EE96DE800842272 /* RootViewController.swift */, 160 | B3FD5BEC1EE96DE100842272 /* BaseViewController.swift */, 161 | B3FD5BC61EE96AC100842272 /* AppDelegate.swift */, 162 | B3FD5BCD1EE96AC100842272 /* Assets.xcassets */, 163 | B3FD5BCF1EE96AC100842272 /* LaunchScreen.storyboard */, 164 | B3FD5BD21EE96AC100842272 /* Info.plist */, 165 | ); 166 | path = PageMenuKitDemo; 167 | sourceTree = ""; 168 | }; 169 | /* End PBXGroup section */ 170 | 171 | /* Begin PBXHeadersBuildPhase section */ 172 | B3FD5BAA1EE967A000842272 /* Headers */ = { 173 | isa = PBXHeadersBuildPhase; 174 | buildActionMask = 2147483647; 175 | files = ( 176 | B3FD5BB11EE967A000842272 /* PageMenuKit.h in Headers */, 177 | ); 178 | runOnlyForDeploymentPostprocessing = 0; 179 | }; 180 | /* End PBXHeadersBuildPhase section */ 181 | 182 | /* Begin PBXNativeTarget section */ 183 | B3FD5BAC1EE967A000842272 /* PageMenuKit */ = { 184 | isa = PBXNativeTarget; 185 | buildConfigurationList = B3FD5BB61EE967A000842272 /* Build configuration list for PBXNativeTarget "PageMenuKit" */; 186 | buildPhases = ( 187 | B3FD5BA81EE967A000842272 /* Sources */, 188 | B3FD5BA91EE967A000842272 /* Frameworks */, 189 | B3FD5BAA1EE967A000842272 /* Headers */, 190 | B3FD5BAB1EE967A000842272 /* Resources */, 191 | ); 192 | buildRules = ( 193 | ); 194 | dependencies = ( 195 | ); 196 | name = PageMenuKit; 197 | productName = PageMenuKit; 198 | productReference = B3FD5BAD1EE967A000842272 /* PageMenuKit.framework */; 199 | productType = "com.apple.product-type.framework"; 200 | }; 201 | B3FD5BC31EE96AC000842272 /* PageMenuKitDemo */ = { 202 | isa = PBXNativeTarget; 203 | buildConfigurationList = B3FD5BD31EE96AC100842272 /* Build configuration list for PBXNativeTarget "PageMenuKitDemo" */; 204 | buildPhases = ( 205 | B3FD5BC01EE96AC000842272 /* Sources */, 206 | B3FD5BC11EE96AC000842272 /* Frameworks */, 207 | B3FD5BC21EE96AC000842272 /* Resources */, 208 | B3FA139F23A2A86E00F1C379 /* Embed Frameworks */, 209 | ); 210 | buildRules = ( 211 | ); 212 | dependencies = ( 213 | B3650E881EEA797500B3D2BB /* PBXTargetDependency */, 214 | ); 215 | name = PageMenuKitDemo; 216 | productName = PageMenuKitDemo; 217 | productReference = B3FD5BC41EE96AC000842272 /* PageMenuKitDemo.app */; 218 | productType = "com.apple.product-type.application"; 219 | }; 220 | /* End PBXNativeTarget section */ 221 | 222 | /* Begin PBXProject section */ 223 | B3FD5B8B1EE966FB00842272 /* Project object */ = { 224 | isa = PBXProject; 225 | attributes = { 226 | LastSwiftUpdateCheck = 0830; 227 | LastUpgradeCheck = 1020; 228 | ORGANIZATIONNAME = "Kouichi ABE (WALL)"; 229 | TargetAttributes = { 230 | B33FF34C258B2415004DBC52 = { 231 | CreatedOnToolsVersion = 12.3; 232 | ProvisioningStyle = Automatic; 233 | }; 234 | B3FD5BAC1EE967A000842272 = { 235 | CreatedOnToolsVersion = 8.3.2; 236 | LastSwiftMigration = 0830; 237 | ProvisioningStyle = Automatic; 238 | }; 239 | B3FD5BC31EE96AC000842272 = { 240 | CreatedOnToolsVersion = 8.3.2; 241 | ProvisioningStyle = Automatic; 242 | }; 243 | }; 244 | }; 245 | buildConfigurationList = B3FD5B8E1EE966FB00842272 /* Build configuration list for PBXProject "PageMenuKitSwift" */; 246 | compatibilityVersion = "Xcode 3.2"; 247 | developmentRegion = en; 248 | hasScannedForEncodings = 0; 249 | knownRegions = ( 250 | en, 251 | Base, 252 | ); 253 | mainGroup = B3FD5B8A1EE966FB00842272; 254 | productRefGroup = B3FD5B941EE966FB00842272 /* Products */; 255 | projectDirPath = ""; 256 | projectRoot = ""; 257 | targets = ( 258 | B3FD5BAC1EE967A000842272 /* PageMenuKit */, 259 | B3FD5BC31EE96AC000842272 /* PageMenuKitDemo */, 260 | B33FF34C258B2415004DBC52 /* PageMenuKitSwiftXCFramework */, 261 | ); 262 | }; 263 | /* End PBXProject section */ 264 | 265 | /* Begin PBXResourcesBuildPhase section */ 266 | B3FD5BAB1EE967A000842272 /* Resources */ = { 267 | isa = PBXResourcesBuildPhase; 268 | buildActionMask = 2147483647; 269 | files = ( 270 | ); 271 | runOnlyForDeploymentPostprocessing = 0; 272 | }; 273 | B3FD5BC21EE96AC000842272 /* Resources */ = { 274 | isa = PBXResourcesBuildPhase; 275 | buildActionMask = 2147483647; 276 | files = ( 277 | B3FD5BD11EE96AC100842272 /* LaunchScreen.storyboard in Resources */, 278 | B3FD5BCE1EE96AC100842272 /* Assets.xcassets in Resources */, 279 | ); 280 | runOnlyForDeploymentPostprocessing = 0; 281 | }; 282 | /* End PBXResourcesBuildPhase section */ 283 | 284 | /* Begin PBXShellScriptBuildPhase section */ 285 | B33FF353258B2426004DBC52 /* ShellScript */ = { 286 | isa = PBXShellScriptBuildPhase; 287 | buildActionMask = 2147483647; 288 | files = ( 289 | ); 290 | inputFileListPaths = ( 291 | ); 292 | inputPaths = ( 293 | ); 294 | outputFileListPaths = ( 295 | ); 296 | outputPaths = ( 297 | ); 298 | runOnlyForDeploymentPostprocessing = 0; 299 | shellPath = /bin/sh; 300 | shellScript = "#!/bin/sh\n\nOUTPUT_FOLDER=${BUILD_DIR}/${CONFIGURATION}-xcframework\n\nARCHS_IOS=\"arm64\"\nARCHS_SIMULATOR=\"x86_64\"\n\nSCHEME_NAME=\"PageMenuKit\"\n\n# make sure the output directory exists\nmkdir -p \"${OUTPUT_FOLDER}\"\n\n# Step 1. Archive Device and Simulator versions\nmk_archive() {\n archs=$1\n platform=$2\n output=$3\n\n xcodebuild \\\n ENABLE_BITCODE=YES \\\n BITCODE_GENERATION_MODE=bitcode \\\n OTHER_CFLAGS=\"-fembed-bitcode\" \\\n BUILD_LIBRARY_FOR_DISTRIBUTION=YES \\\n SKIP_INSTALL=NO \\\n ONLY_ACTIVE_ARCH=YES \\\n ARCHS=\"${archs}\" \\\n -project \"${PROJECT_NAME}.xcodeproj\" \\\n -configuration \"${CONFIGURATION}\" \\\n -scheme \"${SCHEME_NAME}\" \\\n -destination \"generic/platform=${platform}\" \\\n -archivePath \"${OUTPUT_FOLDER}/${PROJECT_NAME}-${output}\" \\\n archive\n}\n\nmk_archive ${ARCHS_IOS} \"iOS\" \"iOS\"\nmk_archive ${ARCHS_SIMULATOR} \"iOS Simulator\" \"iOS_Simulator\"\n\n# Step 2. Create xcframework with all frameworks\nxcodebuild \\\n-create-xcframework \\\n-framework \"${OUTPUT_FOLDER}/${PROJECT_NAME}-iOS.xcarchive/Products/Library/Frameworks/${SCHEME_NAME}.framework\" \\\n-framework \"${OUTPUT_FOLDER}/${PROJECT_NAME}-iOS_Simulator.xcarchive/Products/Library/Frameworks/${SCHEME_NAME}.framework\" \\\n-output \"${OUTPUT_FOLDER}/${SCHEME_NAME}.xcframework\"\n\n# Step 3. Convenience step to open the output's directory in Finder\nopen \"${OUTPUT_FOLDER}\"\n"; 301 | }; 302 | /* End PBXShellScriptBuildPhase section */ 303 | 304 | /* Begin PBXSourcesBuildPhase section */ 305 | B3FD5BA81EE967A000842272 /* Sources */ = { 306 | isa = PBXSourcesBuildPhase; 307 | buildActionMask = 2147483647; 308 | files = ( 309 | B3FD5BE11EE96B1500842272 /* PMKPageMenuController.swift in Sources */, 310 | B3FD5BE71EE96B1500842272 /* PMKPageMenuItemPlain.swift in Sources */, 311 | B3FD5BE61EE96B1500842272 /* PMKPageMenuItemNetLab.swift in Sources */, 312 | B3FD5BEB1EE96B1500842272 /* PMKPageMenuItemWeb.swift in Sources */, 313 | B3FD5BEA1EE96B1500842272 /* PMKPageMenuItemTab.swift in Sources */, 314 | B3FD5BE21EE96B1500842272 /* PMKPageMenuControllerDelegate.swift in Sources */, 315 | B3FD5BE41EE96B1500842272 /* PMKPageMenuItemEllipse.swift in Sources */, 316 | B3FD5BE81EE96B1500842272 /* PMKPageMenuItemSmart.swift in Sources */, 317 | B3FD5BE31EE96B1500842272 /* PMKPageMenuItem.swift in Sources */, 318 | B3650E861EEA566500B3D2BB /* PMKPageMenuItemNHK.swift in Sources */, 319 | B3FD5BE91EE96B1500842272 /* PMKPageMenuItemSuite.swift in Sources */, 320 | B3FD5BE51EE96B1500842272 /* PMKPageMenuItemHacka.swift in Sources */, 321 | ); 322 | runOnlyForDeploymentPostprocessing = 0; 323 | }; 324 | B3FD5BC01EE96AC000842272 /* Sources */ = { 325 | isa = PBXSourcesBuildPhase; 326 | buildActionMask = 2147483647; 327 | files = ( 328 | B3FD5BF11EE96DEF00842272 /* DataViewController.swift in Sources */, 329 | B3FD5BC71EE96AC100842272 /* AppDelegate.swift in Sources */, 330 | B3FD5BED1EE96DE100842272 /* BaseViewController.swift in Sources */, 331 | B3FD5BEF1EE96DE800842272 /* RootViewController.swift in Sources */, 332 | ); 333 | runOnlyForDeploymentPostprocessing = 0; 334 | }; 335 | /* End PBXSourcesBuildPhase section */ 336 | 337 | /* Begin PBXTargetDependency section */ 338 | B3650E881EEA797500B3D2BB /* PBXTargetDependency */ = { 339 | isa = PBXTargetDependency; 340 | target = B3FD5BAC1EE967A000842272 /* PageMenuKit */; 341 | targetProxy = B3650E871EEA797500B3D2BB /* PBXContainerItemProxy */; 342 | }; 343 | /* End PBXTargetDependency section */ 344 | 345 | /* Begin PBXVariantGroup section */ 346 | B3FD5BCF1EE96AC100842272 /* LaunchScreen.storyboard */ = { 347 | isa = PBXVariantGroup; 348 | children = ( 349 | B3FD5BD01EE96AC100842272 /* Base */, 350 | ); 351 | name = LaunchScreen.storyboard; 352 | sourceTree = ""; 353 | }; 354 | /* End PBXVariantGroup section */ 355 | 356 | /* Begin XCBuildConfiguration section */ 357 | B33FF34D258B2415004DBC52 /* Debug */ = { 358 | isa = XCBuildConfiguration; 359 | buildSettings = { 360 | CODE_SIGN_STYLE = Automatic; 361 | PRODUCT_NAME = "$(TARGET_NAME)"; 362 | }; 363 | name = Debug; 364 | }; 365 | B33FF34E258B2415004DBC52 /* Release */ = { 366 | isa = XCBuildConfiguration; 367 | buildSettings = { 368 | CODE_SIGN_STYLE = Automatic; 369 | PRODUCT_NAME = "$(TARGET_NAME)"; 370 | }; 371 | name = Release; 372 | }; 373 | B3FD5BA31EE966FC00842272 /* Debug */ = { 374 | isa = XCBuildConfiguration; 375 | buildSettings = { 376 | ALWAYS_SEARCH_USER_PATHS = NO; 377 | CLANG_ANALYZER_NONNULL = YES; 378 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 379 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 380 | CLANG_CXX_LIBRARY = "libc++"; 381 | CLANG_ENABLE_MODULES = YES; 382 | CLANG_ENABLE_OBJC_ARC = YES; 383 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 384 | CLANG_WARN_BOOL_CONVERSION = YES; 385 | CLANG_WARN_COMMA = YES; 386 | CLANG_WARN_CONSTANT_CONVERSION = YES; 387 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 388 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 389 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 390 | CLANG_WARN_EMPTY_BODY = YES; 391 | CLANG_WARN_ENUM_CONVERSION = YES; 392 | CLANG_WARN_INFINITE_RECURSION = YES; 393 | CLANG_WARN_INT_CONVERSION = YES; 394 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 395 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 396 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 397 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 398 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 399 | CLANG_WARN_STRICT_PROTOTYPES = YES; 400 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 401 | CLANG_WARN_UNREACHABLE_CODE = YES; 402 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 403 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 404 | COPY_PHASE_STRIP = NO; 405 | DEBUG_INFORMATION_FORMAT = dwarf; 406 | ENABLE_STRICT_OBJC_MSGSEND = YES; 407 | ENABLE_TESTABILITY = YES; 408 | GCC_C_LANGUAGE_STANDARD = gnu99; 409 | GCC_DYNAMIC_NO_PIC = NO; 410 | GCC_NO_COMMON_BLOCKS = YES; 411 | GCC_OPTIMIZATION_LEVEL = 0; 412 | GCC_PREPROCESSOR_DEFINITIONS = ( 413 | "DEBUG=1", 414 | "$(inherited)", 415 | ); 416 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 417 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 418 | GCC_WARN_UNDECLARED_SELECTOR = YES; 419 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 420 | GCC_WARN_UNUSED_FUNCTION = YES; 421 | GCC_WARN_UNUSED_VARIABLE = YES; 422 | IPHONEOS_DEPLOYMENT_TARGET = 13.6; 423 | MTL_ENABLE_DEBUG_INFO = YES; 424 | ONLY_ACTIVE_ARCH = YES; 425 | SDKROOT = iphoneos; 426 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 427 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 428 | TARGETED_DEVICE_FAMILY = "1,2"; 429 | }; 430 | name = Debug; 431 | }; 432 | B3FD5BA41EE966FC00842272 /* Release */ = { 433 | isa = XCBuildConfiguration; 434 | buildSettings = { 435 | ALWAYS_SEARCH_USER_PATHS = NO; 436 | CLANG_ANALYZER_NONNULL = YES; 437 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 438 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 439 | CLANG_CXX_LIBRARY = "libc++"; 440 | CLANG_ENABLE_MODULES = YES; 441 | CLANG_ENABLE_OBJC_ARC = YES; 442 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 443 | CLANG_WARN_BOOL_CONVERSION = YES; 444 | CLANG_WARN_COMMA = YES; 445 | CLANG_WARN_CONSTANT_CONVERSION = YES; 446 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 447 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 448 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 449 | CLANG_WARN_EMPTY_BODY = YES; 450 | CLANG_WARN_ENUM_CONVERSION = YES; 451 | CLANG_WARN_INFINITE_RECURSION = YES; 452 | CLANG_WARN_INT_CONVERSION = YES; 453 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 454 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 455 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 456 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 457 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 458 | CLANG_WARN_STRICT_PROTOTYPES = YES; 459 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 460 | CLANG_WARN_UNREACHABLE_CODE = YES; 461 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 462 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 463 | COPY_PHASE_STRIP = NO; 464 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 465 | ENABLE_NS_ASSERTIONS = NO; 466 | ENABLE_STRICT_OBJC_MSGSEND = YES; 467 | GCC_C_LANGUAGE_STANDARD = gnu99; 468 | GCC_NO_COMMON_BLOCKS = YES; 469 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 470 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 471 | GCC_WARN_UNDECLARED_SELECTOR = YES; 472 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 473 | GCC_WARN_UNUSED_FUNCTION = YES; 474 | GCC_WARN_UNUSED_VARIABLE = YES; 475 | IPHONEOS_DEPLOYMENT_TARGET = 13.6; 476 | MTL_ENABLE_DEBUG_INFO = NO; 477 | SDKROOT = iphoneos; 478 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 479 | TARGETED_DEVICE_FAMILY = "1,2"; 480 | VALIDATE_PRODUCT = YES; 481 | }; 482 | name = Release; 483 | }; 484 | B3FD5BB71EE967A000842272 /* Debug */ = { 485 | isa = XCBuildConfiguration; 486 | buildSettings = { 487 | CLANG_ENABLE_MODULES = YES; 488 | CODE_SIGN_IDENTITY = ""; 489 | CURRENT_PROJECT_VERSION = 2; 490 | DEFINES_MODULE = YES; 491 | DEVELOPMENT_TEAM = ""; 492 | DYLIB_COMPATIBILITY_VERSION = 1; 493 | DYLIB_CURRENT_VERSION = 1; 494 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 495 | INFOPLIST_FILE = PageMenuKit/Info.plist; 496 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 497 | IPHONEOS_DEPLOYMENT_TARGET = 14.3; 498 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 499 | ONLY_ACTIVE_ARCH = NO; 500 | PRODUCT_BUNDLE_IDENTIFIER = com.magickworx.PageMenuKit; 501 | PRODUCT_NAME = "$(TARGET_NAME)"; 502 | SKIP_INSTALL = YES; 503 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 504 | SWIFT_VERSION = 5.0; 505 | VALID_ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 506 | VERSIONING_SYSTEM = "apple-generic"; 507 | VERSION_INFO_PREFIX = ""; 508 | }; 509 | name = Debug; 510 | }; 511 | B3FD5BB81EE967A000842272 /* Release */ = { 512 | isa = XCBuildConfiguration; 513 | buildSettings = { 514 | CLANG_ENABLE_MODULES = YES; 515 | CODE_SIGN_IDENTITY = ""; 516 | CURRENT_PROJECT_VERSION = 2; 517 | DEFINES_MODULE = YES; 518 | DEVELOPMENT_TEAM = ""; 519 | DYLIB_COMPATIBILITY_VERSION = 1; 520 | DYLIB_CURRENT_VERSION = 1; 521 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 522 | INFOPLIST_FILE = PageMenuKit/Info.plist; 523 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 524 | IPHONEOS_DEPLOYMENT_TARGET = 14.3; 525 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 526 | ONLY_ACTIVE_ARCH = NO; 527 | PRODUCT_BUNDLE_IDENTIFIER = com.magickworx.PageMenuKit; 528 | PRODUCT_NAME = "$(TARGET_NAME)"; 529 | SKIP_INSTALL = YES; 530 | SWIFT_VERSION = 5.0; 531 | VALID_ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 532 | VERSIONING_SYSTEM = "apple-generic"; 533 | VERSION_INFO_PREFIX = ""; 534 | }; 535 | name = Release; 536 | }; 537 | B3FD5BD41EE96AC100842272 /* Debug */ = { 538 | isa = XCBuildConfiguration; 539 | buildSettings = { 540 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 541 | DEVELOPMENT_TEAM = ""; 542 | INFOPLIST_FILE = PageMenuKitDemo/Info.plist; 543 | IPHONEOS_DEPLOYMENT_TARGET = 14.3; 544 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 545 | PRODUCT_BUNDLE_IDENTIFIER = com.magickworx.PageMenuKitDemo; 546 | PRODUCT_NAME = "$(TARGET_NAME)"; 547 | SWIFT_VERSION = 5.0; 548 | VALID_ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 549 | }; 550 | name = Debug; 551 | }; 552 | B3FD5BD51EE96AC100842272 /* Release */ = { 553 | isa = XCBuildConfiguration; 554 | buildSettings = { 555 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 556 | DEVELOPMENT_TEAM = ""; 557 | INFOPLIST_FILE = PageMenuKitDemo/Info.plist; 558 | IPHONEOS_DEPLOYMENT_TARGET = 14.3; 559 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 560 | PRODUCT_BUNDLE_IDENTIFIER = com.magickworx.PageMenuKitDemo; 561 | PRODUCT_NAME = "$(TARGET_NAME)"; 562 | SWIFT_VERSION = 5.0; 563 | VALID_ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 564 | }; 565 | name = Release; 566 | }; 567 | /* End XCBuildConfiguration section */ 568 | 569 | /* Begin XCConfigurationList section */ 570 | B33FF34F258B2415004DBC52 /* Build configuration list for PBXAggregateTarget "PageMenuKitSwiftXCFramework" */ = { 571 | isa = XCConfigurationList; 572 | buildConfigurations = ( 573 | B33FF34D258B2415004DBC52 /* Debug */, 574 | B33FF34E258B2415004DBC52 /* Release */, 575 | ); 576 | defaultConfigurationIsVisible = 0; 577 | defaultConfigurationName = Release; 578 | }; 579 | B3FD5B8E1EE966FB00842272 /* Build configuration list for PBXProject "PageMenuKitSwift" */ = { 580 | isa = XCConfigurationList; 581 | buildConfigurations = ( 582 | B3FD5BA31EE966FC00842272 /* Debug */, 583 | B3FD5BA41EE966FC00842272 /* Release */, 584 | ); 585 | defaultConfigurationIsVisible = 0; 586 | defaultConfigurationName = Release; 587 | }; 588 | B3FD5BB61EE967A000842272 /* Build configuration list for PBXNativeTarget "PageMenuKit" */ = { 589 | isa = XCConfigurationList; 590 | buildConfigurations = ( 591 | B3FD5BB71EE967A000842272 /* Debug */, 592 | B3FD5BB81EE967A000842272 /* Release */, 593 | ); 594 | defaultConfigurationIsVisible = 0; 595 | defaultConfigurationName = Release; 596 | }; 597 | B3FD5BD31EE96AC100842272 /* Build configuration list for PBXNativeTarget "PageMenuKitDemo" */ = { 598 | isa = XCConfigurationList; 599 | buildConfigurations = ( 600 | B3FD5BD41EE96AC100842272 /* Debug */, 601 | B3FD5BD51EE96AC100842272 /* Release */, 602 | ); 603 | defaultConfigurationIsVisible = 0; 604 | defaultConfigurationName = Release; 605 | }; 606 | /* End XCConfigurationList section */ 607 | }; 608 | rootObject = B3FD5B8B1EE966FB00842272 /* Project object */; 609 | } 610 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PageMenuKitSwift 2 | 3 | [PageMenuController](https://github.com/magickworx/PageMenuController) の Swift 版。 4 | 5 | 日本のニュース系アプリで使われている横スクロールのメニュー画面とそのコンテンツを表示するユーザインタフェースのクラス。 6 | Xcode のプロジェクト一式を登録してあるので、実行すればシミュレータ上で動作確認が可能。 7 | 8 | Swift で実装し直す際に、汎用的で拡張しやすいようにクラスを再設計した。ページメニューの見た目だけが違うので、スタイルごとに PMKPageMenuItem のサブクラスを実装し、それを利用する仕組みにした。よって、簡単にカスタムメニューを追加できる。 9 | 10 | ## How to use PageMenuKit.framework 11 | 12 | Xcode の Build Target に PageMenuKitXCFramework を指定して Build を実行すると、PageMenuKit.xcframework が作成される。これを自作アプリの Xcode の Project で設定する。 13 | 14 | あとは、以下のようなコードを記述して利用する。 15 | 16 | ```Swift 17 | class RootViewController: UIViewController 18 | { 19 | var pageMenuController: PMKPageMenuController? = nil 20 | 21 | override func viewDidLoad() { 22 | super.viewDidLoad() 23 | 24 | var controllers: [UIViewController] = [] 25 | let dateFormatter = DateFormatter() 26 | for month in dateFormatter.monthSymbols { 27 | let viewController: DataViewController = DataViewController() 28 | viewController.title = month 29 | controllers.append(viewController) 30 | } 31 | 32 | let statusBarHeight: CGFloat = UIApplication.shared.statusBarFrame.size.height 33 | /* 34 | * Available menu styles: 35 | * .plain, .tab, .smart, .hacka, .ellipse, .web, .suite, .netlab and .nhk 36 | * See PMKPageMenuItem.swift in PageMenuKit folder. 37 | * 38 | * menuColors: [] means that we will use the default colors 39 | * "startIndex" can be set 1...controllers.count. 40 | */ 41 | pageMenuController = PMKPageMenuController(controllers: controllers, menuStyle: .smart, menuColors: [], startIndex: 1, topBarHeight: statusBarHeight) 42 | self.addChild(pageMenuController!) 43 | self.view.addSubview(pageMenuController!.view) 44 | pageMenuController?.didMove(toParent: self) 45 | } 46 | } 47 | ``` 48 | 49 | より詳細なコードは PageMenuKitDemo 内の RootViewController.swift を見てね。 50 | 51 | 52 | ## Available Menu Styles 53 | 54 | ### .plain 55 | [ニュースパス](https://itunes.apple.com/jp/app/id1106788059?mt=8) っぽいメニュー画面 56 | 57 | ![.plain](screenshots/tab_Plain.png "ニュースパス") 58 | 59 | ### .tab 60 | [グノシー](https://itunes.apple.com/jp/app/id590384791?mt=8) っぽいメニュー画面 61 | 62 | ![.tab](screenshots/tab_Tab.png "グノシー") 63 | 64 | ### .smart 65 | [SmartNews](https://itunes.apple.com/jp/app/id579581125?mt=8) っぽいメニュー画面 66 | 67 | ![.smart](screenshots/tab_Smart.png "SmartNews") 68 | 69 | ### .hacka 70 | [ハッカドール](https://itunes.apple.com/jp/app/id888231424?mt=8) っぽいメニュー画面 71 | 72 | ![.hacka](screenshots/tab_Hacka.png "ハッカドール") 73 | 74 | ### .ellipse 75 | [JCnews](https://itunes.apple.com/jp/app/id1024341813?mt=8) っぽいメニュー画面 76 | 77 | ![.ellipse](screenshots/tab_Ellipse.png "JCnews iOS App") 78 | 79 | ### .web 80 | [JCnews のウェブサイト](https://jcnews.tokyo/) っぽいメニュー画面 81 | 82 | ![.web](screenshots/tab_Web.png "JCnews ウェブサイト") 83 | 84 | ### .suite 85 | [NewsSuite](https://itunes.apple.com/jp/app/id1176431318?mt=8) っぽいメニュー画面(背景色はグラデーション) 86 | 87 | ![.suite](screenshots/tab_Suite.png "ニュース(NewsSuite)") 88 | 89 | ### .netlab 90 | [ねとらぼ](https://itunes.apple.com/jp/app/id949325541?mt=8) っぽいメニュー画面(背景色は透明) 91 | 92 | ![.netlab](screenshots/tab_NetLab.png "ねとらぼ") 93 | 94 | ### .nhk 95 | [NHK ニュース・防災](https://itunes.apple.com/jp/app/id1121104608?mt=8) っぽいメニュー画面 96 | 97 | ![.nhk](screenshots/tab_NHK.png "NHK ニュース・防災") 98 | 99 | 100 | ## Examples 101 | 102 | PMKPageMenuController の initializer の menuColors に __[]__ を指定するとデフォルトの配色になる。ここでは、各スタイルごとに色を変更する例を示す。 103 | 104 | ### .plain, .hacka, .ellipse, .nhk 105 | 106 | .plain, .hacka, .ellipse, .nhk の各スタイルで指定できる色は一つだけである。 107 | 以下の例では .plain スタイルに __紫(.purple)__ を設定している。 108 | 109 | ```swift 110 | pageMenuController = PMKPageMenuController(controllers: controllers, menuStyle: .plain, menuColors: [ .purple ], topBarHeight: statusBarHeight) 111 | ``` 112 | #### .plain 113 | 114 | ![.plain](screenshots/ex_Plain.png "plain") 115 | 116 | #### .hacka 117 | 118 | ![.hacka](screenshots/ex_Hacka.png "hacka") 119 | 120 | #### .ellipse 121 | 122 | ![.ellipse](screenshots/ex_Ellipse.png "ellipse") 123 | 124 | #### .nhk 125 | 126 | ![.nhk](screenshots/ex_NHK.png "nhk") 127 | 128 | 129 | ### .tab, .smart 130 | 131 | .tab, .smart スタイルで指定できる色は一つ以上である。 132 | 以下の例では .tab スタイルに __赤、橙、黄、緑、青、紫__ を設定している。 133 | メニューの数が配色した数よりも多い場合は、順に色が適用される。 134 | 135 | ```swift 136 | pageMenuController = PMKPageMenuController(controllers: controllers, menuStyle: .tab, menuColors: [ .red, .orange, .yello, .green, .blue, .purple ], topBarHeight: statusBarHeight) 137 | ``` 138 | 139 | #### .tab 140 | 141 | ![.tab](screenshots/ex_Tab.png "tab") 142 | 143 | #### .smart 144 | 145 | ![.smart](screenshots/ex_Smart.png "smart") 146 | 147 | 148 | ### .web 149 | 150 | .web スタイルも .tab, .smart スタイルと同様に指定できる色は一つ以上である。 151 | ただし、背景色は現在固定されている。 152 | また、現実装では最初に指定した色が境界線の色になる。 153 | 154 | 以下の例では .web スタイルに __赤、橙、黄、緑、青、紫__ を設定している。 155 | メニューの数が配色した数よりも多い場合は、順に色が適用される。 156 | 157 | ```swift 158 | pageMenuController = PMKPageMenuController(controllers: controllers, menuStyle: .web, menuColors: [ .red, .orange, .yello, .green, .blue, .purple ], topBarHeight: statusBarHeight) 159 | ``` 160 | 161 | ![.web](screenshots/ex_Web.png "web") 162 | 163 | 164 | ### .suite 165 | 166 | .suite スタイルで指定できる色は一つだけであるが、 167 | 現状ではインジケータの色が変更されるだけである。 168 | 以下の例では .suite スタイルに __青(.blue)__ を設定している。 169 | 170 | ```swift 171 | pageMenuController = PMKPageMenuController(controllers: controllers, menuStyle: .suite, menuColors: [ .blue ], topBarHeight: statusBarHeight) 172 | ``` 173 | 174 | ![.suite](screenshots/ex_Suite.png "suite") 175 | 176 | 177 | ### .netlab 178 | 179 | .netlab スタイルで指定できる色は一つだけである。 180 | 現状では、非選択時の文字色に影響する。 181 | 以下の例では .netlab スタイルに __赤(.red)__ を設定している。 182 | 183 | ```swift 184 | pageMenuController = PMKPageMenuController(controllers: controllers, menuStyle: .netlab, menuColors: [ .red ], topBarHeight: statusBarHeight) 185 | ``` 186 | 187 | ![.netlab](screenshots/ex_NetLab.png "netlab") 188 | 189 | 190 | ## Delegate Methods (optional) 191 | 192 | ページの切り替え時に呼び出される Delegate を使うことも可能。 193 | 194 | ```swift 195 | pageMenuController?.delegate = self 196 | ``` 197 | 198 | 上記のような記述を追加して、必要に応じて以下のメソッドを実装してね。 199 | 現時点では、 **.hacka** スタイルのバッジ表示の際に利用しているだけ。 200 | 201 | ```PMKPageMenuControllerDelegte.swift 202 | public protocol PMKPageMenuControllerDelegate: class 203 | { 204 | // ページ画面上でスワイプ操作による切り替えが行われる前に呼び出される 205 | func pageMenuController(_ pageMenuController: PMKPageMenuController, willMoveTo viewController: UIViewController, at menuIndex: Int) 206 | // ページの切り替えが完了した際に呼び出される 207 | func pageMenuController(_ pageMenuController: PMKPageMenuController, didMoveTo viewController: UIViewController, at menuIndex: Int) 208 | 209 | // メニュー項目の作成などが完了した際に呼び出される 210 | func pageMenuController(_ pageMenuController: PMKPageMenuController, didPrepare menuItems: [PMKPageMenuItem]) 211 | // メニューがタップされた際に呼び出される 212 | func pageMenuController(_ pageMenuController: PMKPageMenuController, didSelect menuItem: PMKPageMenuItem, at menuIndex: Int) 213 | } 214 | ``` 215 | 216 | ## References 217 | 218 | Qiita の[ニュース系アプリのユーザインタフェース PageMenuKit の実装](http://qiita.com/magickworx/items/5de63eb926a9447b2665) も見てね。カスタムメニューの実装方法についても書いてあるよ。 219 | 220 | ## Requirements 221 | 222 | - Swift 5 223 | - iOS 13.6 or later 224 | - Xcode 12.3 or later 225 | 226 | ## ToDo 227 | 228 | - .suite と .web と .netlab スタイルのカスタマイズ方法 229 | 230 | ## License Agreement 231 | 232 | Copyright (c) 2017-2020, Kouichi ABE (WALL) All rights reserved. 233 | 234 | Redistribution and use in source and binary forms, with or without 235 | modification, are permitted provided that the following conditions are met: 236 | 237 | 1. Redistributions of source code must retain the above copyright notice, 238 | this list of conditions and the following disclaimer. 239 | 240 | 2. Redistributions in binary form must reproduce the above copyright notice, 241 | this list of conditions and the following disclaimer in the documentation 242 | and/or other materials provided with the distribution. 243 | 244 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 245 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 246 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 247 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 248 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 249 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 250 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 251 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 252 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 253 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 254 | 255 | -------------------------------------------------------------------------------- /screenshots/ex_Ellipse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magickworx/PageMenuKitSwift/673e0e69cb0bc8f909ce158799f5a639ee91a978/screenshots/ex_Ellipse.png -------------------------------------------------------------------------------- /screenshots/ex_Hacka.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magickworx/PageMenuKitSwift/673e0e69cb0bc8f909ce158799f5a639ee91a978/screenshots/ex_Hacka.png -------------------------------------------------------------------------------- /screenshots/ex_NHK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magickworx/PageMenuKitSwift/673e0e69cb0bc8f909ce158799f5a639ee91a978/screenshots/ex_NHK.png -------------------------------------------------------------------------------- /screenshots/ex_NetLab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magickworx/PageMenuKitSwift/673e0e69cb0bc8f909ce158799f5a639ee91a978/screenshots/ex_NetLab.png -------------------------------------------------------------------------------- /screenshots/ex_Plain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magickworx/PageMenuKitSwift/673e0e69cb0bc8f909ce158799f5a639ee91a978/screenshots/ex_Plain.png -------------------------------------------------------------------------------- /screenshots/ex_Smart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magickworx/PageMenuKitSwift/673e0e69cb0bc8f909ce158799f5a639ee91a978/screenshots/ex_Smart.png -------------------------------------------------------------------------------- /screenshots/ex_Suite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magickworx/PageMenuKitSwift/673e0e69cb0bc8f909ce158799f5a639ee91a978/screenshots/ex_Suite.png -------------------------------------------------------------------------------- /screenshots/ex_Tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magickworx/PageMenuKitSwift/673e0e69cb0bc8f909ce158799f5a639ee91a978/screenshots/ex_Tab.png -------------------------------------------------------------------------------- /screenshots/ex_Web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magickworx/PageMenuKitSwift/673e0e69cb0bc8f909ce158799f5a639ee91a978/screenshots/ex_Web.png -------------------------------------------------------------------------------- /screenshots/tab_Ellipse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magickworx/PageMenuKitSwift/673e0e69cb0bc8f909ce158799f5a639ee91a978/screenshots/tab_Ellipse.png -------------------------------------------------------------------------------- /screenshots/tab_Hacka.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magickworx/PageMenuKitSwift/673e0e69cb0bc8f909ce158799f5a639ee91a978/screenshots/tab_Hacka.png -------------------------------------------------------------------------------- /screenshots/tab_NHK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magickworx/PageMenuKitSwift/673e0e69cb0bc8f909ce158799f5a639ee91a978/screenshots/tab_NHK.png -------------------------------------------------------------------------------- /screenshots/tab_NetLab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magickworx/PageMenuKitSwift/673e0e69cb0bc8f909ce158799f5a639ee91a978/screenshots/tab_NetLab.png -------------------------------------------------------------------------------- /screenshots/tab_Plain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magickworx/PageMenuKitSwift/673e0e69cb0bc8f909ce158799f5a639ee91a978/screenshots/tab_Plain.png -------------------------------------------------------------------------------- /screenshots/tab_Smart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magickworx/PageMenuKitSwift/673e0e69cb0bc8f909ce158799f5a639ee91a978/screenshots/tab_Smart.png -------------------------------------------------------------------------------- /screenshots/tab_Suite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magickworx/PageMenuKitSwift/673e0e69cb0bc8f909ce158799f5a639ee91a978/screenshots/tab_Suite.png -------------------------------------------------------------------------------- /screenshots/tab_Tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magickworx/PageMenuKitSwift/673e0e69cb0bc8f909ce158799f5a639ee91a978/screenshots/tab_Tab.png -------------------------------------------------------------------------------- /screenshots/tab_Web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magickworx/PageMenuKitSwift/673e0e69cb0bc8f909ce158799f5a639ee91a978/screenshots/tab_Web.png --------------------------------------------------------------------------------