Swift - 使用CollectionView实现图片Gallery画廊效果(左右滑动浏览图片)

1,效果图

(1)图片从左至右横向排列(只有一行),通过手指拖动可以前后浏览图片。

(2)视图滚动时,每张图片根据其与屏幕中心距离的不同,显示尺寸也会相应地变化。越靠近屏幕中心尺寸就越大,远离屏幕中心的就逐渐变小。

(3)滑动结束后,会有位置自动修正的功能。即将当前最靠近屏幕中点的图片移动到正中央。

(4)点击图片则将该图片删除,点击空白处会在最开始的位置插入一张图片。不管新增还是删除都有动画效果。

(5)点击导航栏上的“切换”按钮,可以在普通的流式布局和我们自定义的画廊布局间相互切换。切换时也是有动画效果的。

        

2,画廊布局类:LinearCollectionViewLayout


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

import UIKit

class LinearCollectionViewLayout: UICollectionViewFlowLayout {

    

    //元素宽度

    var itemWidth:CGFloat = 100

    //元素高度

    var itemHeight:CGFloat = 100

    

    //对一些布局的准备操作放在这里

    override func prepare() {

        super.prepare()

        //设置元素大小

        self.itemSize = CGSize(width: itemWidth, height: itemHeight)

        //设置滚动方向

        self.scrollDirection = .horizontal

        //设置间距

        self.minimumLineSpacing = self.collectionView!.bounds.width / 2 -  itemWidth

        

        //设置内边距

        //左右边距为了让第一张图片与最后一张图片出现在最中央

        //上下边距为了让图片横行排列,且只有一行

        let left = (self.collectionView!.bounds.width - itemWidth) / 2

        let top = (self.collectionView!.bounds.height - itemHeight) / 2

        self.sectionInset = UIEdgeInsetsMake(top, left, top, left)

    }

    

    //边界发生变化时是否重新布局(视图滚动的时候也会触发)

    //会重新调用prepareLayout和调用

    //layoutAttributesForElementsInRect方法获得部分cell的布局属性

    override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {

        return true

    }

    

    //rect范围下所有单元格位置属性

    override func layoutAttributesForElements(in rect: CGRect)

        -> [UICollectionViewLayoutAttributes]? {

        //从父类得到默认的所有元素属性

        let array = super.layoutAttributesForElements(in: rect)

        

        //可见区域(目前显示出来的位于collection view上的矩形区域)

        let visiableRect = CGRect(x: self.collectionView!.contentOffset.x,

                                  y: self.collectionView!.contentOffset.y,

                                  width: self.collectionView!.frame.width,

                                  height: self.collectionView!.frame.height)

        

        //当前屏幕中点,相对于collect view上的x坐标

        let centerX = self.collectionView!.contentOffset.x

            + self.collectionView!.bounds.width / 2

        

        //这个是为了计算缩放比例的

        let maxDeviation = self.collectionView!.bounds.width / 2 + itemWidth / 2

        

        for attributes in array! {

            //与可见区域做碰撞,如果该单元格没显示则直接跳过

            if !visiableRect.intersects(attributes.frame) {continue}

            //显示的单元根据偏移量决定放大倍数(最大放大1.8倍,而离屏幕中央越远的单元格缩放的越小)

            let scale = 1 + (0.8 - abs(centerX - attributes.center.x) / maxDeviation)

            attributes.transform = CGAffineTransform(scaleX: scale, y: scale)

        }

        

        return array

    }

    

    /**

     用来设置collectionView停止滚动那一刻的位置(实现目的是当停止滑动,时刻有一张图片是位于屏幕最中央的)

     proposedContentOffset: 原本collectionView停止滚动那一刻的位置

     velocity:滚动速度

     返回:最终停留的位置

     */

    override func targetContentOffset(forProposedContentOffset

        proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {

        //停止滚动时的可见区域

        let lastRect = CGRect(x: proposedContentOffset.x, y: proposedContentOffset.y,

                              width: self.collectionView!.bounds.width,

                              height: self.collectionView!.bounds.height)

        //当前屏幕中点,相对于collect view上的x坐标

        let centerX = proposedContentOffset.x + self.collectionView!.bounds.width * 0.5;

        //这个可见区域内所有的单元格属性

        let array = self.layoutAttributesForElements(in: lastRect)

        

        //需要移动的距离

        var adjustOffsetX = CGFloat(MAXFLOAT);

        for attri in array! {

            //每个单元格里中点的偏移量

            let deviation = attri.center.x - centerX

            //保存偏移最小的那个

            if abs(deviation) < abs(adjustOffsetX) {

                adjustOffsetX = deviation

            }

        }

        //通过偏移量返回最终停留的位置

        return CGPoint(x: proposedContentOffset.x + adjustOffsetX, y: proposedContentOffset.y)

    }

}

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 UIKit

class ViewController: UIViewController {

    //普通的flow流式布局

    var flowLayout:UICollectionViewFlowLayout!

    //自定义的线性布局

    var linearLayput:LinearCollectionViewLayout!

    

    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)

        

        //初始化自定义布局

        linearLayput = LinearCollectionViewLayout()

        

        //初始化Collection View

