美文网首页iglistkit
IGListKit框架详细解析(三) —— 基于IGListKi

IGListKit框架详细解析(三) —— 基于IGListKi

作者: 刀客传奇 | 来源:发表于2019-01-19 17:06 被阅读130次

版本记录

版本号 时间
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简单示例,感兴趣的给个赞或者关注~~~

相关文章

网友评论

    本文标题:IGListKit框架详细解析(三) —— 基于IGListKi

    本文链接:https://www.haomeiwen.com/subject/mwdzdqtx.html