Nav apraksta

FFPageContentView.swift 5.9KB

    // // FFPageContentView.swift // FFPage // // Created by FFIB on 2017/10/18. // Copyright © 2017年 FFIB. All rights reserved. // import UIKit protocol FFPageContentViewDataSource { func pageContentView(pageContentView: FFPageContentView, cellForItemAt index: Int) -> FFPageContentViewCell func numberOfSections(in pageContentView: FFPageContentView) -> Int } protocol FFPageContentViewDelegate { func pageContentView(pageContentView: FFPageContentView, didSelectItemAt index: Int) } @IBDesignable open class FFPageContentView: UIScrollView, UIScrollViewDelegate { var dataSource: FFPageContentViewDataSource? var pageDelegate: FFPageContentViewDelegate? private var ffConstraints = [NSLayoutConstraint]() private var nibs = [String: UINib]() private var cells = [String: AnyClass]() var needLayout = true public override init(frame: CGRect) { super.init(frame: frame) configuration() } public required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) configuration() } func configuration() { isPagingEnabled = true showsHorizontalScrollIndicator = false showsVerticalScrollIndicator = false alwaysBounceVertical = false bounces = false alwaysBounceHorizontal = true addObserver(self, forKeyPath: "contentOffset", options: .new, context: nil) } open override func layoutSubviews() { if needLayout { reloadData() } super.layoutSubviews() } func register(nib: UINib, with identifier: String) { nibs[identifier] = nib } func register(cell: AnyClass, with identifier: String) { cells[identifier] = cell } func dequeue(with identifier: String) -> FFPageContentViewCell { if let nib = nibs[identifier] { return nib.instantiate(withOwner: self, options: nil).first as! FFPageContentViewCell } if let cell = cells[identifier], cell is FFPageContentViewCell.Type { return (cell as! FFPageContentViewCell.Type).init() } fatalError("FFPageContentViewCell and identifier unmatch") } func reloadData() { subviews.forEach { $0.removeFromSuperview() } NSLayoutConstraint.deactivate(ffConstraints) contentSize = CGSize(width: 0, height: 0) ffConstraints.removeAll() guard let dataSource = dataSource else { return } contentSize = CGSize(width: frame.width * CGFloat(dataSource.numberOfSections(in: self)), height: frame.height) var last: FFPageContentViewCell? for i in 0..<dataSource.numberOfSections(in: self) { var cell = dataSource.pageContentView(pageContentView: self, cellForItemAt: i) cell.index = i cell.translatesAutoresizingMaskIntoConstraints = false addSubview(cell) var subConstriants = [NSLayoutConstraint(item: cell, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1, constant: 0), NSLayoutConstraint(item: cell, attribute: .height, relatedBy: .equal, toItem: self, attribute: .height, multiplier: 1, constant: 0), NSLayoutConstraint(item: cell, attribute: .width, relatedBy: .equal, toItem: self, attribute: .width, multiplier: 1, constant: 0)] var leadConstriant: NSLayoutConstraint if last == nil { leadConstriant = NSLayoutConstraint(item: cell, attribute: .leading, relatedBy: .equal, toItem: self, attribute: .leading, multiplier: 1, constant: 0) } else { leadConstriant = NSLayoutConstraint(item: cell, attribute: .left, relatedBy: .equal, toItem: last, attribute: .right, multiplier: 1, constant: 0) } subConstriants.append(leadConstriant) ffConstraints += subConstriants last = cell } NSLayoutConstraint.activate(ffConstraints) needLayout = false } open override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) { if let point = change?[NSKeyValueChangeKey.newKey] as? CGPoint, (isTracking || isDragging || isDecelerating) { pageDelegate?.pageContentView(pageContentView: self, didSelectItemAt: Int(point.x / frame.width)) } } deinit { removeObserver(self, forKeyPath: "contentOffset") } }