如何将从 firebase 接收的数据分组到标头集合视图?
从 firebase 中,我收到了包含以下数据的阵列:
{
"N7AooUYQU576hb5qLux" : {
"requested_date" : 20190110,
"requested_times" : {
0: 1,
1: 2,
}
"0ckbfkwm2yR0wbcEQ2XT" : {
"requested_date" : 20190110,
"requested_times" : {
0: 3,
1: 4,
}
"38kBVw01kvJtYTtYt0ba" : {
"requested_date" : 20190211,
"requested_times" : {
0: 5,
1: 6,
}
"3bQ3WTwasALxqNNR9P4c" : {
"requested_date" : 20190315,
"requested_times" : {
0: 1,
1: 2,
}
"51OhvSiBGDa0HH8WV5bt" : {
"requested_date" : 20190211,
"requested_times" : {
0: 10,
1: 11,
}
}
要从 firestore 检索数据,请使用以下代码:
var bookingHall: [BookingHall] = []
var document: [DocumentSnapshot] = []
fileprivate func observeQuery() {
guard let query = query else { return }
listener = query.addSnapshotListener { [unowned self] (snapshot, error) in
if let err = error {
self.unknownError(error: err)
} else {
if let snapshot = snapshot {
let bookingModel = snapshot.documents.map { (document) -> BookingHall in
if let newBooking = BookingHall(dictionary: document.data()) {
return newBooking
} else {
fatalError("Fatal error")
}
}
self.bookingHall = bookingModel
self.document = snapshot.documents
self.collectionView.reloadData()
}
}
}
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return ...
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.bookingHall.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "studioBookCollCell", for: indexPath) as! StudioBookCollectionCell
let timeStart = self.bookingHall[indexPath.item].requestedTimes.first!
let timeEnd = self.bookingHall[indexPath.item].requestedTimes.last! + 1
cell.timeLabel.text = String(format: "%02d:00 - %02d:00", timeStart, timeEnd)
return cell
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "headerBook", for: indexPath) as! StudioBookCollectionReusableView
header.dateLabel.text = ""
return header
}
我想看到的最终结果就像下面的图片:
我不知道如何对数据进行分组并应用于标题,并且每个标题中的单元格中都有正确的数据。
请告诉我该怎么做?如果需要更多代码,我将更新我的帖子。
我的结构:
protocol BookingDocumentSerializable {
init?(dictionary:[String:Any])
}
struct BookingHall {
var contactInfo: [String: Any] = [:]
var creationDate: Timestamp
var requestedTimes: [Int] = []
var uid: String = ""
var hall: String = ""
var requestedDate: Int = 0
var dictionary: [String: Any] {
return [
"contact_info": contactInfo,
"creation_date": creationDate,
"requested_times": requestedTimes,
"uid": uid,
"hall": hall,
"requested_date": requestedDate
]
}
}
extension BookingHall: BookingDocumentSerializable {
init?(dictionary: [String: Any]) {
let contactInfo = dictionary["contact_info"] as? [String: Any] ?? [:]
let creationDate = dictionary["creation_date"] as? Timestamp
let requestedTimes = dictionary["requested_times"] as? [Int] ?? []
let uid = dictionary["uid"] as? String ?? ""
let hall = dictionary["hall"] as? String ?? ""
let requestedDate = dictionary["requested_date"] as? Int ?? 0
self.init(contactInfo: contactInfo,
creationDate: creationDate!,
requestedTimes: requestedTimes,
uid: uid,
hall: hall,
requestedDate: requestedDate)
}
}
答案 0 :(得分:2)
您可以使用grouping
来满足您的要求。
创建一个新字典,其关键字是由键返回的分组。 给定的闭包,其值是包含以下内容的元素的数组 返回每个键。
请参考下面的代码,这是一个公正的想法,您可以如何实现上述要求,因此,请您忽略其他语法错误。
let aryData = [BookingHall]() // Your main array
//Create dicationary with grouped value with `requested_date`
let dict = Dictionary(grouping: aryData, by: { $0.requested_date })
//Format Array for populate data into UITableView
let allKeys = Array(dict.keys)
let aryFinalData = [FinalData]()
for value in allKeys{
let data = FinalData(title: value, aryData: dict[value]!)
aryFinalData.append(data)
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return aryFinalData.count
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return aryFinalData[section].aryData.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cellData = aryFinalData[indexPath.section].aryData[indexPath.item]
return cell
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "headerBook", for: indexPath) as! StudioBookCollectionReusableView
let headerData = aryFinalData[indexPath.section]
header.dateLabel.text = headerData.requested_date
return header
}
为标题和子数组创建新结构
struct FinalData{
let title:String?
let aryData:[BookingHall]?
}
答案 1 :(得分:1)
创建字典以存储分组数据
var bookingHall: [BookingHall] = []
var groupedHalls: [Int: [BookingHall]] = [:]
为self.bookingHall数组分配值后,按日期对数据进行分组
self.bookingHall = bookingModel
groupedHalls = Dictionary(grouping: bookingHall, by: { $0.requestedDate })
collectionView.reloadData()
在collectionview数据源方法中使用此词典
func numberOfSections(in collectionView: UICollectionView) -> Int {
return groupedHalls.keys.count
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return groupedHalls[Array(groupedHalls.keys)[section]]?.count ?? 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let bookingHalls = groupedHalls[Array(groupedHalls.keys)[indexPath.section]]
let bookingHall = bookingHalls[indexPath.row]
let timeStart = bookingHall.requestedTimes.first!
let timeEnd = bookingHall.requestedTimes.last! + 1
cell.timeLabel.text = String(format: "%02d:00 - %02d:00", timeStart, timeEnd)
print(bookingHall)
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "headerBook", for: indexPath) as! StudioBookCollectionReusableView
header.dateLabel.text = "\(Array(groupedHalls.keys)[indexPath.section])"
return header
}
答案 2 :(得分:0)
您可以使用其他注释中描述的SupplementaryView,但是根据要实现的结果,可以考虑以下选项:
设为UITableView
,并且每个UITableViewCell
的内部都有一个UICollectionView
。在这种情况下,您可以将所有数据放入collectionView
的单元格中,而标题将属于tableView
在这种情况下有什么好处?您的整个视图是vertical-scrollable
,但是每个单元格可以独立地horizontal-scrollable
答案 3 :(得分:0)
您需要将JSON映射为[ (Int, [(Int,Int)] ) ]
:您的数组将如下所示:
[
( 20190110, [(1,2), (3,4)] ),
( 20190315, [(1,2)]),
( 20190211, [(5,6), (10-11)] )
]
然后在numberOfSection
中,您只需返回arrayForCollectionView.count
对于标题本身:
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "headerBook", for: indexPath) as! StudioBookCollectionReusableView
header.dateLabel.text = arrayForCollectionView[indexPath.section].0
return header
}