【问题标题】:How to arrange cells into sections with a custom header?如何将单元格排列成具有自定义标题的部分?
【发布时间】:2020-03-12 08:05:33
【问题描述】:

如何使用自定义标题按部分排列单元格

我设置了代码以按品牌排列 CartVC 中的单元格(将品牌放在 CartHeaderCell 中)。当数据从 HomeVC 传递到 CartVC 时,我无法让我的代码从我在 CartVC 中创建的代码按品牌将单元格排列成部分。 (当前代码将数据从 HomeVC 传递到 CartVC,而不将单元格排列成部分)

数据传入购物车后,我将如何在 CartVC 中按品牌排列部分

更新:

现在CartViewController Extension 中的代码将单元格排列成部分并按品牌将项目传递到单元格中,但是将所有单元格打乱成随机部分或在单元格中为品牌创建一个新部分,和/或按下 CartBtn 时使模拟器崩溃,或在多个部分中显示相同的项目/单元格

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 { $0. titleBrandName }
        let uniqueBrandNames = Array(Set(brandNames))           
        let sortedBrandNames = uniqueBrandNames.sorted()
        let sections: [[Tray]] = sortedBrandNames.map { firstBrandNames in
            return tray
                .filter { $0. titleBrandName == firstBrandNames } 
                .sorted { $0.cart.brand < $1.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()
    }
}

【问题讨论】:

  • 节的标题不应实现为一行。实现这一点的更好方法是 - 1. 使用以品牌名称为键的字典而不是数据源的数组,并在数组中使用相应的值。 2. 在numberOfSections 中提供字典的键数。 3.在viewForHeaderInSection 配置section header。
  • 我刚刚在我的 CartVC 和 Tray 类(标记为“测试代码”)中添加了一些代码,我认为这将使您的解决方案迈出第一步。很抱歉,我整个社区的 wifi 都断了,我终于可以去当地的咖啡店做这件事了
  • 我刚刚在numberOfSections 中测试了这个,我放置了return Tray.currentCart.cartItems.countnumberOfRowsInSection 我放置了return Tray.currentCart.cartItems[section].count。虽然它在数据传递时显示一个标题并将单元格分成多个部分,但它并不准确,实际上它完全打乱了任何地方的项目。而且该品牌未能在标题中显示我尝试的内容
  • 可以贴一下表格数据源吗?
  • 我认为 Tray 的模型是错误的,因为从图片中似乎有多个品牌,而您将 titleBrandName 用作单一属性而不是数组。除此之外,能否请您发布项目的模型类,以便我可以仔细看看如何安排项目?

标签: ios arrays swift uitableview uitableviewsectionheader


【解决方案1】:

问题是你实际上并没有保存你正在做的事情。即使您是……您正在查看 UITableViewDataSource 方法中数据代码的不同部分。

第一个问题:您实际上并没有保存数据。 确保创建CartViewController 的函数实际上在tray 之前传递viewDidLoad: !!

在这部分:

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 { $0. titleBrandName }
        let uniqueBrandNames = Array(Set(brandNames))           
        let sortedBrandNames = uniqueBrandNames.sorted()
        let sections: [[Tray]] = sortedBrandNames.map { firstBrandNames in
            return tray
                .filter { $0. titleBrandName == firstBrandNames } 
                .sorted { $0.cart.brand < $1.cart.brand } // sort them
        }

        // Do any additional setup after loading the view.
        cartTableView.dataSource = self
        cartTableView.delegate = self

    }
}

您的viewDidLoad 会创建sortedBrandNamessections 的本地版本。 删除让并尝试这个:

override func viewDidLoad() {
    super.viewDidLoad()

    // arranges cells into sections
    let brandNames = tray.map { $0. titleBrandName }
    let uniqueBrandNames = Array(Set(brandNames)) 

    // MY CHANGES ARE BELOW (remove let)      
    sortedBrandNames = uniqueBrandNames.sorted()
    sections: [[Tray]] = sortedBrandNames.map { firstBrandNames in
        return tray
            .filter { $0. titleBrandName == firstBrandNames } 
            .sorted { $0.cart.brand < $1.cart.brand } // sort them
    }

    // Do any additional setup after loading the view.
    cartTableView.dataSource = self
    cartTableView.delegate = self

}

一般反馈.. 您应该使用这些来填写您的表格视图,而不是静态 Tray.currentTray。将数据保存在您可以从代码库中的任何位置读取/写入的值上真的很糟糕。

其次..您正在使用 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 中排序的数据。 (注意我假设您的排序逻辑正常工作)

【讨论】:

  • 好的,我刚刚运行了代码,当我删除 Let 时,我在 viewDidLoad 中遇到了错误。在cell.configure(withItems: cart) 上的 cellForRowAt 中出现错误 无法将“托盘”类型的值转换为预期的参数类型“产品列表”cartHeader.storeName.text = self.sections[section].brand 上的 viewForHeaderInSection 出现错误**“类型的值”[ Tray]' 没有成员 'brand'**。我会尽力解决错误,看看我是否可以完成这项工作,但我现在无法正常工作
  • 你对Tray.currentCart 的看法是绝对正确的,我正在研究如何重组我的代码以将currentCart 从托盘类中删除,这将需要我一些时间来重写我的代码,因为它的属性用于将数据从我的 HomeVC(代码不在此处)从闭包传递到 CartVC
  • 如果你想备份数据,可以使用委托之类的东西。在HomeVC 上初始化CartVC 设置cartVC.delegate = self 然后你可以像这样传回数据。请务必在 Google 上搜索,因为您将要声明委托 weak 以避免保留周期和其他最佳做法
  • 试过了,但没用,因为我有一个 closure 可以将数据从 HomeVC 传递到 CartVC
  • 运行了一堆测试来让这段代码工作,它工作,很抱歉花了这么长时间才弄清楚,最近网络不好,过去一周做了大量工作
猜你喜欢
  • 2020-03-19
  • 2020-03-16
  • 1970-01-01
  • 1970-01-01
  • 2018-10-09
  • 2016-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多