IGListKit框架详细解析(三) —— 基于IGListKit框架的更好的UICollectionViews简单示例(二)

版本记录

版本号 时间
V1.0 2019.01.19 星期六

前言

IGListKit这个框架可能很多人没有听过,它其实就是一个数据驱动的UICollectionView框架,用于构建快速灵活的列表。它由Instagram开发,接下来这几篇我们就一起看一下这个框架。感兴趣的看上面几篇。
1. IGListKit框架详细解析(一) —— 基本概览(一)
2. IGListKit框架详细解析(二) —— 基于IGListKit框架的更好的UICollectionViews简单示例(一)

Adding Messages

JPL工程师非常高兴您能够快速完成重构,但他们确实需要与被困的宇航员建立联系。 他们已经要求您尽快集成消息模块ASAP

在添加任何视图之前,首先需要数据。

打开FeedViewController.swift并在FeedViewController的顶部添加一个新属性:

let pathfinder = Pathfinder()

PathFinder()充当消息系统,代表宇航员在火星上挖出的物理Pathfinder漫游者。

ListAdapterDataSource扩展中找到objects(for:)并修改内容以匹配以下内容:

var items: [ListDiffable] = pathfinder.messages
items += loader.entries as [ListDiffable]
return items

您可能还记得,此方法为ListAdapter提供了数据源对象。 此处的修改将pathfinder.messages添加到items以为新的控制器提供消息。

注意:您必须强制转换entries数组以使Swift编译器可以使用。 对象已经遵循IGListDiffable

右键单击SectionControllers组以创建名为MessageSectionController的新ListSectionController子类。 将IGListKitimport添加到顶部:

import IGListKit

编译器可以使用,你现在可以保持其余的不变。

返回FeedViewController.swift并更新ListAdapterDataSource扩展中的listAdapter(_:sectionControllerFor :),使其显示如下:

if object is Message {
  return MessageSectionController()
} else {
  return JournalSectionController()
}

如果数据对象的类型为Message,则现在返回新的message section controller

JPL团队希望您设置具有以下要求的MessageSectionController

  • 收到消息Message
  • 有一个15点的bottom inset
  • 返回使用MessageCell.cellSize(width:text :)方法调整大小的单个单元格。
  • 使用Message对象的textuser.name值对MessageCell进行出队和配置以填充标签。
  • 在所有大写中显示Message对象的user.name值。

试一试! 如果您需要帮助,该团队会在下面起草一个解决方案。

import IGListKit

class MessageSectionController: ListSectionController {
  var message: Message!
  
  override init() {
    super.init()
    inset = UIEdgeInsets(top: 0, left: 0, bottom: 15, right: 0)
  }
}

// MARK: - Data Provider
extension MessageSectionController {
  override func numberOfItems() -> Int {
    return 1
  }
  
  override func sizeForItem(at index: Int) -> CGSize {
    guard let context = collectionContext else {
      return .zero
    }
    return MessageCell
      .cellSize(width: context.containerSize.width, text: message.text)
  }
  
  override func cellForItem(at index: Int) -> UICollectionViewCell {
    let cell = collectionContext?
      .dequeueReusableCell(of: MessageCell.self, for: self, at: index) 
        as! MessageCell
    cell.messageLabel.text = message.text
    cell.titleLabel.text = message.user.name.uppercased()
    return cell
  }
  
  override func didUpdate(to object: Any) {
    message = object as? Message
  }  
}

准备好后,构建并运行以查看集成到Feed中的消息!


Weather on Mars

你的宇航员需要能够获得当前的天气,以便在沙尘暴等障碍物周围航行。 JPL构建了另一个显示当前天气的模块。 那里有很多信息,所以他们要求天气只在点击时显示。

创建一个名为WeatherSectionController的最后一个section controller。 使用初始化程序和一些变量启动class:

import IGListKit

class WeatherSectionController: ListSectionController {
  // 1
  var weather: Weather!
  // 2
  var expanded = false
  
  override init() {
    super.init()
    // 3
    inset = UIEdgeInsets(top: 0, left: 0, bottom: 15, right: 0)
  }
}

这段代码的作用:

  • 1) 此section controller将在didUpdate(to :)中接收Weather对象。
  • 2) expanded是一个Bool,用于跟踪宇航员是否扩大了天气section。 您将其初始化为false,以便最初折叠详细信息单元格。
  • 3) 与其他section一样,使用15点的bottom inset

现在为WeatherSectionController添加一个扩展并重写三个方法:

// MARK: - Data Provider
extension WeatherSectionController {
  // 1
  override func didUpdate(to object: Any) {
    weather = object as? Weather
  }

  // 2
  override func numberOfItems() -> Int {
    return expanded ? 5 : 1
  }
  
  // 3
  override func sizeForItem(at index: Int) -> CGSize {
    guard let context = collectionContext else { 
      return .zero 
    }
    let width = context.containerSize.width
    if index == 0 {
      return CGSize(width: width, height: 70)
    } else {
      return CGSize(width: width, height: 40)
    }
  }
}

