1. 程式人生 > >Swift - 使用CollectionView實現圖片Gallery畫廊效果(左右滑動瀏覽圖片)

Swift - 使用CollectionView實現圖片Gallery畫廊效果(左右滑動瀏覽圖片)

abs ber pad comment style 即將 使用 ram 數據源

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

Swift - 使用CollectionView實現圖片Gallery畫廊效果(左右滑動瀏覽圖片)