        collectionView = UICollectionView(frame: view.bounds,

                                          collectionViewLayout: linearLayput)

        

        //Collection View代理设置

        collectionView.delegate = self

        collectionView.dataSource = self

        collectionView.backgroundColor = .white

        

        //注册重用的单元格

        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: LinearCollectionViewLayout.self) ? flowLayout : linearLayput

        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 {

    

}

源码下载:hangge_1602.zip
原文出自:www.hangge.com  转载请保留原文链接:http://www.hangge.com/blog/cache/detail_1602.html

时间: 2024-10-22 02:51:42

Swift - 使用CollectionView实现图片Gallery画廊效果(左右滑动浏览图片)的相关文章

自定义View 之利用ViewPager 实现画廊效果(滑动放大缩小)

自定义View 之利用ViewPager 实现画廊效果(滑动放大缩小) 转载请标明出处: http://blog.csdn.net/lisdye2/article/details/52315008 本文出自:[Alex_MaHao的博客] 项目中的源码已经共享到github,有需要者请移步[Alex_MaHao的github] 基本介绍 画廊在很多的App设计中都有,如下图所示: 该例子是我没事的时候写的一个小项目,具体源码地址请访问https://github.com/AlexSmille/Y

wpf 模拟3D效果(和手机浏览图片效果相似)(附源码)

原文 wpf 模拟3D效果(和手机浏览图片效果相似)(附源码) pf的3D是一个很有意思的东西,类似于ps的效果,类似于电影动画的效果,因为动画的效果,(对于3D基础的摄像机,光源,之类不介绍,对于依赖属性也不介绍.),个人认为,依赖属性这个东西,有百分之五十是为了3D而存在.(自己写的类似于demo的东西)先上图,无图无真相这是demo的整个效果图,可以用鼠标移动,触摸屏也可以手指滑动,图片会移动,然后移动结束,会有一个回弹的判断. <Window x:Class="_3Dshow.Wi

Gallery画廊视图

画廊视图使用Gallery表示,能够按水平方向显示内容,并且可以手指直接拖动图片和移动,一般用来浏览图片,,被选中的选项位于中间,并且可以响应事件显示信息.在使用画廊视图时,首先在屏幕上添加Gallery组件,通常使用标记在XML而布局文件中添加. 画廊视图在4.0后已经过期,但是我们仍然可以使用,不过后面我们将用水平的ListView自定义组件来实现这个效果,在自定义视图中讲解. 常用属性:1. android:animationDuration 用于设置列表项切换时的动画持续时间2. and

UI组件之AdapterView及其子类(四)Gallery画廊控件使用

听说 Gallery如今已经不使用了,API使用ViewPaper取代了,以后再学专研ViewPaper吧如今说说Gallery画廊,就是不停显示图片的意思 Gallery是用来水平滚动的显示一系列项目.Gallery组件能够横向显示一个图像列表,当单击当前图像的后一个图像时,这个图像列表会向左移动一格,当单击当前图像的前一个图像时,这个图像列表会向右移动一样. 也能够通过拖动的方式来向左和向右移动图像列表在使用Gallery的时候,我们应指定他的背景.不然它的项目会紧凑的贴在一起.不会产生画廊

JS图片自动轮换效果实现

今天不在状态,五一快到了,俺就特想玩了.好了,天色已晚,闲话不多说,看下用javaScript 实现的图片自动轮换效果,先看图片 下面是具体的代码,还是比较简单的. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="htt

Gallery实现ViewPager的页面切换效果、以及实现图片画廊效果

activity_main.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"

利用ViewPager实现3D画廊效果及其图片加载优化

前言 对于ViewPager,相信大家都已经很熟悉了,在各种切换场景比如Fragment切换.选项卡的切换或者顶部轮播图片等都可以用ViewPager去实现.那么本篇文章带来ViewPager的一种实现效果:3D画廊.直接上图来看: 从上面的图我们可以看出,整个页面分成三个部分,中间的是大图,正中地显示给用户:而两边的是侧图,而这两幅图片又有着角度的旋转,与大图看起来不在同一平面上,这就形成了3D效果.接着拖动页面,侧面的图慢慢移到中间,这个过程也是有着动画的,包括了图片的旋转.缩放和平移.在欣

Swift 使用CollectionView 实现图片轮播封装就是这样简单

前言: 这篇你可以学会自定义视图,创建collectionView,协议的使用,定时器; 自制图片 先上Demo:Github上封装好的下载即用, 好用请Star Thanks首先新建一个继承于UIView的视图, 且用collectionView实现所以需要签订两个协议代码如下: let sectionNum: Int = 100 // 区的数量 let width = UIScreen.mainScreen().bounds.size.width // 屏幕宽度 let height = U

带放大镜效果的jQuery LightBox图片画廊插件

zbox是一款带放大镜效果的jQuery LightBox图片画廊插件.该Lightbox插件可以显示相应缩略图的高清大图,并且在浏览高清大图时还可以使用放大镜来局部查看放大效果. 在线预览   源码下载 使用方法 使用该LightBox插件需要引入jQuery和jquery.zbox.css,以及jquery.zbox.js文件 <link type="text/css" rel="stylesheet" href="css/jquery.zbox