如何使用自定义 header 将单元格排列成多个部分?
How to arrange cells into sections with a custom header?
如何使用自定义 header
按部分排列单元格
我设置了代码以按品牌排列 CartVC 中的单元格(将品牌放在 CartHeaderCell 中)。当数据从 HomeVC 传递到 CartVC 时,我无法让我的代码从我在 CartVC 中创建的代码中按品牌将单元格排列成多个部分。 (目前代码将数据从 HomeVC 传递到 CartVC 而无需将单元格排列成部分)
数据传入购物车后,我将如何在 CartVC 中按品牌排列各个部分
更新:
现在 CartViewController Extension
中的代码将单元格排列成多个部分,并按品牌将项目传递到单元格中,但将所有单元格打乱成随机部分或为品牌创建一个新部分单元格,and/or 在按下 CartBtn 时使模拟器崩溃,或在多个部分显示相同的 item/cell
extension HomeController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return itemSetup.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "HomeCell") as? HomeCell else { return UITableViewCell() }
let item = itemSetup[indexPath.row]
cell.configure(withItems: item)
// passes data to the Cart Cells in the CartVC when ATC Btn is pressed in each HomeCell
cell.addActionHandler = { (option: Int) in
print("Option selected = \(option)")
Tray.currentCart.cartItems.append(item)
item.selectedOption = option
}
return cell
}
}
import UIKit
class CartViewController: UIViewController {
var items: Items!
// arranges cells into sections
var tray: [Tray] = []
var sortedBrandsByName: [String] = []
var sections: [[Tray]] = [[]]
@IBOutlet weak var cartTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// arranges cells into sections
let brandNames = tray.map { [=12=]. titleBrandName }
let uniqueBrandNames = Array(Set(brandNames))
let sortedBrandNames = uniqueBrandNames.sorted()
let sections: [[Tray]] = sortedBrandNames.map { firstBrandNames in
return tray
.filter { [=12=]. titleBrandName == firstBrandNames }
.sorted { [=12=].cart.brand < .cart.brand } // sort them
}
// Do any additional setup after loading the view.
cartTableView.dataSource = self
cartTableView.delegate = self
}
}
extension CartViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return Tray.currentCart.cartItems.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//allows data passed from the HomeVC populate the CartCells
return Tray.currentCart.cartItems[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CartCell", for: indexPath) as! CartCell
// **Active code** that allows data passed from the HomeVC populate the CartCells
let cart = Tray.currentCart.cartItems[indexPath.row]
cell.configure(withItems: cart)
return cell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cartHeader = tableView.dequeueReusableCell(withIdentifier: "CartHeaderCell") as! CartHeaderCell
cartHeader.storeName.text = Tray.currentCart.cartItems[section].brand
return cartHeader
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 45
}
}
class CartHeaderCell: UITableViewCell {
@IBOutlet weak var brandName: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
}
class CartCell: UITableViewCell {
@IBOutlet weak var lblMealName: UILabel!
@IBOutlet weak var imageUrl: UIImageView!
@IBOutlet weak var lblSubTotal: UILabel!
@IBOutlet weak var lblQty: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
// allows the data to be passed into the cart cells
func configure(withItems items: Items) {
imageUrl.sd_setImage(with: URL(string: items.imageUrl))
lblQty.text = "\(items.count)"
let formatter = NumberFormatter()
formatter.maximumFractionDigits = 2
formatter.numberStyle = .decimal
if items.selectedOption == 1 {
lblSubTotal.text = "$\(formatter.string(for: items.price1 * Float(items.count))!)"
lblMealName.text = "\(items.name) ● \(items.weight1)"
} else if items.selectedOption == 2 {
lblSubTotal.text = "$\(formatter.string(for: items.price2 * Float(items.count))!)"
lblMealName.text = "\(items.name) ● \(items.weight2)"
} else if items.selectedOption == 3 {
lblSubTotal.text = "$\(formatter.string(for: items.price3 * Float(items.count))!)"
lblMealName.text = "\(items.name) ● \(items.weight3)"
}
}
}
// allows the code that is passed to the CartVC when an item is passed from the HomeVC to the CartVC
class Tray {
static let currentCart = Tray()
var cartItems = [Items]()
var cart: Items!
var sectionTitle: String!
}
extension Tray {
var titleBrandName: String {
return String(self.cart.brand[self.cart.brand.startIndex]).uppercased()
}
}
问题是你实际上并没有保存你正在做的排序。即使您是..您正在查看 UITableViewDataSource
方法中数据的代码的不同部分。
第一个问题:您实际上并没有保存数据。
确保创建 CartViewController
的函数实际上在 viewDidLoad:
之前传入 tray
!!
这部分:
import UIKit
class CartViewController: UIViewController {
var items: Items!
// arranges cells into sections
var tray: [Tray] = []
var sortedBrandsByName: [String] = []
var sections: [[Tray]] = [[]]
@IBOutlet weak var cartTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// arranges cells into sections
let brandNames = tray.map { [=10=]. titleBrandName }
let uniqueBrandNames = Array(Set(brandNames))
let sortedBrandNames = uniqueBrandNames.sorted()
let sections: [[Tray]] = sortedBrandNames.map { firstBrandNames in
return tray
.filter { [=10=]. titleBrandName == firstBrandNames }
.sorted { [=10=].cart.brand < .cart.brand } // sort them
}
// Do any additional setup after loading the view.
cartTableView.dataSource = self
cartTableView.delegate = self
}
}
您的 viewDidLoad
创建了 sortedBrandNames
和 sections
的本地版本。
删除 lets 并试试这个:
override func viewDidLoad() {
super.viewDidLoad()
// arranges cells into sections
let brandNames = tray.map { [=11=]. titleBrandName }
let uniqueBrandNames = Array(Set(brandNames))
// MY CHANGES ARE BELOW (remove let)
sortedBrandNames = uniqueBrandNames.sorted()
sections: [[Tray]] = sortedBrandNames.map { firstBrandNames in
return tray
.filter { [=11=]. titleBrandName == firstBrandNames }
.sorted { [=11=].cart.brand < .cart.brand } // sort them
}
// Do any additional setup after loading the view.
cartTableView.dataSource = self
cartTableView.delegate = self
}
一般反馈..您应该使用这些来填写您的 table 视图,而不是静态 Tray.currentTray
。将数据保存在您可以从代码库中的任何位置 read/write 的值上是非常糟糕的。
其次..您正在使用 UITableViewDataSource
方法读取不同的数据集...
假设我们确实设法保存了我们现在排序的数据......当你这样做时 Tray.currentCart
你实际上并没有查看你刚刚排序的数据(那将是 self.sections
),在没有重点是你更改了 Tray.currentCart
中的数据吗(再次强调,不要制作像这样的静态东西或单例,这样很容易引入错误)
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//allows data passed from the HomeVC populate the CartCells
return Tray.currentCart.cartItems[section].count
}
相反...试试这个:
extension CartViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return self.sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.sections[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CartCell", for: indexPath) as! CartCell
let cart = self.sections[indexPath.section][indexPath.row]
cell.configure(withItems: cart)
return cell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cartHeader = tableView.dequeueReusableCell(withIdentifier: "CartHeaderCell") as! CartHeaderCell
cartHeader.storeName.text = self.sections[section].brand
return cartHeader
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 45
}
}
这样您就可以查看刚刚在 viewDidLoad
中排序的数据。
(请注意,我假设您的排序逻辑工作正常)
如何使用自定义 header
按部分排列单元格我设置了代码以按品牌排列 CartVC 中的单元格(将品牌放在 CartHeaderCell 中)。当数据从 HomeVC 传递到 CartVC 时,我无法让我的代码从我在 CartVC 中创建的代码中按品牌将单元格排列成多个部分。 (目前代码将数据从 HomeVC 传递到 CartVC 而无需将单元格排列成部分)
数据传入购物车后,我将如何在 CartVC 中按品牌排列各个部分
更新:
现在 CartViewController Extension
中的代码将单元格排列成多个部分,并按品牌将项目传递到单元格中,但将所有单元格打乱成随机部分或为品牌创建一个新部分单元格,and/or 在按下 CartBtn 时使模拟器崩溃,或在多个部分显示相同的 item/cell
extension HomeController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return itemSetup.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "HomeCell") as? HomeCell else { return UITableViewCell() }
let item = itemSetup[indexPath.row]
cell.configure(withItems: item)
// passes data to the Cart Cells in the CartVC when ATC Btn is pressed in each HomeCell
cell.addActionHandler = { (option: Int) in
print("Option selected = \(option)")
Tray.currentCart.cartItems.append(item)
item.selectedOption = option
}
return cell
}
}
import UIKit
class CartViewController: UIViewController {
var items: Items!
// arranges cells into sections
var tray: [Tray] = []
var sortedBrandsByName: [String] = []
var sections: [[Tray]] = [[]]
@IBOutlet weak var cartTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// arranges cells into sections
let brandNames = tray.map { [=12=]. titleBrandName }
let uniqueBrandNames = Array(Set(brandNames))
let sortedBrandNames = uniqueBrandNames.sorted()
let sections: [[Tray]] = sortedBrandNames.map { firstBrandNames in
return tray
.filter { [=12=]. titleBrandName == firstBrandNames }
.sorted { [=12=].cart.brand < .cart.brand } // sort them
}
// Do any additional setup after loading the view.
cartTableView.dataSource = self
cartTableView.delegate = self
}
}
extension CartViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return Tray.currentCart.cartItems.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//allows data passed from the HomeVC populate the CartCells
return Tray.currentCart.cartItems[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CartCell", for: indexPath) as! CartCell
// **Active code** that allows data passed from the HomeVC populate the CartCells
let cart = Tray.currentCart.cartItems[indexPath.row]
cell.configure(withItems: cart)
return cell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cartHeader = tableView.dequeueReusableCell(withIdentifier: "CartHeaderCell") as! CartHeaderCell
cartHeader.storeName.text = Tray.currentCart.cartItems[section].brand
return cartHeader
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 45
}
}
class CartHeaderCell: UITableViewCell {
@IBOutlet weak var brandName: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
}
class CartCell: UITableViewCell {
@IBOutlet weak var lblMealName: UILabel!
@IBOutlet weak var imageUrl: UIImageView!
@IBOutlet weak var lblSubTotal: UILabel!
@IBOutlet weak var lblQty: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
// allows the data to be passed into the cart cells
func configure(withItems items: Items) {
imageUrl.sd_setImage(with: URL(string: items.imageUrl))
lblQty.text = "\(items.count)"
let formatter = NumberFormatter()
formatter.maximumFractionDigits = 2
formatter.numberStyle = .decimal
if items.selectedOption == 1 {
lblSubTotal.text = "$\(formatter.string(for: items.price1 * Float(items.count))!)"
lblMealName.text = "\(items.name) ● \(items.weight1)"
} else if items.selectedOption == 2 {
lblSubTotal.text = "$\(formatter.string(for: items.price2 * Float(items.count))!)"
lblMealName.text = "\(items.name) ● \(items.weight2)"
} else if items.selectedOption == 3 {
lblSubTotal.text = "$\(formatter.string(for: items.price3 * Float(items.count))!)"
lblMealName.text = "\(items.name) ● \(items.weight3)"
}
}
}
// allows the code that is passed to the CartVC when an item is passed from the HomeVC to the CartVC
class Tray {
static let currentCart = Tray()
var cartItems = [Items]()
var cart: Items!
var sectionTitle: String!
}
extension Tray {
var titleBrandName: String {
return String(self.cart.brand[self.cart.brand.startIndex]).uppercased()
}
}
问题是你实际上并没有保存你正在做的排序。即使您是..您正在查看 UITableViewDataSource
方法中数据的代码的不同部分。
第一个问题:您实际上并没有保存数据。
确保创建 CartViewController
的函数实际上在 viewDidLoad:
之前传入 tray
!!
这部分:
import UIKit
class CartViewController: UIViewController {
var items: Items!
// arranges cells into sections
var tray: [Tray] = []
var sortedBrandsByName: [String] = []
var sections: [[Tray]] = [[]]
@IBOutlet weak var cartTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// arranges cells into sections
let brandNames = tray.map { [=10=]. titleBrandName }
let uniqueBrandNames = Array(Set(brandNames))
let sortedBrandNames = uniqueBrandNames.sorted()
let sections: [[Tray]] = sortedBrandNames.map { firstBrandNames in
return tray
.filter { [=10=]. titleBrandName == firstBrandNames }
.sorted { [=10=].cart.brand < .cart.brand } // sort them
}
// Do any additional setup after loading the view.
cartTableView.dataSource = self
cartTableView.delegate = self
}
}
您的 viewDidLoad
创建了 sortedBrandNames
和 sections
的本地版本。
删除 lets 并试试这个:
override func viewDidLoad() {
super.viewDidLoad()
// arranges cells into sections
let brandNames = tray.map { [=11=]. titleBrandName }
let uniqueBrandNames = Array(Set(brandNames))
// MY CHANGES ARE BELOW (remove let)
sortedBrandNames = uniqueBrandNames.sorted()
sections: [[Tray]] = sortedBrandNames.map { firstBrandNames in
return tray
.filter { [=11=]. titleBrandName == firstBrandNames }
.sorted { [=11=].cart.brand < .cart.brand } // sort them
}
// Do any additional setup after loading the view.
cartTableView.dataSource = self
cartTableView.delegate = self
}
一般反馈..您应该使用这些来填写您的 table 视图,而不是静态 Tray.currentTray
。将数据保存在您可以从代码库中的任何位置 read/write 的值上是非常糟糕的。
其次..您正在使用 UITableViewDataSource
方法读取不同的数据集...
假设我们确实设法保存了我们现在排序的数据......当你这样做时 Tray.currentCart
你实际上并没有查看你刚刚排序的数据(那将是 self.sections
),在没有重点是你更改了 Tray.currentCart
中的数据吗(再次强调,不要制作像这样的静态东西或单例,这样很容易引入错误)
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//allows data passed from the HomeVC populate the CartCells
return Tray.currentCart.cartItems[section].count
}
相反...试试这个:
extension CartViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return self.sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.sections[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CartCell", for: indexPath) as! CartCell
let cart = self.sections[indexPath.section][indexPath.row]
cell.configure(withItems: cart)
return cell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cartHeader = tableView.dequeueReusableCell(withIdentifier: "CartHeaderCell") as! CartHeaderCell
cartHeader.storeName.text = self.sections[section].brand
return cartHeader
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 45
}
}
这样您就可以查看刚刚在 viewDidLoad
中排序的数据。
(请注意,我假设您的排序逻辑工作正常)