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

网格UICollectionView除了使用流布局,还可以使用自定义布局。实现自定义布局需要继承UICollectionViewLayout,同时还要重载下面的三个方法:


1

2

3

4

5

6

7

8

9

10

11

12

// 这个方法返回每个单元格的位置和大小

override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath)

    -> UICollectionViewLayoutAttributes! {

}

// 返回内容区域总大小,不是可见区域

override func collectionViewContentSize() -> CGSize {

}

// 返回所有单元格位置属性

override func layoutAttributesForElementsInRect(rect: CGRect) -> [AnyObject] {

}

下面实现一个自定义布局的例子,单元格有大小两种。网格从上到下,先是左边一个大单元格右边两个小单元格,接着左边两个小单元格右边一个大单元格,依次同上循环排列。

效果图如下:

--- 自定义布局 CustomLayout.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

import UIKit

/**

 * 这个类只简单定义了一个section的布局

 */

class CustomLayout : UICollectionViewLayout {

    

    // 内容区域总大小,不是可见区域

    override func collectionViewContentSize() -> CGSize {

        return CGSizeMake(collectionView!.bounds.size.width,

            CGFloat(collectionView!.numberOfItemsInSection(0) * 200 / 3 + 200))

    }

    

    // 所有单元格位置属性

    override func layoutAttributesForElementsInRect(rect: CGRect) -> [AnyObject] {

        

        var attributesArray = [AnyObject]()

        let cellCount = self.collectionView!.numberOfItemsInSection(0)

        for i in 0..<cellCount {

            var indexPath =  NSIndexPath(forItem:i, inSection:0)

            var attributes =  self.layoutAttributesForItemAtIndexPath(indexPath)

            

            attributesArray.append(attributes)

            

        }

        return attributesArray

    }

    

    // 这个方法返回每个单元格的位置和大小

    override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath)

        -> UICollectionViewLayoutAttributes! {

        //当前单元格布局属性

        var attribute =  UICollectionViewLayoutAttributes(forCellWithIndexPath:indexPath)

        

        //单元格外部空隙,简单起见,这些常量都在方法内部定义了,没有共享为类成员

        let itemSpacing = 2

        let lineSpacing = 5

        

        //单元格边长

        let largeCellSide:CGFloat = 200

        let smallCellSide:CGFloat = 100

        

        //内部间隙,左右5

        var insets = UIEdgeInsetsMake(2, 5, 2, 5)

        

        //当前行数,每行显示3个图片,1大2小

        var line:Int =  indexPath.item / 3

        //当前行的Y坐标

        var lineOriginY =  largeCellSide * CGFloat(line) + CGFloat(lineSpacing * line) + insets.top

        //右侧单元格X坐标,这里按左右对齐,所以中间空隙大

        var rightLargeX =  collectionView!.bounds.size.width - largeCellSide - insets.right

        var rightSmallX =  collectionView!.bounds.size.width - smallCellSide - insets.right

        

        // 每行2个图片,2行循环一次,一共6种位置

        if (indexPath.item % 6 == 0) {

            attribute.frame = CGRectMake(insets.left, lineOriginY, largeCellSide, largeCellSide)

        } else if (indexPath.item % 6 == 1) {

            attribute.frame = CGRectMake(rightSmallX, lineOriginY, smallCellSide, smallCellSide)

        } else if (indexPath.item % 6 == 2) {

            attribute.frame = CGRectMake(rightSmallX, lineOriginY + smallCellSide + insets.top,

                smallCellSide, smallCellSide)

        } else if (indexPath.item % 6 == 3) {

            attribute.frame = CGRectMake(insets.left, lineOriginY, smallCellSide, smallCellSide)

        } else if (indexPath.item % 6 == 4) {

            attribute.frame = CGRectMake(insets.left, lineOriginY + smallCellSide + insets.top,

                smallCellSide, smallCellSide)

        } else if (indexPath.item % 6 == 5) {

            attribute.frame = CGRectMake(rightLargeX, lineOriginY, largeCellSide, 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

import UIKit

class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource

{

    

    var collectionView:UICollectionView!

    //课程名称和图片,每一门课程用字典来表示

    let courses = [

        ["name":"Swift","pic":"swift.png"],

        ["name":"OC","pic":"oc.jpg"],

        ["name":"Java","pic":"java.png"],

        ["name":"PHP","pic":"php.jpeg"],

        ["name":"JS","pic":"js.jpeg"],

        ["name":"HTML","pic":"html.jpeg"],

        ["name":"Ruby","pic":"ruby.png"]

    ]

    

    override func viewDidLoad() {

        super.viewDidLoad()

        // Do any additional setup after loading the view, typically from a nib.

        

        let layout = CustomLayout()

        //let layout = UICollectionViewFlowLayout()

        self.collectionView = UICollectionView(

            frame: CGRectMake(0,20,view.bounds.size.width,view.bounds.height-20),

            collectionViewLayout:layout)

        self.collectionView.delegate = self

        self.collectionView.dataSource = self

        // 注册CollectionViewCell

        self.collectionView.registerClass(UICollectionViewCell.self,

            forCellWithReuseIdentifier: "ViewCell")

        //默认背景是黑色和label一致

        self.collectionView.backgroundColor = UIColor.whiteColor()

        

        self.view.addSubview(collectionView)

    }

    

    override func didReceiveMemoryWarning() {

        super.didReceiveMemoryWarning()

        // Dispose of any resources that can be recreated.

    }

    

    // CollectionView行数

    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

        return courses.count;

    }

    

    // 获取单元格

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath)

        -> UICollectionViewCell {

        // storyboard里设计的单元格

        let identify:String = "ViewCell"

        // 获取设计的单元格,不需要再动态添加界面元素

        let cell = self.collectionView.dequeueReusableCellWithReuseIdentifier(

            identify, forIndexPath: indexPath) as UICollectionViewCell

        // 添加图片

        let img = UIImageView(image: UIImage(named: courses[indexPath.item]["pic"]!))

        img.frame = cell.bounds

        // 图片上面显示课程名称,居中显示

        let lbl = UILabel(frame:CGRectMake(0,5,cell.bounds.size.width,20))

        lbl.textAlignment = NSTextAlignment.Center

        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)

    }

    */

}

