SWIFT 3中的UICOLLECTIONVIEW,没有界面构建器。
集合视图类似于表视图,它们显示由自定义布局定义的单元格的集合,并且像表视图一样,它们必须符合协议才能显示数据和执行操作。 在本教程中,我们将创建一个看起来像网格的集合视图。
好吧,让我们潜入……
让我们开始创建一个新项目,这次选择Swift。 现在,让我开始向您介绍将处理collectionView布局的类UICollectionViewFlowLayout。
创建一个新的Cocoa Touch文件并使其成为UICollectionViewFlowLayout的子类,添加此完整的实现,我将对其进行解释……
let innerSpace: CGFloat = 1.0
let numberOfCellsOnRow: CGFloat = 3
override init() {
super.init()
self.minimumLineSpacing = innerSpace
self.minimumInteritemSpacing = innerSpace
self.scrollDirection = .vertical
}
required init?(coder aDecoder: NSCoder) {
//fatalError("init(coder:) has not been implemented")
super.init(coder: aDecoder)
}
func itemWidth() -> CGFloat {
return (collectionView!.frame.size.width/self.numberOfCellsOnRow)-self.innerSpace
}
override var itemSize: CGSize {
set {
self.itemSize = CGSize(width:itemWidth(), height:itemWidth())
}
get {
return CGSize(width:itemWidth(),height:itemWidth())
}
}
我们想要创建一个在单元格之间水平和垂直方向上有1个点的网格布局,这就是为什么我们有一个具有该值的常量并将其分配给ninimumLineSpacing和minimumInteritemSpacing属性的原因。
现在,我敢打赌,您所有的注意力都在“致命错误”行上,看起来确实很吓人,但是声明此“怪异”行的方法只是一个失败的初始化程序,我不会深入探讨此主题,但是您可以在这里查看更多信息,也不会触发aDecoder:NSCoder不会触发,因为我们将在代码中完成所有操作,并且只有在接口构建器上实现collectionView时才会触发。
itemWidth函数返回除以的完整宽度,但是要在“行”中减去多少单元格,减去内部空间的数量。
最后,我们通过返回新的CGSize覆盖itemSize属性。
这就是布局的全部内容,现在让我们跳到ViewController文件,添加这两个变量…
var gridCollectionView: UICollectionView!
var gridLayout: GridLayout!
在viewDidLoad方法中,让我们使用新的GridLayout类来实现collectionView,如下所示:
gridLayout = GridLayout()
gridCollectionView = UICollectionView.init(frame: CGRect.zero, collectionViewLayout: gridLayout)
gridCollectionView.backgroundColor = UIColor.orange
gridCollectionView.showsVerticalScrollIndicator = false
gridCollectionView.showsHorizontalScrollIndicator = false
self.view.addSubview(gridCollectionView)
现在,我们需要为collectionView设置大小和位置,复制并粘贴…
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
var frame = gridCollectionView.frame
frame.size.height = self.view.frame.size.height
frame.size.width = self.view.frame.size.width
frame.origin.x = 0
frame.origin.y = 0
gridCollectionView.frame = frame
}
是时候创建一个自定义Cell,创建UICollectionviewCell的新可可触摸文件子类,并将其命名为ImageCell,复制并粘贴了……
class ImageCell: UICollectionViewCell {
var imageView: UIImageView!
override init(frame: CGRect) {
super.init(frame: frame)
imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.isUserInteractionEnabled = false
contentView.addSubview(imageView)
}
override func layoutSubviews() {
super.layoutSubviews()
var frame = imageView.frame
frame.size.height = self.frame.size.height
frame.size.width = self.frame.size.width
frame.origin.x = 0
frame.origin.y = 0
imageView.frame = frame
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
在这里,我们向其中添加一个ImageView,这就是该单元格了。
在viewDidLoad中,我们为我们的collectionView注册类单元,并设置委托和数据源,将这些行添加到gridCollectionView的实现中。
gridCollectionView!.register(ImageCell.self, forCellWithReuseIdentifier: "cell")
gridCollectionView.dataSource = self
gridCollectionView.delegate = self
现在,您的编译器在抱怨,这是因为我们需要遵循协议,通常我们将其添加到类名的旁边,但是Swift为我们提供了一种更好的方法,并且扩展在哪里发光。 扩展使我们能够在不破坏类实现的情况下放置协议的所有逻辑,Apple似乎非常重视可读性,这对我们来说真是太棒了。 在课堂外,复制并粘贴此内容…
extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 50
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! ImageCell
cell.imageView.image = UIImage.init(named: "puppy")
return cell
}
}
当然,您可以更改逻辑,例如,显示来自restApi的图像集合,但为简单起见,在我的情况下,我们仅使用一个图像,我向资产中添加了Puppy图像,请继续并寻找一个不错的选择。图像,运行该应用程序,您将看到图像的完整网格布局!
让我们更进一步,添加一些基本的动画,使用alpha值来创建溶解效果,并使用UIGesturRecoginzer。
开始将UIImageView添加到viewDidLoad中的项目并将其alpha值设置为0
fullImageView = UIImageView()
fullImageView.contentMode = .scaleAspectFit
fullImageView.backgroundColor = UIColor.lightGray
fullImageView.isUserInteractionEnabled = true
fullImageView.alpha = 0
self.view.addSubview(fullImageView)
使用具有相同尺寸和collectionView位置的fullImageView布局,将这行添加到ViewWillLayoutSubViews方法中…
fullImageView.frame = gridCollectionView.frame
如果立即运行该应用程序,将看不到fullImageView,这是因为alpha值为0,alpha属性值从0变为1,O不可见,直到1完全可见。
让我们创建一个将alpha更改回完全可见的方法,并使用CGAffineTransform制作很酷的动画,复制和粘贴…
func showFullImage(of image:UIImage) {
fullImageView.transform = CGAffineTransform(scaleX: 0, y: 0)
fullImageView.contentMode = .scaleAspectFit
UIView.animate(withDuration: 0.5, delay: 0, options: [], animations:{
self.fullImageView.image = image
self.fullImageView.alpha = 1
self.fullImageView.transform = CGAffineTransform(scaleX: 1, y: 1)
}, completion: nil)
}
转到您的扩展程序,然后添加…
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! ImageCell
if let image = cell.imageView.image {
self.showFullImage(of: image)
} else {
print("no photo")
}
}
现在,如果您运行该应用程序,则在您点击任何单元格时,它将向您显示fullImageView,但是我们需要关闭该视图,并要完成此操作,我们将向其中添加一个UITapGestureRecognizer; 在viewDidLoad中添加此行…
let dismissWihtTap = UITapGestureRecognizer(target: self, action: #selector(hideFullImage))
fullImageView.addGestureRecognizer(dismissWihtTap)
最后,让我们实现该方法,以关闭编译器错误,让我们通过创建“溶解效果”来再次使用Alpha,在0.5秒内将Alpha更改回0,当然,您可以根据需要自定义其持续时间,这是功能…
func hideFullImage() {
UIView.animate(withDuration: 0.5, delay: 0, options: [], animations:{[unowned self] in
self.fullImageView.alpha = 0
}, completion: nil)
}
运行该应用程序,点击一个单元格以显示完整图像,然后点击该图像将其关闭。 现在,您可以采用第一种方法来使用不同的有用工具,例如UICollectionViews,扩展,CGAffineTransform,使用视图属性,例如在动画块中更改Alpha以创建炫酷效果并使用UITapGestureRecognizer来执行操作。
希望这对您有所帮助,这是Swift中的完整项目以及Objective-C中的整个项目。
这是Swift 4项目的新版本,并以编程方式使用Autolayout。
和平!