UICollectionView在Swift3.0中的用法
UICollectionView的初始化跟OC中是相似的,创建 GameView 集成自 UICollectionView 。注意不同于UITableView的用法,他需要用 UICollectionViewFlowLayout 来指定一些需要设置的属性,或者可以通过遵守
UICollectionViewDelegateFlowLayout 这个代理来实现。下面我用设置属性的方式来实现的,比较方便。
//布局 layout.scrollDirection = .vertical//滑动方向 这个就是默认是纵向滑动 layout.itemSize = CGSize( 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( maiSrc.width, height: 30)//设置headerView的size layout.footerReferenceSize = CGSize( 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, maiSrc.width, height: maiSrc.height - 20)) self.view.addSubview(game) }
源码 :
// // 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, 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( maiSrc.width, height: 30)//设置headerView的size layout.footerReferenceSize = CGSize( 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") } }