下面就是工作原理:

  • 1) 在didUpdate(to :)中,保存传递的Weather对象。
  • 2) 如果您正在显示扩展天气,则numberOfItems()将返回包含不同天气数据的五个单元格。如果未展开,则只需要一个单元格即可显示占位符。
  • 3) 第一个单元格应该比其他单元格大一些,因为它显示标题。您不必检查展开expanded状态,因为该header单元格是两种情况下的第一个单元格。

接下来,您需要实现cellForItem(at :)来配置天气单元格。以下是一些详细要求:

  • 第一个单元格应为WeatherSummaryCell类型,其他单元格应为WeatherDetailCell
  • 使用cell.setExpanded(_ :)配置天气摘要单元格。
  • 使用以下标题和详细信息标签配置四个不同的天气细节单元格:
    • “Sunrise” with weather.sunrise
    • “Sunset” with weather.sunset
    • “High” with "\(weather.high) C"
    • “Low” with "\(weather.low) C"

给这个cell一个截图,解决方案就在下面。

override func cellForItem(at index: Int) -> UICollectionViewCell {
  let cellClass: AnyClass = 
    index == 0 ? WeatherSummaryCell.self : WeatherDetailCell.self
  let cell = collectionContext!
    .dequeueReusableCell(of: cellClass, for: self, at: index)

  if let cell = cell as? WeatherSummaryCell {
    cell.setExpanded(expanded)
  } else if let cell = cell as? WeatherDetailCell {
    let title: String, detail: String
    switch index {
    case 1:
      title = "SUNRISE"
      detail = weather.sunrise
    case 2:
      title = "SUNSET"
      detail = weather.sunset
    case 3:
      title = "HIGH"
      detail = "\(weather.high) C"
    case 4:
      title = "LOW"
      detail = "\(weather.low) C"
    default:
      title = "n/a"
      detail = "n/a"
    }
    cell.titleLabel.text = title
    cell.detailLabel.text = detail
  }
  return cell
}

您需要做的最后一件事是切换展开的部分并在点击时更新单元格。 重写ListSectionController另一个方法:

override func didSelectItem(at index: Int) {
  collectionContext?.performBatch(animated: true, updates: { batchContext in
    self.expanded.toggle()
    batchContext.reload(self)
  }, completion: nil)
}

performBatch(animated:updates:completion :)批量处理并在单个事务中执行更新。 只要控制器中的内容或单元数发生变化,就可以使用它。 由于您使用numberOfItems()切换扩展,因此将根据expanded标志添加或删除单元格。

返回FeedViewController.swift并在FeedViewController顶部附近添加以下内容:

let wxScanner = WxScanner()

WxScanner是天气条件的模型对象。

接下来,更新ListAdapter DataSource扩展中的objects(for:),使其如下所示:

// 1
var items: [ListDiffable] = [wxScanner.currentWeather]
items += loader.entries as [ListDiffable]
items += pathfinder.messages as [ListDiffable]
// 2
return items.sorted { (left: Any, right: Any) -> Bool in
  guard let 
    left = left as? DateSortable, 
    let right = right as? DateSortable 
    else {
      return false
  }
  return left.date > right.date
}

您已更新数据源方法以包含currentWeather。 以下是有关此功能的详细信息:

  • 1) 将currentWeather添加到items数组中。
  • 2) 所有数据都符合DataSortable协议,因此使用该协议对数据进行排序。 这可确保数据按时间顺序显示。

最后,更新listAdapter(_:sectionControllerFor :)以显示如下:

if object is Message {
  return MessageSectionController()
} else if object is Weather {
  return WeatherSectionController()
} else {
  return JournalSectionController()
}

Weather对象出现时,返回WeatherSectionController

建立并再次运行。 您应该在顶部看到新的天气对象。 尝试点击该部分以展开和收缩它。


Performing Updates

JPL对你的进步感到欣喜若狂!

在你工作的时候,美国宇航局局长协调了宇航员的救援行动,要求他发射并拦截另一艘船! 这将是一个复杂的发射,所以他将不得不在恰当的时间升空。

JPL工程部门通过实时聊天扩展了消息传递模块,他们要求您对其进行集成。

打开FeedViewController.swift并将以下行添加到viewDidLoad()的末尾:

pathfinder.delegate = self
pathfinder.connect()

Pathfinder模块都经过实时支持修补。 您需要做的就是连接到设备并响应委托事件。

将以下扩展添加到文件的底部:

// MARK: - PathfinderDelegate
extension FeedViewController: PathfinderDelegate {
  func pathfinderDidUpdateMessages(pathfinder: Pathfinder) {
    adapter.performUpdates(animated: true)
  }
}

FeedViewController现在符合PathfinderDelegate。 单个方法performUpdates(animated :)告诉ListAdapter向其数据源询问新对象,然后更新UI。 它处理被删除,更新,移动或插入的对象。

构建并运行以查看队长的消息更新! 您所要做的就是为IGListKit添加一个方法,以确定数据源中的更改内容,并在新数据到达时为更改设置动画:

您现在需要做的就是将最新版本传输给宇航员,他将回家!

后记

本篇主要简单介绍了基于IGListKit框架的更好的UICollectionViews简单示例,感兴趣的给个赞或者关注~~~

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

推荐阅读更多精彩内容