Swift - 使用CollectionView实现图片Stack层叠效果
http://www.hangge.com/blog/cache/detail_1605.html
本文通过自定义 UICollectionView 布局,实现一个用于图片层叠展示(Stack)效果。
1,效果图
(1)图片从下往上层层堆叠,第一张在最顶层,最后一张在最底部。
(2)每张图片会有一定的旋转角度,体现层叠的效果(最上面的一张不旋转)。
(3)点击图片则将该图片删除,点击空白处会在最上方插入一张图片。不管新增还是删除都有动画效果。
(5)点击导航栏上的“切换”按钮,可以在普通的流式布局和我们自定义的层叠布局间相互切换。切换时也是有动画效果的。
2,层叠布局类:StackCollectionViewLayout
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
import UIKitclass StackCollectionViewLayout: UICollectionViewLayout { //元素尺寸(如果继承UICollectionViewFlowLayout的话,自动会有这个属性) var itemSize = CGSize(width:120, height:120) //角度(从上到下,每个元素依次使用) let angles: [CGFloat] = [0, 0.2, -0.5, -0.2, 0.5] //边界发生变化时是否重新布局(视图滚动的时候也会触发) //会重新调用prepareLayout和调用 //layoutAttributesForElementsInRect方法获得部分cell的布局属性 override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { return true } //rect范围下所有单元格位置属性 override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { var attrArray: [UICollectionViewLayoutAttributes] = [] let itemCount = self.collectionView!.numberOfItems(inSection: 0) for i in 0..<itemCount { let attr = self.layoutAttributesForItem(at: IndexPath(item: i, section: 0))! attrArray.append(attr) } return attrArray } //这个方法返回每个单元格的位置、大小、角度 override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { let attr = UICollectionViewLayoutAttributes(forCellWith: indexPath) attr.center = CGPoint(x:self.collectionView!.bounds.width / 2, y:self.collectionView!.bounds.height / 2) attr.size = itemSize attr.transform = CGAffineTransform(rotationAngle: angles[indexPath.item % angles.count]) //让第一张显示在最上面 attr.zIndex = self.collectionView!.numberOfItems(inSection: 0) - indexPath.item return attr }} |
3,使用样例
(1)自定义单元格类:MyCollectionViewCell.swift(创建的时候生成对应的 xib 文件)
|
1
2
3
4
5
6
7
8
9
10
11
12
|
import UIKit//自定义的Collection View单元格class MyCollectionViewCell: UICollectionViewCell { //用于显示图片 @IBOutlet weak var imageView: UIImageView! override func awakeFromNib() { super.awakeFromNib() }} |
(2)主视图代码
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
import UIKitclass ViewController: UIViewController { //普通的flow流式布局 var flowLayout:UICollectionViewFlowLayout! //自定义的层叠布局 var stackLayput:StackCollectionViewLayout! var collectionView:UICollectionView! //重用的单元格的Identifier let CellIdentifier = "myCell" //所有书籍数据 var images = ["c#.png", "html.png", "java.png", "js.png", "php.png", "react.png", "ruby.png", "swift.png", "xcode.png"] override func viewDidLoad() { super.viewDidLoad() //初始化Collection View initCollectionView() //注册tap点击事件 let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(ViewController.handleTap(_:))) collectionView.addGestureRecognizer(tapRecognizer) } private func initCollectionView() { //初始化flow布局 flowLayout = UICollectionViewFlowLayout() flowLayout.itemSize = CGSize(width: 60, height: 60) flowLayout.sectionInset = UIEdgeInsets(top: 74, left: 0, bottom: 0, right: 0) //初始化自定义布局 stackLayput = StackCollectionViewLayout() //初始化Collection View collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: stackLayput) //Collection View代理设置 collectionView.delegate = self collectionView.dataSource = self collectionView.backgroundColor = .black //注册重用的单元格 let cellXIB = UINib.init(nibName: "MyCollectionViewCell", bundle: Bundle.main) collectionView.register(cellXIB, forCellWithReuseIdentifier: CellIdentifier) //将Collection View添加到主视图中 view.addSubview(collectionView) } //点击手势响应 func handleTap(_ sender:UITapGestureRecognizer){ if sender.state == UIGestureRecognizerState.ended{ let tapPoint = sender.location(in: self.collectionView) //点击的是单元格元素 if let indexPath = self.collectionView.indexPathForItem(at: tapPoint) { //通过performBatchUpdates对collectionView中的元素进行批量的插入,删除,移动等操作 //同时该方法触发collectionView所对应的layout的对应的动画。 self.collectionView.performBatchUpdates({ () -> Void in self.collectionView.deleteItems(at: [indexPath]) self.images.remove(at: indexPath.row) }, completion: nil) } //点击的是空白位置 else{ //新元素插入的位置(开头) let index = 0 images.insert("xcode.png", at: index) self.collectionView.insertItems(at: [IndexPath(item: index, section: 0)]) } } } //切换布局样式 @IBAction func changeLayout(_ sender: Any) { self.collectionView.collectionViewLayout.invalidateLayout() //交替切换新布局 let newLayout = collectionView.collectionViewLayout .isKind(of: StackCollectionViewLayout.self) ? flowLayout : stackLayput collectionView.setCollectionViewLayout(newLayout, animated: true) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() }}//Collection View数据源协议相关方法extension ViewController: UICollectionViewDataSource { //获取分区数 func numberOfSections(in collectionView: UICollectionView) -> Int { return 1 } //获取每个分区里单元格数量 func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return images.count } //返回每个单元格视图 func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { //获取重用的单元格 let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CellIdentifier, for: indexPath) as! MyCollectionViewCell //设置内部显示的图片 cell.imageView.image = UIImage(named: images[indexPath.item]) return cell }}//Collection View样式布局协议相关方法extension ViewController: UICollectionViewDelegate { } |
原文出自:www.hangge.com 转载请保留原文链接:http://www.hangge.com/blog/cache/detail_1605.html




浙公网安备 33010602011771号