| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485 |
- //
- // ExcelViewSwifty.swift
- // YunYingSwift
- //
- // Created by AlasKu on 17/2/10.
- // Copyright © 2017年 innostic. All rights reserved.
- //
- import UIKit
- import NVActivityIndicatorView
- let AKCollectionViewCellIdentifier = "AKCollectionView_Cell"
- let AKCollectionViewHeaderIdentifier = "AKCollectionView_Header"
- @objc protocol AKExcelViewDelegate : NSObjectProtocol {
-
- @objc optional func excelView(_ excelView: AKExcelView, didSelectItemAt indexPath: IndexPath)
- @objc optional func excelView(_ excelView: AKExcelView, viewAt indexPath: IndexPath) -> UIView?
- @objc optional func excelView(_ excelView: AKExcelView, attributedStringAt indexPath: IndexPath) -> NSAttributedString?
- }
- class AKExcelView: UIView , UICollectionViewDelegate , UICollectionViewDataSource , UIScrollViewDelegate , UICollectionViewDelegateFlowLayout{
-
- /// Delegate
- weak var delegate : AKExcelViewDelegate?
- /// CellTextMargin
- var textMargin : CGFloat = 5
- /// Cell Max width
- var itemMaxWidth : CGFloat = 200
- /// cell Min width
- var itemMinWidth : CGFloat = 50
- /// cell heihth
- var itemHeight : CGFloat = 44
- /// header Height
- var headerHeight : CGFloat = 44
- /// header BackgroundColor
- var headerBackgroundColor : UIColor = UIColor.lightGray
- /// header Text Color
- var headerTextColor : UIColor = UIColor.black
- /// header Text Font
- var headerTextFontSize : UIFont = UIFont.systemFont(ofSize: 15)
- /// contenTCell TextColor
- var contentTextColor : UIColor = UIColor.black
- /// content backgroung Color
- var contentBackgroundColor : UIColor = UIColor.white
- /// content Text Font
- var contentTextFontSize : UIFont = UIFont.systemFont(ofSize: 13)
- /// letf freeze column
- var leftFreezeColumn : Int = 1
- /// header Titles
- var headerTitles : [String]?
- /// content Data
- var contentData : Array<NSObject>?
- /// 颜色支持
- var contentDataColor: [[UIColor]]?
- /// set Column widths
- var columnWidthSetting : Dictionary<Int, CGFloat>?
- /// CelledgeInset
- var itemInsets : UIEdgeInsets?
- /// showsProperties
- var properties : Array<String>?
- /// autoScrollItem default is false
- var autoScrollToNearItem = false
- /// if set, there is no loading view when reload datas. default is true
- var isNeedLoadingView = true
-
- fileprivate lazy var horizontalShadow : CAShapeLayer = { //水平阴影
- let s = CAShapeLayer()
- s.strokeColor = UIColor.lightGray.cgColor
- s.shadowColor = UIColor.black.cgColor
- s.shadowOffset = CGSize.init(width: 2, height: 0)
- s.shadowOpacity = 1
- return s
- }()
-
- fileprivate lazy var veritcalShadow : CAShapeLayer = { //垂直阴影
- let s = CAShapeLayer()
- s.strokeColor = UIColor.lightGray.cgColor
- s.shadowColor = UIColor.black.cgColor
- s.shadowOffset = CGSize.init(width: 0, height: 3)
- s.shadowOpacity = 1
- return s
- }()
- // MARK: - Public Method
- override init(frame: CGRect) {
- super.init(frame: frame)
- setup()
- }
-
- required init?(coder aDecoder: NSCoder) {
- super.init(coder: aDecoder)
- setup()
- }
-
- override func layoutSubviews() {
- super.layoutSubviews()
- setUpFrames()
- }
-
- func reloadData() {
-
- if isNeedLoadingView {
-
- // 开启Loading
- NVActivityIndicatorPresenter.sharedInstance.startAnimating(ActivityData(message: "数据加载中...", color: UIColor.loding()), NVActivityIndicatorView.DEFAULT_FADE_IN_ANIMATION)
- }
-
- DispatchQueue.global().sync {
-
- self.dataManager.caculateData()
- DispatchQueue.main.async {
-
- if self.isNeedLoadingView {
-
- NVActivityIndicatorPresenter.sharedInstance.stopAnimating(NVActivityIndicatorView.DEFAULT_FADE_OUT_ANIMATION)
- }
-
- self.setUpFrames()
- self.headFreezeCollectionView.reloadData()
- self.headMovebleCollectionView.reloadData()
- self.contentFreezeCollectionView.reloadData()
- self.contentMoveableCollectionView.reloadData()
- }
- }
- }
-
- func sizeForItem(item: Int) -> CGSize {
-
- if item < leftFreezeColumn {
- return NSCoder.cgSize(for: self.dataManager.freezeItemSize[item])
- } else {
- return NSCoder.cgSize(for: self.dataManager.slideItemSize[item - leftFreezeColumn])
- }
- }
-
- //MARK: - Private Method
- private func setup() {
-
- dataManager.excelView = self
- clipsToBounds = true
-
-
- addSubview(headFreezeCollectionView)
- addSubview(contentFreezeCollectionView)
- addSubview(contentScrollView)
-
- contentScrollView.addSubview(headMovebleCollectionView)
- contentScrollView.addSubview(contentMoveableCollectionView)
-
- contentMoveableCollectionView.contentInset = UIEdgeInsets(top: -1, left: 0, bottom: 0, right: 0)
- contentFreezeCollectionView.contentInset = UIEdgeInsets(top: -1, left: 0, bottom: 0, right: 0)
- layer.addSublayer(horizontalShadow)
- contentScrollView.layer.addSublayer(veritcalShadow)
- }
-
- fileprivate func showHorizontalDivideShadowLayer() {
- if horizontalShadow.path == nil {
- let path = UIBezierPath()
- path.move(to: CGPoint(x: 0, y: headerHeight))
- path.addLine(to: CGPoint(x: min(self.bounds.width, self.dataManager.freezeWidth + self.dataManager.slideWidth), y: headerHeight))
- path.lineWidth = 0.5
- horizontalShadow.path = path.cgPath
- }
- }
-
- fileprivate func dismissHorizontalDivideShadowLayer() {
- horizontalShadow.path = nil
- }
-
- fileprivate func showVerticalDivideShadowLayer() {
- if veritcalShadow.path == nil {
- let path = UIBezierPath()
- let heigh = contentScrollView.contentSize.height // + headFreezeCollectionView.contentSize.height
- path.move(to: CGPoint(x: 0, y: 0))
- path.addLine(to: CGPoint(x: 0, y: heigh))
- path.lineWidth = 0.5
- veritcalShadow.path = path.cgPath
- }
- }
-
- fileprivate func dismissVerticalDivideShadowLayer() {
- veritcalShadow.path = nil
- }
-
- fileprivate func setUpFrames() {
-
- let width = bounds.width
- let height = bounds.height
-
- if headerTitles != nil {
-
- headFreezeCollectionView.frame = CGRect(x: 0, y: 0, width: dataManager.freezeWidth, height: headerHeight)
- contentFreezeCollectionView.frame = CGRect(x: 0, y: headerHeight, width: dataManager.freezeWidth, height: height - headerHeight)
-
- contentScrollView.frame = CGRect(x: dataManager.freezeWidth, y: 0, width: width - dataManager.freezeWidth , height: height)
- contentScrollView.contentSize = CGSize(width: dataManager.slideWidth, height: height)
-
- headMovebleCollectionView.frame = CGRect(x: 0, y: 0, width: dataManager.slideWidth, height: headerHeight)
- contentMoveableCollectionView.frame = CGRect(x: 0, y: headerHeight, width: dataManager.slideWidth, height: height - headerHeight)
- } else {
-
- contentFreezeCollectionView.frame = CGRect(x: 0, y: 0, width: dataManager.freezeWidth, height: height)
-
- contentScrollView.frame = CGRect(x: dataManager.freezeWidth, y: 0, width: width - dataManager.freezeWidth, height: height)
- contentScrollView.contentSize = CGSize(width: dataManager.slideWidth, height: height)
-
- contentMoveableCollectionView.frame = CGRect(x: 0, y: 0, width: dataManager.slideWidth, height: height)
- }
- }
-
- //MARK: - 懒加载
- fileprivate let dataManager : AKExcelDataManager = AKExcelDataManager()
-
- fileprivate lazy var headFreezeCollectionView : UICollectionView = {
-
- return UICollectionView.init(delelate: self, datasource: self)
- }()
- fileprivate lazy var headMovebleCollectionView : UICollectionView = {
-
- return UICollectionView.init(delelate: self, datasource: self)
- }()
- fileprivate lazy var contentFreezeCollectionView : UICollectionView = {
-
- return UICollectionView.init(delelate: self, datasource: self)
- }()
- fileprivate lazy var contentMoveableCollectionView : UICollectionView = {
-
- return UICollectionView.init(delelate: self, datasource: self)
- }()
- fileprivate lazy var contentScrollView : UIScrollView = {
-
- let slideScrollView = UIScrollView()
- slideScrollView.bounces = false
- slideScrollView.showsHorizontalScrollIndicator = true
- slideScrollView.delegate = self
-
- return slideScrollView
- }()
- }
- //MARK: - UICollectionView Delegate & DataSource & collectionPrivate
- extension AKExcelView {
-
- func numberOfSections(in collectionView: UICollectionView) -> Int {
-
- if collectionView == headMovebleCollectionView || collectionView == headFreezeCollectionView {
- return 1
- }
- return contentData?.count ?? 0
- }
-
- func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
-
- guard let firstBodyData = self.contentData?.first else { return 0 }
-
- if collectionView == headFreezeCollectionView || collectionView == contentFreezeCollectionView {
- return leftFreezeColumn
- } else {
- if let pros = properties {
- return pros.count - leftFreezeColumn
- }
- let slideColumn = firstBodyData.propertyNames().count - leftFreezeColumn
- return slideColumn
- }
- }
-
- func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
-
- let cell = collectionView.dequeueReusableCell(withReuseIdentifier: AKCollectionViewCellIdentifier, for: indexPath) as! AKExcelCollectionViewCell
- cell.horizontalMargin = self.textMargin
- self.configCells(collectionView: collectionView, cell: cell, indexPath: indexPath)
-
- return cell
- }
-
- private func configCells(collectionView:UICollectionView ,cell:AKExcelCollectionViewCell ,indexPath: IndexPath) {
-
- var targetIndexPath = indexPath
- if collectionView == headFreezeCollectionView {
-
- cell.textLabel.text = headerTitles?[indexPath.row]
- cell.backgroundColor = headerBackgroundColor
- cell.textLabel.font = headerTextFontSize
- } else if collectionView == headMovebleCollectionView {
-
- cell.backgroundColor = headerBackgroundColor
- cell.textLabel.text = headerTitles?[indexPath.item + leftFreezeColumn]
- cell.textLabel.font = headerTextFontSize
- targetIndexPath = NSIndexPath(item: indexPath.item + leftFreezeColumn, section: indexPath.section) as IndexPath
- }else if (collectionView == contentFreezeCollectionView) {
- let text = dataManager.contentFreezeData[indexPath.section][indexPath.item]
- cell.textLabel.text = text
- cell.backgroundColor = contentBackgroundColor
- cell.textLabel.textColor = contentTextColor
- cell.textLabel.font = contentTextFontSize
- targetIndexPath = NSIndexPath(item: indexPath.item, section: indexPath.section + 1) as IndexPath
- } else {
- let text = dataManager.contentSlideData[indexPath.section][indexPath.item]
- cell.textLabel.text = text
- cell.backgroundColor = contentBackgroundColor
- if let contentDataColor = contentDataColor {
- cell.textLabel.textColor = contentDataColor[indexPath.section][indexPath.item + 1]
- } else {
- cell.textLabel.textColor = contentTextColor
- }
- cell.textLabel.font = contentTextFontSize
- targetIndexPath = NSIndexPath(item: indexPath.item + leftFreezeColumn, section: indexPath.section + 1) as IndexPath
- }
-
- self.customViewInCell(cell: cell, indexPath: targetIndexPath)
- self.attributeStringInCell(cell: cell, indexPath: targetIndexPath)
- }
-
- func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
- if (contentData?.count == 0) || self.dataManager.freezeItemSize.count == 0 || self.dataManager.slideItemSize.count == 0 {
-
- return CGSize.zero
- } else {
-
- if (collectionView == headFreezeCollectionView ||
- collectionView == contentFreezeCollectionView) {
-
- return NSCoder.cgSize(for: self.dataManager.freezeItemSize[indexPath.item])
- } else {
-
- return NSCoder.cgSize(for: self.dataManager.slideItemSize[indexPath.item])
- }
- }
- }
-
- func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
-
- var targetIndexPath = indexPath
- if collectionView == headFreezeCollectionView {
-
- } else if (collectionView == headMovebleCollectionView) {
- targetIndexPath = NSIndexPath.init(item: indexPath.item + leftFreezeColumn, section: indexPath.section) as IndexPath
- } else if (collectionView == contentFreezeCollectionView) {
- targetIndexPath = NSIndexPath.init(item: indexPath.item, section: indexPath.section + 1) as IndexPath
- } else {
- targetIndexPath = NSIndexPath.init(item: indexPath.item + leftFreezeColumn, section: indexPath.section + 1) as IndexPath
- }
- self.delegate?.excelView?(self, didSelectItemAt: targetIndexPath)
- }
-
- func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
-
- if itemInsets != nil {
- return itemInsets!
- }
- return UIEdgeInsets.zero
- }
- }
- //MARK: - UISCrollViewDelegate
- extension AKExcelView {
-
- func scrollViewDidScroll(_ scrollView: UIScrollView) {
-
- if scrollView != contentScrollView {
- contentFreezeCollectionView.contentOffset = scrollView.contentOffset
- contentMoveableCollectionView.contentOffset = scrollView.contentOffset
-
- if scrollView.contentOffset.y > 1 {
- showHorizontalDivideShadowLayer()
- } else {
- dismissHorizontalDivideShadowLayer()
- }
- }else{
- dPrint("scrollView.contentOffset.y is \(scrollView.contentOffset.y)")
- if (scrollView.contentOffset.x > 0) {
- showVerticalDivideShadowLayer()
- } else {
- dismissVerticalDivideShadowLayer()
- }
- CATransaction.begin()
- CATransaction.setDisableActions(true)
- veritcalShadow.transform = CATransform3DMakeTranslation(scrollView.contentOffset.x, 0, 0)
- CATransaction.commit()
- }
- }
-
- func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
- if autoScrollToNearItem && scrollView == contentScrollView && !decelerate {
- scrollEndAnimation(scrollView: scrollView)
- }
- }
-
- func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
- if scrollView == contentScrollView && autoScrollToNearItem {
- scrollEndAnimation(scrollView: scrollView)
- }
- }
-
- fileprivate func scrollEndAnimation(scrollView: UIScrollView) {
-
- let offSetX = scrollView.contentOffset.x
-
- let deltaOffSets = dataManager.slideItemOffSetX.compactMap({ (offset) -> CGFloat in
-
- return abs(offset - offSetX)
- })
-
- var min:CGFloat = deltaOffSets[0]
-
- for i in 0 ..< deltaOffSets.count {
- if deltaOffSets[i] < min {
- min = deltaOffSets[i]
- }
- }
- let index = deltaOffSets.firstIndex(of: min)
- let slideToOffset = dataManager.slideItemOffSetX[index!]
-
- let scrollViewWidth = bounds.width - dataManager.freezeWidth
-
- dPrint("dataManager.slideWidth - offSetX - scrollViewWidth is \(dataManager.slideWidth - offSetX - scrollViewWidth)")
- if abs(dataManager.slideWidth - offSetX - scrollViewWidth) <= 1 { // FIXME: 不知为何,有一些误差
-
- return
- }
-
- UIView.animate(withDuration: 0.5, animations: {
- scrollView.contentOffset.x = slideToOffset
- })
- }
- }
- //MARK: - CollectionView Extension
- extension UICollectionView {
-
- /**
- * 遍历构造函数
- */
-
- convenience init(delelate: UICollectionViewDelegate , datasource: UICollectionViewDataSource){
-
- let flowLayout = UICollectionViewFlowLayout()
- flowLayout.minimumLineSpacing = 0
- flowLayout.minimumInteritemSpacing = 0
- flowLayout.headerReferenceSize = CGSize(width: kScreenWidth, height: 0)
-
- self.init(frame: CGRect.zero, collectionViewLayout: flowLayout)
-
- dataSource = datasource
- delegate = delelate
- register(AKExcelCollectionViewCell.self, forCellWithReuseIdentifier: AKCollectionViewCellIdentifier)
- backgroundColor = UIColor.clear
- showsVerticalScrollIndicator = false
- translatesAutoresizingMaskIntoConstraints = false
- if #available(iOS 11.0, *) {
- self.contentInsetAdjustmentBehavior = .never
- }
- }
- }
- //MARK: - AKExcelView Delegate Implemention
- extension AKExcelView {
-
- fileprivate func customViewInCell(cell : AKExcelCollectionViewCell , indexPath : IndexPath) {
-
- let customView = delegate?.excelView?(self, viewAt: indexPath)
- cell.customView = customView
- }
-
- fileprivate func attributeStringInCell(cell: AKExcelCollectionViewCell , indexPath : IndexPath) {
-
- let attributeString = delegate?.excelView?(self, attributedStringAt: indexPath)
- if attributeString != nil {
- cell.textLabel.attributedText = attributeString
- }
- }
- }
|