Swift - 使用网格(UICollectionView)的自定义布局实现复杂页面

实现自定义布局需要继承UICollectionViewLayout,同时还要重载下面的三个方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
// 内容区域总大小,不是可见区域
override  var  collectionViewContentSize:  CGSize  {
}
 
// 所有单元格位置属性
override  func  layoutAttributesForElements( in  rect:  CGRect )
     -> [ UICollectionViewLayoutAttributes ]? {
}
 
// 这个方法返回每个单元格的位置和大小
override  func  layoutAttributesForItem(at indexPath:  IndexPath )
     ->  UICollectionViewLayoutAttributes ? {
}

下面实现一个自定义布局的例子,单元格有大小两种。网格从上到下,先是左边一个大单元格右边两个小单元格,接着左边两个小单元格右边一个大单元格,依次同上循环排列。 
效果图如下:
  
Swift - 使用网格(UICollectionView)的自定义布局实现复杂页面_第1张图片

--- 自定义布局 CustomLayout.swift ---
(本文样例代码已升级到Swift3)
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
import  UIKit
 
/**
  * 这个类只简单定义了一个section的布局
  */
class  CustomLayout  UICollectionViewLayout  {
     
     // 内容区域总大小,不是可见区域
     override  var  collectionViewContentSize:  CGSize  {
         let  width = collectionView!.bounds.size.width - collectionView!.contentInset.left
             - collectionView!.contentInset.right
         let  height =  CGFloat ((collectionView!.numberOfItems(inSection: 0) + 1) / 3)
             * (width / 3 * 2)
         return  CGSize (width: width, height: height)
     }
     
