Swift - 使用CollectionView实现图片Stack层叠效果

http://www.hangge.com/blog/cache/detail_1605.html

本文通过自定义 UICollectionView 布局,实现一个用于图片层叠展示(Stack)效果。
 

1,效果图

(1)图片从下往上层层堆叠,第一张在最顶层,最后一张在最底部。
(2)每张图片会有一定的旋转角度,体现层叠的效果(最上面的一张不旋转)。
(3)点击图片则将该图片删除,点击空白处会在最上方插入一张图片。不管新增还是删除都有动画效果。
(5)点击导航栏上的“切换”按钮,可以在普通的流式布局和我们自定义的层叠布局间相互切换。切换时也是有动画效果的。
   原文:Swift - 使用CollectionView实现图片Stack层叠效果      原文:Swift - 使用CollectionView实现图片Stack层叠效果

 

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 UIKit
 
class StackCollectionViewLayoutUICollectionViewLayout {
     
    //元素尺寸(如果继承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 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 文件)
原文:Swift - 使用CollectionView实现图片Stack层叠效果
1
2
3
4
5
6
7
8
9
10
11
12
import UIKit
 
//自定义的Collection View单元格
class MyCollectionViewCellUICollectionViewCell {
 
    //用于显示图片
    @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 UIKit
 
class ViewControllerUIViewController {
    //普通的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(inself.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 ViewControllerUICollectionViewDataSource {
    //获取分区数
    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:
            CellIdentifierfor: indexPath) asMyCollectionViewCell
        //设置内部显示的图片
        cell.imageView.image = UIImage(named: images[indexPath.item])
        return cell
    }
}
 
//Collection View样式布局协议相关方法
extension ViewControllerUICollectionViewDelegate {
     
}


原文出自:www.hangge.com  转载请保留原文链接:http://www.hangge.com/blog/cache/detail_1605.html

posted @ 2018-07-05 12:03  sundaysios  阅读(965)  评论(0编辑  收藏  举报