UICollectionView 01 - 基础布局篇

目录

项目下载地址: CollectionView-Note

UICollectionView 01 - 基础布局篇
UICollectionView 02 - 布局和代理篇
UICollectionView 03 - 自定义布局原理篇
UICollectionView 04 - 卡片布局
UICollectionView 05 - 可伸缩Header
UICollectionView 06 - 瀑布流布局
UICollectionView 07 - 标签布局

简介

我们日常开发中大部分的列表视图都可以使用 UITableView 完美的实现,它使用起来非常的简单高效。但是面对一些网格视图和瀑布流,甚至交叉布局,圆形等各种创新布局,UITableView 显得束手无策,这时候我们需要祭出 UICollectionView ,它真的是一个非常强大的控件, 既可以实现简单的列表网格等布局,也可以完成各种复杂的自定义布局,以及动画特效。是一个非常值得花时间去学习的控件。所以我打算对此做一个总结,从基础的FlowLayout 到各种 自定义布局。全面的学习这个控件。

第一篇主要了解这个控件,以及使用他来做一个基本的网格布局。

UICollectionView 的基本使用非常简单,和UITableView类似。但是它将展示和布局分开处理。UICollectionView 负责展示数据,UICollectionViewLayout 负责处理布局信息,系统默认帮我们实现了一种流式布局 UICollectionViewFlowLayout ,可以满足大部分场景。下面展示简单的例子。

示例

我们在 Storyboard 中拖一个 UICollectionView 然后自定义一个BasicsCell , CollectionView 默认是使用 UICollectionViewFlowLayout 布局的。所以看起来是这样。

storyboard

给Cell加上reuseIdentifier

reuseid

我们的cell里面什么只有一行复用id ,这是一个简单的demo,并不准备加任何布局和逻辑,直接用色块表示单元格

class BasicsCell: UICollectionViewCell {
  static let reuseID = "basicsCell"
}

我们的 ViewController 顶部定义collectionView以及计算属性 flowLayout

@IBOutlet weak var collectionView: UICollectionView!
  
var flowLayout: UICollectionViewFlowLayout? {
    return collectionView.collectionViewLayout as? UICollectionViewFlowLayout
}

由于我们是使用色块,这里写一个便捷的方法生成随机颜色。和颜色数组。

extension UIColor {
  static func randomColor() -> UIColor{
    let red = CGFloat(arc4random_uniform(255) + 1)
    let green = CGFloat(arc4random_uniform(255) + 1)
    let blue = CGFloat(arc4random_uniform(255) + 1)
    return UIColor(red: red/255, green: green/255, blue: blue/255, alpha: 1)
  }
}

class DataManager {
  static let shared = DataManager()
  func generalColors(_ count: Int) -> [UIColor] {
    var colors = [UIColor]()
    for _ in 0..<count{
      colors.append(UIColor.randomColor())
    }
    return colors
  } 
}

在Controller中定义颜色数组,为了体现分组,这里定义二维数组。在viewDidLoad中对数组进行初始化。

var colors: [[UIColor]] = []

// viewDidLoad 中初始化code
colors.append(DataManager.shared.generalColors(8))
colors.append(DataManager.shared.generalColors(5))
colors.append(DataManager.shared.generalColors(7))

UICollectionViewFlowLayout 为我们提供了一些便捷的方式来指定单元格的大小间距等属性(如果自定义布局,这些都要我们自己计算,之后的文章会写)。UICollectionView是继承自UIScrollView的,所以UIScrollView 的所有方法和属性他都可以使用,我们这里做一个间距和边距都是1的正方形色块。所以对UICollectionView 左右加了内边距。

viewDidLoad中加入如下代码。

// 加内边距
collectionView.contentInset = UIEdgeInsets(top: 0, left: 1, bottom: 0, right: 1)
    
let itemWidth = (view.bounds.width - 4)/3 
flowLayout?.itemSize = CGSize(width: itemWidth, height: itemWidth)
// 最小行间距
flowLayout?.minimumLineSpacing = 1
// 最小元素之间的间距
flowLayout?.minimumInteritemSpacing = 1
flowLayout?.headerReferenceSize = CGSize(width: view.bounds.width, height: 50)
flowLayout?.footerReferenceSize = CGSize(width: view.bounds.width, height: 30)

我们这里一行放三个元素,这里使用垂直滚动,如果你想水平滚动只需要加上 flowLayout?.scrollDirection = .horizontal

这里的间距为啥都是最小间距? 因为他不是固定间距,比如水平宽度是400,每个元素width是120,这样水平放三个还剩下40,如果你设置最小间距是1,这里会自动拉大间距,将间距拉大为 40 / (itemcount - 1) 。

其实这些布局也可以通过一个代理设置,这样可以对每个item进行设置,为了使本篇简单化,后面再补充。

添加数据源。因为cell是在 Storyboard 中设置的,不需要再register , 如果是Xib或者纯代码,需要调用 collectionView.register(_ , forCellWithReuseIdentifier: )

collectionView.dataSource = self

// MARK: - UICollectionViewDataSource

extension BasicsViewController: UICollectionViewDataSource {
  
  func numberOfSections(in collectionView: UICollectionView) -> Int {
    return colors.count
  }
  
  func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return colors[section].count
  }
  
  func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: BasicsCell.reuseID, for: indexPath) as! BasicsCell
    cell.backgroundColor = colors[indexPath.section][indexPath.row]
    return cell
  }
}

一个网格布局ok了,非常简单,代理方法几乎和UITableView一样。

000

白色并不是我们设置的 ,我们其实是有分组的,但是这里并没有明显感受到,所以我们需要给它加上Header和Footer。

UICollectionView中的Header和Footer都是使用Supplementary Views 来实现的。 只需要自定义继承自UICollectionReusableView 的view即可。

这里我们使用Xib来做,纯代码也一样,就一个Label标识一下

class BasicsHeaderView: UICollectionReusableView {
  
  static let reuseID = "BasicsHeaderView"
  
  @IBOutlet weak var titleLabel: UILabel!
  override func awakeFromNib() {
    super.awakeFromNib()
    titleLabel.textColor = UIColor.black
    titleLabel.font = UIFont.boldSystemFont(ofSize: 18)
  } 
}
class BasicsFooterView: UICollectionReusableView {
  
  static let reuseID = "BasicsFooterView"
  @IBOutlet weak var titleLabel: UILabel!
  
  override func awakeFromNib() {
    super.awakeFromNib()
    titleLabel.textColor = UIColor.gray
    titleLabel.font = UIFont.systemFont(ofSize: 14)
  }
}

布局信息依然是由flowLayout 来设置,在viewDidLoad加上如下代码

collectionView.register(UINib(nibName: "BasicsHeaderView", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: BasicsHeaderView.reuseID)
collectionView.register(UINib(nibName: "BasicsFooterView", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: BasicsFooterView.reuseID)

flowLayout?.headerReferenceSize = CGSize(width: view.bounds.width, height: 50)
flowLayout?.footerReferenceSize = CGSize(width: view.bounds.width, height: 30)

cellForItemAt 的代理下加上如下方法

func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
    switch kind {
    case UICollectionView.elementKindSectionHeader:
      let view = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: BasicsHeaderView.reuseID, for: indexPath) as! BasicsHeaderView
      view.titleLabel.text = "HEADER -- \(indexPath.section)"
      return view
    case UICollectionView.elementKindSectionFooter:
      let view = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: BasicsFooterView.reuseID, for: indexPath) as! BasicsFooterView
      view.titleLabel.text = "FOOTER -- \(indexPath.section)"
      return view
    default:
      fatalError("No such kind")
    }
}

我们只处理我们注册过的类型。

ok, 一个网格布局就完成了,非常easy。看下效果。

000

如果我们需要实现粘性的Header或者粘性的Footer,以前的话需要我们自定义Layout,从iOS 9 以后系统自动支持了。flowLayout的两个属性。

flowLayout?.sectionHeadersPinToVisibleBounds = true
flowLayout?.sectionFootersPinToVisibleBounds = true

效果:

000

本篇只介绍了一些基础的用法,后面的文章会介绍一些高级点的用法。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容

  • 1、通过CocoaPods安装项目名称项目信息 AFNetworking网络请求组件 FMDB本地数据库组件 SD...
    X先生_未知数的X阅读 15,960评论 3 119
  • 遇到一个生活艰辛但聪明努力的大妈,遇到一个日子幸福但傻甜淡然的大妈,彼此倾诉,彼此羡慕,前者说后者有福,后者称前者...
    希耳阅读 173评论 0 0
  • **如果你是老板,你会重用什么样的员工? ** 01 面试的故事 今天是我去面试的公司的第二天,但非常特别的是我至...
    高锋爱学习2021读书100本阅读 330评论 4 2
  • 早上七点半起床,去了博物馆。我们上了一号展厅,二号展厅,三号展厅,我非常累,然后我们做的游戏。做完了之后我们去了《...
    乔文浩阅读 227评论 1 1
  • 【连载】元无(七)【八】 夜幕四合,江叙辗转反侧,难以入睡。 “老妹儿啊,别翻了,我都被弄醒了。”江旭不满地嘟囔出...
    有三没九阅读 135评论 1 1