     // 所有单元格位置属性
     override  func  layoutAttributesForElements( in  rect:  CGRect )
         -> [ UICollectionViewLayoutAttributes ]? {
             var  attributesArray = [ UICollectionViewLayoutAttributes ]()
             let  cellCount =  self .collectionView!.numberOfItems(inSection: 0)
             for  in  0..
                 let  indexPath =   IndexPath (item:i, section:0)
                 let  attributes =   self .layoutAttributesForItem(at: indexPath)
                 attributesArray.append(attributes!)
             }
             return  attributesArray
     }
     
     // 这个方法返回每个单元格的位置和大小
     override  func  layoutAttributesForItem(at indexPath:  IndexPath )
         ->  UICollectionViewLayoutAttributes ? {
             //当前单元格布局属性
             let  attribute =   UICollectionViewLayoutAttributes (forCellWith:indexPath)
             
             //单元格边长
             let  largeCellSide = collectionViewContentSize.width / 3 * 2
             let  smallCellSide = collectionViewContentSize.width / 3
             
             //当前行数,每行显示3个图片,1大2小
             let  line: Int  =  indexPath.item / 3
             //当前行的Y坐标
             let  lineOriginY =  largeCellSide *  CGFloat (line)
             //右侧单元格X坐标,这里按左右对齐,所以中间空隙大
             let  rightLargeX = collectionViewContentSize.width - largeCellSide
             let  rightSmallX = collectionViewContentSize.width - smallCellSide
             
             // 每行2个图片,2行循环一次,一共6种位置
             if  (indexPath.item % 6 == 0) {
                 attribute.frame =  CGRect (x:0, y:lineOriginY, width:largeCellSide,
                                          height:largeCellSide)
             else  if  (indexPath.item % 6 == 1) {
                 attribute.frame =  CGRect (x:rightSmallX, y:lineOriginY, width:smallCellSide,
                                          height:smallCellSide)
             else  if  (indexPath.item % 6 == 2) {
                 attribute.frame =  CGRect (x:rightSmallX,
                                          y:lineOriginY + smallCellSide,
                                          width:smallCellSide, height:smallCellSide)
             else  if  (indexPath.item % 6 == 3) {
                 attribute.frame =  CGRect (x:0, y:lineOriginY, width:smallCellSide,
                                          height:smallCellSide )
             else  if  (indexPath.item % 6 == 4) {
                 attribute.frame =  CGRect (x:0,
                                          y:lineOriginY + smallCellSide,
                                          width:smallCellSide, height:smallCellSide)
             else  if  (indexPath.item % 6 == 5) {
                 attribute.frame =  CGRect (x:rightLargeX, y:lineOriginY,
                                          width:largeCellSide,
                                          height:largeCellSide)
             }
             
             return  attribute
     }
     
     /*
      //如果有页眉、页脚或者背景,可以用下面的方法实现更多效果
      func layoutAttributesForSupplementaryViewOfKind(elementKind: String!,
      atIndexPath indexPath: NSIndexPath!) -> UICollectionViewLayoutAttributes!
      func layoutAttributesForDecorationViewOfKind(elementKind: String!,
      atIndexPath indexPath: NSIndexPath!) -> UICollectionViewLayoutAttributes!
      */
}


--- 主页面 ViewController.swift ---
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
import  UIKit
 
class  ViewController UIViewController UICollectionViewDelegate UICollectionViewDataSource
{
     var  collectionView: UICollectionView !
     //课程名称和图片,每一门课程用字典来表示
     let  courses = [
         [ "name" : "Swift" , "pic" : "swift.png" ],
         [ "name" : "Xcode" , "pic" : "xcode.png" ],
         [ "name" : "Java" , "pic" : "java.png" ],
         [ "name" : "PHP" , "pic" : "php.png" ],
         [ "name" : "JS" , "pic" : "js.png" ],
         [ "name" : "React" , "pic" : "react.png" ],
         [ "name" : "Ruby" , "pic" : "ruby.png" ],
         [ "name" : "HTML" , "pic" : "html.png" ],
         [ "name" : "C#" , "pic" : "c#.png" ]
     ]
     
     override  func  viewDidLoad() {
         super .viewDidLoad()
         
         let  layout =  CustomLayout ()
         //let layout = UICollectionViewFlowLayout()
         let  frame =  CGRect (x:0, y:20, width: view.bounds.size.width,
                            height:view.bounds.height-20)
         self .collectionView =  UICollectionView (frame: frame, collectionViewLayout:layout)
         self .collectionView.delegate =  self
         self .collectionView.dataSource =  self
         // 注册CollectionViewCell
         self .collectionView.register( UICollectionViewCell . self ,
                                      forCellWithReuseIdentifier:  "ViewCell" )
         //默认背景是黑色和label一致
         self .collectionView.backgroundColor =  UIColor .white
         
         //设置collectionView的内边距
         self .collectionView.contentInset =  UIEdgeInsetsMake (0, 5, 0, 5)
         
         self .view.addSubview(collectionView)
     }
     
     override  func  didReceiveMemoryWarning() {
         super .didReceiveMemoryWarning()
     }
     
     // CollectionView行数
     func  collectionView(_ collectionView:  UICollectionView ,
                         numberOfItemsInSection section:  Int ) ->  Int  {
         return  courses.count;
     }
     
     // 获取单元格
     func  collectionView(_ collectionView:  UICollectionView ,
                         cellForItemAt indexPath:  IndexPath ) ->  UICollectionViewCell  {
         // storyboard里设计的单元格
         let  identify: String  "ViewCell"
         // 获取设计的单元格,不需要再动态添加界面元素
         let  cell =  self .collectionView.dequeueReusableCell(
             withReuseIdentifier: identify,  for : indexPath)  as  UICollectionViewCell
         //先清空内部原有的元素
         for  subview  in  cell.subviews {
             subview.removeFromSuperview()
         }
         // 添加图片
         let  img =  UIImageView (image:  UIImage (named: courses[indexPath.item][ "pic" ]!))
         img.frame = cell.bounds
         img.contentMode = .scaleAspectFit
         // 图片上面显示课程名称,居中显示
         let  lbl =  UILabel (frame: CGRect (x:0, y:0, width:cell.bounds.size.width, height:20))
         lbl.textColor =  UIColor .white
         lbl.textAlignment = .center
         lbl.backgroundColor =  UIColor (red: 0, green: 0, blue: 0, alpha: 0.2)
         lbl.text = courses[indexPath.item][ "name" ]
         cell.addSubview(img)
         cell.addSubview(lbl)
         return  cell
     }
     
     /* 自定义布局不需要调用
      //单元格大小
      func collectionView(collectionView: UICollectionView!,
      layout collectionViewLayout: UICollectionViewLayout!,
      sizeForItemAtIndexPath indexPath: NSIndexPath!) -> CGSize {
      let size:Float = indexPath.item % 3 == 0 ? 200 : 100
      return CGSize(width:size, height:size)
      }
      */
}

你可能感兴趣的:(swift,自定义Layout)