UICollectionView的初始化跟OC中是類似的,建立 GameView 集成自 UICollectionView 。注意不一樣於UITableView的用法,他須要用 UICollectionViewFlowLayout 來指定一些須要設置的屬性,或者能夠經過遵照swift
UICollectionViewDelegateFlowLayout 這個代理來實現。下面我用設置屬性的方式來實現的,比較方便。緩存
//佈局 layout.scrollDirection = .vertical//滑動方向 這個就是默認是縱向滑動 layout.itemSize = CGSize(width: width, height: width)//item的size layout.sectionInset = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)//section距上下左右的數據 layout.minimumLineSpacing = CGFloat(integerLiteral: 5)//若是是縱向滑動的話即行間距,若是是橫向滑動則爲列間距 layout.minimumInteritemSpacing = CGFloat(integerLiteral: 5)//若是是縱向滑動的話即列間距,若是是橫向滑動則爲行間距 layout.headerReferenceSize = CGSize(width: maiSrc.width, height: 30)//設置headerView的size layout.footerReferenceSize = CGSize(width: maiSrc.width, height: 30)//設置footerView的size
下邊直接貼出整個的源碼 ,調用就異常簡單了 :數據結構
override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. self.view.backgroundColor = UIColor.white() let game = GameView.init(frame: CGRect(x: 0, y: 20, width: maiSrc.width, height: maiSrc.height - 20)) self.view.addSubview(game) }
源碼 :app
// // GameView.swift // CharacterGame // // Created by 江南花印孓 on 2016/6/28. // Copyright © 2016年 恆江. All rights reserved. // import UIKit let identifier = "identifier" let headerIdentifier = "headerIdentifier" let footerIdentifier = "footerIdentifier" class GameView: UICollectionView ,UICollectionViewDelegate ,UICollectionViewDataSource ,UICollectionViewDataSourcePrefetching{ internal var num = 6 internal var items = 196 var source = [Int]() //MARK:---------這裏是一個 init 初始化標記 init(frame:CGRect) { //TODO: -----int 初始化方法 裏邊要作的事情---- let layout = UICollectionViewFlowLayout.init()//經過Layout的一些屬性把對應數據設置好,則不用再實現對應函數 let leftWidth = maiSrc.width - CGFloat(integerLiteral: ( num + 1 ) * 5) let width = leftWidth / CGFloat(integerLiteral: num) for i in 1...items { source.append(i) } //FIXME: 問題一 : 除了使用layout屬性設置還能夠用什麼方法來實現? //佈局 layout.scrollDirection = .vertical//滑動方向 這個就是默認是縱向滑動 layout.itemSize = CGSize(width: width, height: width)//item的size layout.sectionInset = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)//section距上下左右的數據 layout.minimumLineSpacing = CGFloat(integerLiteral: 5)//若是是縱向滑動的話即行間距,若是是橫向滑動則爲列間距 layout.minimumInteritemSpacing = CGFloat(integerLiteral: 5)//若是是縱向滑動的話即列間距,若是是橫向滑動則爲行間距 layout.headerReferenceSize = CGSize(width: maiSrc.width, height: 30)//設置headerView的size layout.footerReferenceSize = CGSize(width: maiSrc.width, height: 30)//設置footerView的size //FIXME: 注意這個父類 init 方法寫在這裏了 super.init(frame: frame, collectionViewLayout: layout) //初始化 self.backgroundColor = UIColor.white() self.delegate = self self.dataSource = self self.prefetchDataSource = self;//這個協議對應 UICollectionViewDataSourcePrefetching 是 10.0 之後新加的兩個方法,下面介紹 self.isPrefetchingEnabled = true//容許實現 UICollectionViewDataSourcePrefetching 這個協議 10.0 後新加的 self.allowsMultipleSelection = true//容許多選 self.showsVerticalScrollIndicator = false //右側那條上下滑動的線 //這三個方法能夠看底層說明,講的很詳細 self.register(singleCell.self, forCellWithReuseIdentifier: identifier) self.register(headerView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: headerIdentifier) self.register(footerView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: footerIdentifier) //FIXME: 一個很實用的系統定義宏 , 用來打印對應object的全部屬性信息 dump(self) /* * 重排手勢 UICollectionViewController 裏有一個默認爲 true 的屬性用來設置開啓重排手勢功能,實現對應的代理函數便可實現對應功能。 * collectionView(_ : , moveItemAt : , to : ) * 這裏集成自 UICollectionView ,沒有手勢,因此須要添加一個 長按手勢 。 */ let longGesture = UILongPressGestureRecognizer.init(target: self, action: #selector(handlelongGesture)) self.addGestureRecognizer(longGesture) } //MARK: --------------- my action ------------ func handlelongGesture(longGesture:UILongPressGestureRecognizer) -> Void { switch longGesture.state { case .began: //判斷手勢落點所在 item 的 indexPath 是否在 collectionView 內 let index = self.indexPathForItem(at: longGesture.location(in: self)) if index == nil { break } //若是在,那麼就開始移動這個位置上的cell self.beginInteractiveMovementForItem(at: index!) break case .changed: //當位置發生偏移時調用該函數,判斷新的位置是否在 collectionView 之內來決定是放回原位置仍是移動到新的位置 self.updateInteractiveMovementTargetPosition(longGesture.location(in: self)) print("on the way") break case .ended: /* * 接受後調用下邊兩個函數中的一個通知 collectionView 軌跡交互移動已經結束,把item永久的移動到新位置,同時響應 * collectionView(_ : , moveItemAt : , to : ) 函數 來處理數據源 確保數據源的數據結構沒問題 */ self.endInteractiveMovement() break default: self.cancelInteractiveMovement() break } } //MARK: -------- UICollection View Delegate ------- func collectionView(_ collectionView: UICollectionView, canMoveItemAt indexPath: IndexPath) -> Bool { return true } /* 注意:cell重置須要在 UICollectionViewController 裏開啓一個手勢 installsStandardGestureForInteractiveMovement 開關 * 以後由控制器給 collectionView 添加長按手勢 LongPressGesture 以後纔會走下邊的函數 * 單純的 collectionView 並無這個手勢,因此沒法觸發這個代理 */ func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { let str = source[sourceIndexPath.item!] source.remove(at: sourceIndexPath.item!) source.insert(str, at: destinationIndexPath.item!) print("this is a test String") } override func numberOfSections() -> Int { return 1 } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return items } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as! singleCell let index = source[indexPath.item!] cell.age.text = String.init(index) cell.backgroundColor = UIColor.red() return cell } func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { /** * 注意要點 * 1.supplementaryView 的返回類型爲 UICollectionReusableView ,不能混淆,Swift裏邊對於返回值的類型要去很嚴格。 * 2.UICollectionReusableView 繼承自 UIView ,是 UIView 的子類 * 3.kind 分爲 footer 和 header 兩種,區分開來 * 4.kind 和 identifier 要對應起來,由於是兩個不一樣的 reuse identifier */ if kind == UICollectionElementKindSectionHeader { let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerIdentifier, for: indexPath) as! headerView header.name.text = "測試" return header } let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: footerIdentifier, for: indexPath) return footer } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { let index = indexPath.item! as Int print("\(index)") } //MARK: ----------- UICollectionViewDataSourcePrefetching 預取 緩存 ----- /* 獲取 ‘預取’ 地址集合 item出現以前的預處理,iOS 10.0之後新加的,不明覺厲。。不知道有什麼用 * 目前來看 只能是單純的提高運行效率 作一下預處理。。。 * 當界面顯示不完 item 時 , 相似複用隊列同樣能夠緩存一部分還沒有顯示出來的 item ,具體緩存多少目前還沒搞清楚, * 貌似跟幾何面積有關,單個item越大,緩存的行數越少;相反,item的size越小,緩存的行數越多 */ func collectionView(_ collectionView: UICollectionView, prefetchItemsAt indexPaths: [IndexPath]) { //dump(indexPaths) } /* * optional public func collectionView(_ collectionView: UICollectionView, cancelPrefetchingForItemsAt indexPaths: [IndexPath]) * 這個函數的做用看文檔說明,我的理解爲 已經緩存,事實上卻又沒有用到,就是沒有顯示的 item 的子集。 */ required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } } class headerView: UICollectionReusableView { override init(frame: CGRect) { super.init(frame: frame) self.addSubview(name) //單純的個體案例 用不到三方框架 用 VFL 適配 self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[name]-0-|", options: [], metrics: nil, views: ["name":name])) self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[name]-0-|", options: [], metrics: nil, views: ["name" : name ])) self.backgroundColor = UIColor.orange() } //懶加載 lazy var name: UILabel = { let name = UILabel.init()//2098 name.translatesAutoresizingMaskIntoConstraints = false name.backgroundColor = UIColor.red()// name.textAlignment = .center name.textColor = UIColor.white() return name }() required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } } class footerView: UICollectionReusableView { override init(frame: CGRect) { super.init(frame: frame) self.backgroundColor = UIColor.green() } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } } class singleCell: UICollectionViewCell { override init(frame: CGRect) { super.init(frame: frame) self.addSubview(age) self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-[age]-|", options: [], metrics: nil, views: ["age":age])) self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-[age]-|", options: [], metrics: nil, views: ["age" : age ])) } lazy var age: UILabel = { let age = UILabel.init() age.translatesAutoresizingMaskIntoConstraints = false age.backgroundColor = UIColor.blue() age.textAlignment = .center age.textColor = UIColor.white() age.text = "0" return age }() required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } }