[译] NSCollectionView 入门教程

本文翻译自 raywenderlich.comNSCollectionView Tutorial,已咨询对方网站,可至多翻译 10 篇文章。
但愿各位有英语阅读能力的话,仍是 先打赏 而后去阅读英文原吧,毕竟不管是 Xcode,抑或是官方的文档,仍是各类最前沿的资讯都只有英文版本。
综上,此翻译版本仅供参考,谢绝转载macos

相关连接:
NSCollectionView 进阶教程:原文 / 译文(翻译中)
零基础 macOS 应用开发教程(一):原文 / 译文swift

更新信息: 此 NSCollectionView 教程已由 Gabriel Miro 更新至 Xcode 8 和 Swift 3.segmentfault

Collection View 是显示一系列相同类型数据的最佳方式。Mac 中自带的 Finder 和 Photos 就是使用了它:经过一个 Collection View 来展现全部的文件和图片。设计模式

NSCollectionView 最先在 OS X 10.5 被推出,它能够很是方便地布局一组具备相同大小的 item,并把它们展现在一个能够滑动的 Scroll View 中。api

在 OS X 10.11 El Capitan 中,参照 iOS 上的 UICollectionViewNSCollectionView 被全面进行了升级。数组

macOS 10.12 Sierra 则给予了它「收起分区」(就像 Finder 里那样)和「固定标题」两项新功能,使得它和 iOS 的差距进一步减少了。浏览器

在这个 NSCollectionView 的入门教程中,你将会创造一个叫 SlideMagic 的 app,它是一个只属于你的网格状的图片浏览 app。app

这个教程假定你已经基本了解过了 macOS app 的开发,若是你还未曾了解过,raywenderlich.com 上提供了不少很棒的 macOS 开发教程,你能够先去看看那些。框架

固然还有我本身翻的《零基础 macOS 应用开发教程》系列ide

准备开始

你将会编写的 SlidesMagic app 是一个简单的图片浏览器,它很酷,可是,可别由于它太酷了而一不当心在把玩的时候把本身 Mac 上的照片删了哦?~

这个 app 会从获取一个文件夹里的全部图片,而后用一个极其优雅的 Collection View 来把它们显示出来。完成了的 app 长这样:

下载这个项目的起步代码,编译并运行:

此时,这个 app 看起来只是一个空荡荡的窗口,但这些起步代码包含了一些「隐藏功能」,这是后面使它成为一个图片浏览器的基础。

SlidesMagic 启动的时候,会自动加载系统中 Desktop Pictures 目录下的全部图片,在 Xcode 的控制台输出中,咱们能够看到这些文件的名字。

控制台中输出的列表代表,起步代码中 Model 的加载逻辑代码已经能够正常工做了,你能够在这个 app 的 FileOpen Another Folder… 菜单中打开另外一个目录。

起步代码

起步代码提供了一些与 Collection Views 无直接关联的代码。

Model

  • ImageFile.swift: 用于描述一个图片文件
  • ImageDirectoryLoader.swift: 用来把图片从硬盘中加载出来的 Helper 类

Controller

这个 app 拥有两个主要的 Controller:

  • WindowController.swift

    • windowDidLoad():在左半边的屏幕上设置主窗口的大小;
    • openAnotherFolder(_:):提供一个标准的「打开」对话框来供用户选择文件夹;
  • ViewController.swift

    • viewDidLoad() 打开 Desktop Pictures 目录做为默认目录。

Collection View 幕后探秘

NSCollectionView 是今天的主角,它将会在几个关键的组成部分的帮助下,显示许多 item。

布局

NSCollectionViewLayout:明确了 Collection View 的布局方式,它是一个抽象的类,全部用来表示 CollectionView 布局的实类都继承自它。

NSCollectionViewFlowLayout:提供了一个灵活的网格状的布局。对于绝大多数 app,这种布局方式都适用。

NSCollectionViewGridLayout:为了兼容 OS X 10.11 和之前的版本所保留的布局方式,对于新建立的 app 不推荐使用。

Section 和 IndexPath:前者容许你把 item 分红若干个 section(分区),每一个 section 包含了一组有序的 item。每一个 item 都和一个索引相关联,这个索引是一个由一对整数(section,item)构成的 IndexPath 实例。默认状况下,当你不须要给 item 分区时,这个 Collection View 仍然会拥有一个 section。

Collection View Item

就像其余许多 Cocoa 框架同样,Collection View 中的 item 也遵照着 MVC 设计模式。

Model 和 View:这个 item 的内容来自 Model 的数据对象。每一个单独的对象都经过在 Collection View 中建立本身的 View 来把本身显示出来。这些 View 的结构由一个单独的 nib 文件(文件扩展名是 .xib)来定义。

Controller:上面提到的 nib 文件是一个由 NSCollectionViewItem 管理的 NSViewController 的子类。它负责与 Model 对象进行通讯并控制 Collection View 的显示。一般状况下,你会编写一个 NSCollectionViewItem 的子类。当你须要不一样类型的 item 的时候,你须要为每一个分支定义一个不一样的子类,并建立一个 nib。

额外的 View

要在 Collection View 中显示不一样于普通 item 额外的信息,你须要额外的 item。

最直观的例子就是分区的标题和脚注。

Collection View 的数据源和代理(Data Source and Delegates)

  • NSCollectionViewDataSource:用 item 和额外的 item 来填充 Collection View。
  • NSCollectionViewDelegate:处理拖放相关的事件,以及选中状态和高亮。
  • NSCollectionViewDelegateFlowLayout:容许你自定义你的网格视图。

注意:填充一个 Collection View 的方法有二:数据源和 Cocoa 绑定。这个教程将会使用数据源。

建立 Collection View

打开 Main.storyboard。前往控件库,向 View Controller Scene 中拖动一个 Collection View

注意:你或许注意到了,Interface Builder 为咱们添加了三个 View,而不是一个。这是由于 Collection View 是嵌入在一个 Scroll View 中的,然后者又自带一个 Clip View 子视图。这仨视图各不相同,所以当本教程须要你选择 Collection View 的时候,切记不要错选了 Scroll ViewClip View

调整 Bordered Scroll View 的大小,使它填满它的父视图的全部空间。而后选择 Xcode 菜单栏上的 EditorResolve Auto Layout IssuesAdd Missing Constraints 来添加 Auto Layout 约束条件。

你须要在 ViewController 中添加一个 Outlet 来访问界面上的 Collection View。打开 ViewController.swift,在 ViewController 类的定义中添加如下代码:

@IBOutlet weak var collectionView: NSCollectionView!

打开 Main.storyboard,并选择 View Controller Scene 中的 View Controller

打开链接检查器,在 Outlets 部分中找到 collectionView拖动它旁边的小圆圈到画布中的 Collection View 上。

调整 Collection View 的布局

你如今有两种选择:在 Interface Builder 中设置好主要的布局属性,或者在代码中手动编写。

在 SlidesMagic 这个项目中,咱们选择手动编写代码。

打开 ViewController.swift,把这些方法添加到 ViewController 中:

fileprivate func configureCollectionView() {
    // 1
    let flowLayout = NSCollectionViewFlowLayout()
    flowLayout.itemSize = NSSize(width: 160.0, height: 140.0)
    flowLayout.sectionInset = EdgeInsets(top: 10.0, left: 20.0, bottom: 10.0, right: 20.0)
    flowLayout.minimumInteritemSpacing = 20.0
    flowLayout.minimumLineSpacing = 20.0
    collectionView.collectionViewLayout = flowLayout
    // 2
    view.wantsLayer = true
    // 3
    collectionView.layer?.backgroundColor = NSColor.black.cgColor
  }

这些代码的做用是:

  1. 建立一个 NSCollectionViewFlowLayout,配置它的基本属性,并设置 NSCollectionViewcollectionViewLayout
  2. 通常状况下,NSCollectionView 是基于层的,因此你须要把它的父视图的 wantsLayer 设置为 true
  3. 把 Collection View 的背景颜色设置为黑色。

你须要在试图加载完成时调用这个方法,因此在 viewDidLoad() 方法的最后插入:

configureCollectionView()

编译并运行:

此时,你的 Collection View 已经拥有了一个黑色的背景,并配置好了布局。

建立一个 Collection View Item

先在你须要建立一个 NSCollectionViewItem 的子类并把 Model 里的数据们显示出来。

点击 Xcode 菜单栏上的 FileNewFile…,选择 macOSSourceCocoa Class 并点击 Next

Class 填写 CollectionViewItemSubclass of 填写 NSCollectionViewItem,并勾选 Also create XIB for user interface

点击 Next,而后在对话框中的 Group 中选择 Controllers,并点击 Create

打开 CollectionViewItem.swift,把里边的内容所有替换为:

import Cocoa
class CollectionViewItem: NSCollectionViewItem {

  // 1
  var imageFile: ImageFile? {
    didSet {
      guard isViewLoaded else { return }
      if let imageFile = imageFile {
        imageView?.image = imageFile.thumbnail
        textField?.stringValue = imageFile.fileName
      } else {
        imageView?.image = nil
        textField?.stringValue = ""
      }
    }
  }
  
  // 2
  override func viewDidLoad() {
    super.viewDidLoad()
    view.wantsLayer = true
    view.layer?.backgroundColor = NSColor.lightGray.cgColor
  }
}

这些代码的功能是:

  1. 定义了 imageFile 属性,用来访问须要展现的 Model 对象。当你为 imageFile 属性赋值时,它的 didSet 属性观察器会设置这个 item 的 Image 和 Label;
  2. 改变此 item 的 View 的背景颜色。

向 View 中添加 Control

你在 CollectionViewItem.swift 时勾选了「Also create a XIB(同时建立一个 XIB)」,为了更清楚地整理文件,把 CollectionViewItem.xib 拖动到 Main.storyboard 下方的 Resources 分组中。

Nib 文件中的 View 就是每一个 item 所显示出来的根视图,你须要添加一个 Image View 来显示图片,以及一个 Label 来显示文件名。

打开 CollectionViewItem.xib,添加一个 NSImageView

  1. 控件库中拖动一个 Image View 到画布上的 View 中;
  2. Auto Layout 工具栏中点击 Pin 按钮来设置它的约束条件;
  3. 设置它的 topleadingtrailing 约束为 0,bottom 为 30。点击 Update Frames: Items of New Constraints 而后点击 Add 4 Constraints

再来添加一个 Label:

  1. 控件库中拖动一个 Label 到画布上的 Image View 的下方;
  2. Auto Layout 工具栏中点击 Pin 按钮,设置它的 topbottomleadingtrailing 约束都为 0。点击 Update Frames: Items of New Constraints 而后点击 Add 4 Constraints

选中 Label,在属性检查器中设置以下属性:

  1. 设置 Alignmentcenter
  2. 设置 Text Colorwhite
  3. 设置 Line BreakTruncate Tail

向 Nib 中添加 CollectionViewItem 并链接 Outlets

尽管 Nib 文件的 File’s Owner 如今是 CollectionViewItem,它还只是一个占位符。当 Nib 文件被实例化时,它还会须要一个「真正的」NSCollectionViewItem 的实例。

控件库中拖动一个 Collection View Item文档大纲中,选中它,在 身份检查器中把它的 Class 设置为 CollectionViewItem

在 xib 中,你须要把 View 的层次关系链接到 CollectionViewItem 的 Outlet 中,在 CollectionViewItem.xib 中:

  1. 选中 Collection View Item 并前往 Connections Inspector
  2. view 的 outlet 拖动到文档大纲中的 View 上;
  3. 用一样的方法,把 imageViewtextField 的 outlet 链接到文档大纲中的 Image ViewLabel 中。

填充 Collection View

你须要实现 Collection View 的数据源协议,说人话就是:

  1. Collection 中有几个分区?
  2. 每一个分区分别有多少个 item?
  3. 某个索引路径(Index Path)对应的是哪一个 Item?

打开 ViewController.swift 并在文件的末尾添加这些扩展代码:

extension ViewController : NSCollectionViewDataSource {
  
  // 1
  func numberOfSections(in collectionView: NSCollectionView) -> Int {
    return imageDirectoryLoader.numberOfSections
  }
  
  // 2
  func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
    return imageDirectoryLoader.numberOfItemsInSection(section)
  }
  
  // 3
  func collectionView(_ itemForRepresentedObjectAtcollectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
    
    // 4
    let item = collectionView.makeItem(withIdentifier: "CollectionViewItem", for: indexPath)
    guard let collectionViewItem = item as? CollectionViewItem else {return item}
    
    // 5
    let imageFile = imageDirectoryLoader.imageFileForIndexPath(indexPath)
    collectionViewItem.imageFile = imageFile
    return item
  }
  
}
  1. 若是你的 app 不须要用到分区,那么你能够删除这个方法,由于一个分区就够了;
  2. 这是两个 NSCollectionViewDataSource 协议必须实现的方法之一,在这个方法中你须要返回某个分区容纳的 item 的数量;
  3. 另外一个必须实现的方法,这个方法会针对某个 indexPath 返回一个 item;
  4. 这个方法会从 nib 中实例化一个 item,这个 item 的名字是 identifier 参数,它会根据所须要的 item 的类型来试图重复使用一个 item,若是没有 item 可供重复使用,它会新建一个 item;
  5. 根据 IndexPath 获取 Model 对象,设置 Image 和 Label 的内容。

注意: Collection View 具备一项能力:循环使用已经生成了的 Item,以此来减轻数据源过大时的内存压力。从界面上移出去的 item 就是被重复使用的 item。

设置数据源

接下来我发须要定义数据源:

打开 Main.storyboard,选中 Collection View。

打开链接检查器,在 Outlets 部分中找到 dataSource拖动它旁边的小圆圈到文档大纲里的 View Controller 上。

编译并运行,你的 Collection View 如今应该能显示 Desktop Pictures 目录中的图片了:

哈哈哈,折腾了半天都是值得的✌️~

故障排除

若是你还看不见任何图片,你可能遗漏了一些小细节:

  1. 你在链接检查器中正确地设置了全部的链接吗?
  2. 你设置 dataSource 的 Outlet 了吗?
  3. 你在身份检查器中应用正确的自定义类了吗?
  4. 你添加顶层的 NSCollectionViewItem,并把它的类设置为 CollectionViewItem 了吗?
  5. makeItemWithIdentifier 中的 identifier 参数的值和 nib 的名字同样吗?

Model 发生改变时从新加载 Item 们

要显示另外一个目录中的图片,你能够在 app 的菜单栏上点击 FileOpen Another Folder…,而后选择一个存有 JPGPNG 格式的图片的目录。

但时此时窗口中的东西彷佛什么变化都没有,仍是显示着 Desktop Pictures 目录中的图片。尽管 Xcode 里的控制台中已经打印出了新目录里的文件名称。

你须要调用 Collection View 的 reloadData() 方法来刷新它的 item。

打开 ViewController.swift 并把这些代码添加到 loadDataForNewFolderWithUrl(_:) 方法中:

collectionView.reloadData()

编译并运行,如今你应该能看到窗口中已经能显示正确的照片了。

添加分区

SlidesMagic app 如今已经能够作一些很神奇的事儿了,但咱们要更进一步 —— 为 Collection View 加入分区。

首先,你须要在主视图的最底部加入一个复选框,来容许你切换是否启用分组。

打开 Main.storyboard,而后在文档大纲中选中 Scroll View 的约束条件,在尺寸检查器中吧它的 Constant 修改成 30.

这会把 Collection View 抬高一些些,腾出地方来放置复选框。

如今,从控件库中拖动一个 Check Box Button到画布中 Collection View 下方的空间里,选中它,在属性检查器中把它的 Title 设置为 Show Sections,而后把 State 设置为 Off

接下来,点击 Pin 按钮更新它的 Auto Layout 约束条件:Top 设置为 8,Leading 设置为 20。而后点击 Update Frames: Items of New ConstraintsAdd 2 Constraints

编译并运行,如今 app 的底部看起来应该是这样的:

当你点击这个复选框的时候,你的 app 须要改变 Collection View 的外观。

打开 ViewController.swiftViewController 类的最后添加这些代码:

@IBAction func showHideSections(sender: NSButton) {
    let show = sender.state
    // 1
    imageDirectoryLoader.singleSectionMode = (show == NSOffState)
    // 2
    imageDirectoryLoader.setupDataForUrls(nil)
    // 3
    collectionView.reloadData()
  }

这些代码会:

  1. 根据复选框的状态切换单一分组/多个分组;
  2. 根据当前选择的模式来调整 Model,此时传递的 nil 参数表示跳过图像加载 —— 毕竟图片仍是那些图片,只是布局发生了改变;
  3. Model 发生了改变,因此须要刷新数据。

若是你好奇图片是按照是按照什么规则进行分组的,在 ImageDirectoryLoader 中找到 sectionLengthArray,这个数组里的数字设置了各个分组的里最多能够容纳多少个 item。这个数组是随机生成的,只是用来用做演示。

如今,打开 Main.storyboard。在文档大纲按住 Control⌃ 键的同时Show Sections 拖动到 View Controller 上。在弹出的黑色窗口中点击 showHideSections:。你能够在链接检查器里查看你是否链接成功了。

编译并运行,勾选 Show Sections 来查看布局的变化。

为了更好地区分各个分区,打开 ViewController.swift,编辑 configureCollectionView() 方法里的 sectionInset 属性。

把这一行:

flowLayout.sectionInset = EdgeInsets(top: 10.0, left: 20.0, bottom: 10.0, right: 20.0)

替换成这个:

flowLayout.sectionInset = EdgeInsets(top: 30.0, left: 20.0, bottom: 30.0, right: 20.0)

编译并运行,勾选 Show Sections,能够看到各个分区之间已经有了分隔。

添加分区标题

另外一种区分各个分区边界的方法是为每一个分区添加一个标题或脚注。

你须要一个自定义的 NSView 类,并实现相应的数据源方法来为 Collection View 添加一个标题

要建立一个标题,在 Xcode 的菜单栏点击 FileNewFile…。选择 macOSUser InterfaceView,并点击 Next

文件名输入 HeaderView.xibGroup 选择 Resources

点击 Create

打开 HeaderView.xib 并选中 Custom View。在尺寸检查器中把 Width 设置为 500,Height 设置为 40。

Object Library 拖动一个 Label 到 Custom View 的左半边。打开属性检查器,设置它的 TitleSection Number,设置 Font Size16

再拖动一个 Label 到 Custom View 的右半边。设置它的 TitleImage Count,设置 AlignmentRight

选中 Section Number Label,点击 Pin 按钮,设置它的 Top 约束为 12,Leading 约束为 20。点击 Update Frames: Items of New ConstraintsAdd 2 Constraints

接下来,设置 Image Count Label 的 Top 约束为 11,Trailing 约束为 20,别忘了点击 Update Frames: Items of New ConstraintsAdd 2 Constraints

如今咱们的标题应该看起来像这样:

如今咱们的标题 UI 已经准备好了,咱们还须要为它建立一个子类。

在 Xcode 的菜单栏点击 FileNewFile…。选择 macOSSourceCocoa Class,并点击 Next。把它的类名设置为 HeaderView,并让它继承自 NSView,点击 Next,并在 Group 中选择 Views。点击 Create

打开 HeaderView.swift 而后把里边的全部内容替换为:

// 1
@IBOutlet weak var sectionTitle: NSTextField!
@IBOutlet weak var imageCount: NSTextField!

// 2
override func draw(_ dirtyRect: NSRect) {
  super.draw(dirtyRect)
  NSColor(calibratedWhite: 0.8 , alpha: 0.8).set()
  NSRectFillUsingOperation(dirtyRect, NSCompositingOperation.sourceOver)
}

这里的代码作了这些事儿:

  1. 设置你须要用来链接 nib 元素的 outlet;
  2. 绘制一个灰色的背景。

要把 outlet 链接至 Label,打开 HeaderView.xib 并选中 Custom View。在 Identity Inspector 中把 Class 设置为 HeaderView

文档大纲视图中,按住 Control⌃ 键的同时点击 Header View。在弹出的黑色窗口中,拖动 imageCountImages Count 上来链接 outlet。

对第二个 Label 进行一样的操做,拖动 sectionTitle 到画布中的 Section Number Label 上。

实现数据源和代理方法

你的标题已经彻底准备好上战场了,你须要实现 collectionView(_:viewForSupplementaryElementOfKind:at:),把这个标题视图传递给 Collection View:

打开 ViewController.swift 并把这些方法添加到 NSCollectionViewDataSource extension 中:

func collectionView(_ collectionView: NSCollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> NSView {
  // 1
  let view = collectionView.makeSupplementaryView(ofKind: NSCollectionElementKindSectionHeader, withIdentifier: "HeaderView", for: indexPath) as! HeaderView
  // 2
  view.sectionTitle.stringValue = "Section \(indexPath.section)"
  let numberOfItemsInSection = imageDirectoryLoader.numberOfItemsInSection(indexPath.section)
  view.imageCount.stringValue = "\(numberOfItemsInSection) image files"
  return view
}

Collection View 会在它须要数据源的时候调用这个方法,并为每一个分区设置标题。这个方法作了这些:

  1. 调用 makeSupplementaryViewOfKind(_:withIdentifier:for:) 来从 nib 文件实例化一个名字是 withIdentifierHeaderView 对象;
  2. 设置各个 Label 的值。

ViewController.swift 的最后,添加这个 NSCollectionViewDelegateFlowLayout 扩展:

extension ViewController : NSCollectionViewDelegateFlowLayout {
  func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> NSSize {
    return imageDirectoryLoader.singleSectionMode ? NSZeroSize : NSSize(width: 1000, height: 40)
  }
}

上面这个方法实际上是不是必须的,但当你须要设置标题的时候就必须写上了,由于 Flow Layout(流式布局)的代理须要你提供各个分区的标题的大小。

若是没有实现这个方法,你将看不到标题,由于它们的尺寸都是 0。此外,它还会忽略你指定的宽度,而是把标题的宽度设置为 Collection View 的宽度。

在这个例子中,当 Collection View 只有一个分区的时候,这个方法返回的标题尺寸是 0,不然他会返回 40.

对于使用了 NSCollectionViewDelegateFlowLayout 的 Collection View,你须要把 ViewController 链接到 NSCollectionViewdelegate

打开 Main.storyboard 并选中 Collection View。打开链接检查器,在 Outlets 部分中找到 delegate拖动他旁边的小圆点到文档大纲中的 View Controller 上。

编译并运行,勾选 Show Sections,能够看到一个个标题把分区区分开来:

固定标题

macOS 10.12 中的 NSCollectionViewFlowLayout 新加入了两个属性:sectionHeadersPinToVisibleBoundssectionFootersPinToVisibleBounds

sectionHeadersPinToVisibleBounds 设置为 true,最上端的分区的标题将会固定在顶端,而不会移出界面之外。当你继续向下滚动时,下一个标题会把它顶走。这种效果通常被称为「sticky headers(固定标题)」或「floating headers(浮动标题)」。

sectionFootersPinToVisibleBounds 设置为 true 则会把脚注固定在底部。

打开 ViewController.swift,在 configureCollectionView() 方法的底部加入这个方法:

flowLayout.sectionHeadersPinToVisibleBounds = true

编译并运行,勾选 Show Sections 并向下滚动一些,你能够看到第一个区域已经有一些图片被移出屏幕了,但标题仍是固定在顶部:

注意:若是你的 app 须要支持 OS X 10.11 或更老的版本,你须要经过重写 layoutAttributesForElements(in:) 方法来「手动」实现固定标题。你能够查看[Advanced Collection Views in OS X Tutorial]这篇教程(我正在翻译~)。

Collection View 的选择功能

为了显示一个 item 的被选中状态,你须要设置一个白色的边框,没有被选中的项目将不会显示这个边框。

首先,你须要让咱们的 Collection View 支持选中。打开 Main.storyboard,选中 Collection View 并在属性检查器里,勾选 Selectable

勾选 Selectable 开启了选择功能,意味着你能够经过点击一个 item 来选中它。若是你点击另外一个 item,将会取消选择以前的那个 item 并选中新的 item。

当你选中一个 item:

  1. 它的 IndexPath 会被添加到 NSCollectionViewselectionIndexPaths 属性;
  2. 它的 isSelected 属性会被设置为 true

打开 CollectionViewItem.swift。在 viewDidLoad() 方法的最后追加:

// 1 
view.layer?.borderColor = NSColor.white.cgColor 
// 2 
view.layer?.borderWidth = 0.0

这段代码:

  1. 设置了一个白色的边框;
  2. borderWidth 设置为 0.0 来确保边框不可见 —— 也就是没被选中。

要在每次 isSelected 被设置时改变 borderWidth,咱们须要把这些代码添加到 CollectionViewItem 类中:

override var isSelected: Bool {
    didSet {
      view.layer?.borderWidth = isSelected ? 5.0 : 0.0
    }
  }

每次 isSelected 发生了改变,didSet 将会根据新的值来设置边框的宽度。

编译并运行。点击一个项目来选中它,你将会看见它周围出现了边框。哈哈哈,神奇✨!

下一步该作些啥?

点击这里下载最终完成了的 SlideMagic

在这个 NSCollectionView 入门教程中,你了解了如何建立你的第一个 Collection View,了解了错综复杂的数据源 API 和如何处理分区。至此你已经学到了不少,但其实这仅仅是个开始,Collection View 还有不少功能等待你去发掘。这里有不少值得去探索的东西:

  • 经过 Cocoa 的数据绑定构建「免数据源」的 Collection View
  • 不一样类型的 Item
  • 追加和移除 Item
  • 自定义布局
  • 拖放手势(Drag and drop)
  • 动画
  • 修改 NSCollectionViewFlowLayout
  • 收起某个分区(macOS 10.12 Sierra 的新功能)

你能够在咱们的《NSCollectionView 进阶教程》(原文|译文)中了解更多。

相关文章
相关标签/搜索