时间: 2024-12-21 23:53:51

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

Swift - 使用网格(UICollectionView)进行流布局

一.网格UICollectionView最典型的例子是iBooks.其主要属性如下: 1,layout 该属性表示布局方式,有Flow.Custom两种布局方式.默认是Flow流式布局. 2,Accessories 是否显示页眉和页脚 3,各种尺寸属性 Cell Size:单元格尺寸 Header Size:页眉尺寸 Footer Size:页脚尺寸 Min Spacing:单元格之间间距 Section Insets:格分区上下左右空白区域大小. 二.流布局的简单样例 1,先创建一个ASimp

UICollectionView自定义布局教程

转载自:叶孤城 UICollectionView自定义布局Pintere UICollection这个东西是在iOS6被推出来的,所以如果你的app还在支持iOS5还是老实用TableView吧,要么牛逼的就用ScrollView手撸一个出来 它 最牛逼的地方就在于,Custom的Layout可以玩出无限可能.举个简单例子,早年有个非常出名的CoverFlow第三方库iCarousel(大 约在13年的时候我非常频繁的使用过它),效果非常炫,但问题是它是用scrollview撸出来的,虽然里面也

自定义布局RelativeLayout 画网格线

在Android中画线必须由一个载体,要么是一个控件,要么是一个布局,其实他们都是继承自View,通过自定义控件或布局的方式画线是最常见的.下面的小例子实现了在自定义RelativeLayout中画网格线 代码下载:http://download.csdn.net/detail/yxg190221/7589287 自定义控件代码: </pre><pre name="code" class="java">package layout.layou

ActionBar 自定义布局定义

Android系统中ActionBar默认的布局不美观且难于控制,通过为ActionBar自定义布局的方式可以灵活控制ActionBar. 效果: 工具/原料 android集成开发环境eclipse.ADT android sdk 3.0及以上 方法/步骤 自定义Activity主题和ActionBar样式 在新建的android工程的res/values/styles.xml添加自定义ActionBar样式的代码和自定义Activity主题的代 码,并在AndroidMainfest.xml

Notification的基本用法以及使用RemoteView实现自定义布局

Notification的作用 Notification是一种全局效果的通知,在系统的通知栏中显示.既然作为通知,其基本作用有: 显示接收到短消息.即时信息等 显示客户端的推送(广告.优惠.新闻等) 显示正在进行的事物(后台运行的程序,如音乐播放进度.下载进度) Notification的基本操作: Notification的基本操作主要有创建.更新和取消三种.一个Notification的必要属性有三项,如果不设置的话在运行时会抛出异常: 小图标,通过setSmallIcon方法设置 标题,通

Android开发学习之路--UI之自定义布局和控件

新的一年已经开始了,今天已经是初二了,两天没有学习了,还是要来继续学习下.一般手机的title都是actionbar,就像iphone一样可以后退,可以编辑.这里自定义布局就来实现下这个功能,首先准备下三张图片,一张用来当作背景,两张分别表示后退和编辑.新建工程UICostomViewsTest,然后自动创建工程后,新建title.xml,编写代码如下: <?xml version="1.0" encoding="utf-8"?> <LinearL

SharePoint 2013 设置自定义布局页

在SharePoint中,我们经常需要自定义登陆页面.错误页面.拒绝访问等:不知道大家如何操作,以前自己经常在原来页面改或者跳转,其实SharePoint为我们提供了PowerShell命令,来修改这些页面为我们自己的布局页. 具体设置,可以通过PowerShell命令的Identity参数来修改,可以修改的参数主要包括None.AccessDenied.Confirmation.Error.Login.RequestAccess.Signout 或WebDeleted. 设置自定义布局页的映射

Android:创建可穿戴应用 - 自定义布局

创建自定义布局(Creating Custom Layouts) 本文将介绍如何创建自定义通知以及使用可穿戴UI库来创建自定义布局你同时还需要了解可穿戴设计准则(Wear Design Principles)除了屏幕尺寸和瞬读能力(Glance ability)外,为可穿戴应用创建布局大体和普通手机一样. 创建自定义通知(Custom Notifications) 通常,你应该在手机应用上创建通知然后自动同步到可穿戴应用.这让你只需要构建通知一次,就可以呈现于多种设备(不只是可穿戴,最终还包括汽

任务八——响应式网格(栅格化)布局之问题总结

题目请看:任务八:响应式网格(栅格化)布局 一:要求是每个元素之间的间距均为20px,首先间距的实现有两种方法:    方法1. <div class="container"> <div class="col-sm-4 col-xs-6">4-6</div> . . . . . . </div> container设置box-sizing:border-box:width:100%:padding:10px:每个div