|
//
// 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])
}
}
|