No Description

FFPageView.swift 13KB

    // // FFPageView.swift // FFPage // // Created by FFIB on 2017/10/19. // Copyright © 2017年 FFIB. All rights reserved. // import UIKit public protocol FFPageViewDataSource { func pageView(pageView: FFPageView, cellForItemAt index: Int) -> FFPageContentViewCell } public protocol FFPageViewDelegate { func pageViewWithClickMenu(pageView: FFPageView) } @IBDesignable public class FFPageView: UIView { private var pageMenuView = FFPageMenuView() private var pageContentView = FFPageContentView() private var needlayout = true private var rootVC: UIViewController? private var ffConstraints = [NSLayoutConstraint]() //configuratable parameter public var dataSource: FFPageViewDataSource? public var delegate: FFPageViewDelegate? var isNavigationMenu = true { willSet { if newValue != isNavigationMenu { needlayout = true setNeedsLayout() } } } public var sliderView = UIView() { willSet { if sliderView != newValue { pageMenuView.sliderView = newValue } } } public var selectedColor = UIColor.blue { willSet { if selectedColor != newValue { pageMenuView.selectedColor = newValue } } } public var normalColor = UIColor.black { willSet { if normalColor != newValue { pageMenuView.normalColor = newValue } } } public var pageMenuContentMode = FFPageMenuContentMode.scaleAspectFill { willSet { pageMenuView.pageMenuContentMode = newValue } } public var font = UIFont.systemFont(ofSize: 17) { willSet { if font != newValue { pageMenuView.font = newValue } } } public var titles = [String]() { willSet { if titles != newValue { pageMenuView.titles = newValue pageContentView.needLayout = true pageMenuView.setNeedsLayout() pageContentView.setNeedsLayout() } } } public override func layoutSubviews() { super.layoutSubviews() if needlayout { initSubViews() } } func initSubViews() { needlayout = false pageContentView.removeFromSuperview() pageMenuView.removeFromSuperview() NSLayoutConstraint.deactivate(ffConstraints) ffConstraints.removeAll() pageMenuView.pageDelegate = self pageContentView.dataSource = self pageContentView.pageDelegate = self addSubview(pageContentView) pageContentView.translatesAutoresizingMaskIntoConstraints = false pageMenuView.translatesAutoresizingMaskIntoConstraints = false let contentTopConstraint: NSLayoutConstraint var responder = self.next while responder != nil { if let targetVC = responder as? UIViewController { rootVC = targetVC break } responder = responder?.next } if #available(iOS 11.0, *) { pageContentView.contentInsetAdjustmentBehavior = .never } else { rootVC?.automaticallyAdjustsScrollViewInsets = false } switch isNavigationMenu { case false: addSubview(pageMenuView) let menuConstraints = [NSLayoutConstraint(item: pageMenuView, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1, constant: 0), NSLayoutConstraint(item: pageMenuView, attribute: .leading, relatedBy: .equal, toItem: self, attribute: .leading, multiplier: 1, constant: 0), NSLayoutConstraint(item: pageMenuView, attribute: .trailing, relatedBy: .equal, toItem: self, attribute: .trailing, multiplier: 1, constant: 0), NSLayoutConstraint(item: pageMenuView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: 44)] contentTopConstraint = NSLayoutConstraint(item: pageContentView, attribute: .top, relatedBy: .equal, toItem: pageMenuView, attribute: .bottom, multiplier: 1, constant: 0) ffConstraints += menuConstraints case true: var barContentView: UIView? if #available(iOS 11, *) { barContentView = rootVC? .navigationController? .navigationBar .subviews .filter { NSStringFromClass($0.classForCoder).contains("NavigationBarContentView") } .first } else { barContentView = rootVC?.navigationController?.navigationBar } contentTopConstraint = NSLayoutConstraint(item: pageContentView, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1, constant: 0) let menuConstraints = [NSLayoutConstraint(item: pageMenuView, attribute: .top, relatedBy: .equal, toItem: barContentView, attribute: .top, multiplier: 1, constant: 0), NSLayoutConstraint(item: pageMenuView, attribute: .bottom, relatedBy: .equal, toItem: barContentView, attribute: .bottom, multiplier: 1, constant: 0), NSLayoutConstraint(item: pageMenuView, attribute: .centerX, relatedBy: .equal, toItem: barContentView, attribute: .centerX, multiplier: 1, constant: 0)] ffConstraints += menuConstraints NotificationCenter.default.addObserver(forName: NSNotification.Name.init("UINavigationController.willShow"), object: nil, queue: nil, using: { (notification) in if let userInfo = notification.userInfo, let vc = userInfo["targetController"] as? UIViewController, self.rootVC == vc { self.pageMenuView.isHidden = false } else { self.pageMenuView.isHidden = true } }) } let contentConstraints = [contentTopConstraint, NSLayoutConstraint(item: pageContentView, attribute: .leading, relatedBy: .equal, toItem: self, attribute: .leading, multiplier: 1, constant: 0), NSLayoutConstraint(item: pageContentView, attribute: .trailing, relatedBy: .equal, toItem: self, attribute: .trailing, multiplier: 1, constant: 0), NSLayoutConstraint(item: pageContentView, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1, constant: 0), NSLayoutConstraint(item: pageContentView, attribute: .width, relatedBy: .equal, toItem: self, attribute: .width, multiplier: 1, constant: 0)] ffConstraints += contentConstraints NSLayoutConstraint.activate(ffConstraints) } public func dequeue(with identifier: String) -> FFPageContentViewCell { return pageContentView.dequeue(with: identifier) } public func register(nib: UINib, with identifier: String) { pageContentView.register(nib: nib, with: identifier) } public func register(cell: AnyClass, with identifier: String) { pageContentView.register(cell: cell, with: identifier) } deinit { NotificationCenter.default.removeObserver(self) } } extension FFPageView: FFPageMenuViewDelegate { public func pageMenuView(pageMenuView: FFPageMenuView, didSelectItemAt index: Int) { pageContentView.scrollRectToVisible(CGRect(x: CGFloat(index) * frame.width, y: 0, width: frame.width, height: frame.height), animated: true) if let delegate = delegate { delegate.pageViewWithClickMenu(pageView: self) } } } extension FFPageView: FFPageContentViewDelegate { public func pageContentView(pageContentView: FFPageContentView, didSelectItemAt index: Int) { let offset = pageContentView.contentOffset.x / pageContentView.frame.width pageMenuView.scroll(offset: offset) } } extension FFPageView: FFPageContentViewDataSource { public func pageContentView(pageContentView: FFPageContentView, cellForItemAt index: Int) -> FFPageContentViewCell { guard let dataSource = dataSource else { fatalError("\(self) did not set up FFPageViewDataSource") } return dataSource.pageView(pageView: self, cellForItemAt: index) } public func numberOfSections(in pageContentView: FFPageContentView) -> Int { return titles.count } } extension UIViewController: UINavigationControllerDelegate { public func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) { NotificationCenter.default.post(name: NSNotification.Name("UINavigationController.willShow"), object: nil, userInfo: ["targetController": viewController]) } }