进一步扩展可扩展 table 视图单元格

Expanding the expandable table View cells to further extent

我创建了可扩展 table 视图单元格,如下图所示。 使用的库是 JExpandableTableView

创建此 ExpandableTable 视图的代码如下:

部分模型:

class SectionInfo: NSObject {

    var cells = [CellInfo]()
    var CategoryName: String
    var CategoryCount: String
    var CategoryImage: UIImage

    init(_ text: String,SubCount: String, Image: UIImage ) {

        self.CategoryName = text
        self.CategoryCount = SubCount
        self.CategoryImage = Image
    }
}

子类别单元格的模型:

class CellInfo: NSObject {

    var SubcategoryName: String!
    var SubcategoryCount: String!


    init(_ SubName: String, SubCount: String) {

        self.SubcategoryName = SubName
        self.SubcategoryCount = SubCount
    }
}

视图控制器:

class CategoryVC: BaseVC,JExpandableTableViewDataSource,JExpandableTableViewDelegate{

    @IBOutlet weak var tblViewCategory: JExpandableTableView!

    var tableViewData = [SectionInfo]()
    var expandedIndexPath: IndexPath?

    override func viewDidLoad() {
        super.viewDidLoad()

        self.title = "Category"
        self.tblViewCategory.dataSource = self
        self.tblViewCategory.delegate = self
        self.tblViewCategory.keepPreviousCellExpanded = false

        self.LoadData()
    }


    func LoadData() {

        var cellInfo = CellInfo("SubCategory 1",SubCount: "10")

        let sec1 = SectionInfo("Category 1", SubCount: "5", Image: UIImage(named: "Category3")!)
        sec1.cells.append(cellInfo)
        let sec2 = SectionInfo("Category 2", SubCount: "8", Image: UIImage(named: "Category3")!)
        cellInfo = CellInfo("SubCategory 2",SubCount: "20")
        sec2.cells.append(cellInfo)
        cellInfo = CellInfo("SubCategory 2.1",SubCount: "30")
        sec2.cells.append(cellInfo)

        let sec3 = SectionInfo("Category 3", SubCount: "10", Image: UIImage(named: "Category3")!)
        cellInfo = CellInfo("SubCategory 3",SubCount: "30")
        sec3.cells.append(cellInfo)

        tableViewData.append(sec1)
        tableViewData.append(sec2)
        tableViewData.append(sec3)



        let celNib = UINib.init(nibName: "SubCategoryCell", bundle: nil)
        tblViewCategory.register(celNib, forCellReuseIdentifier: "SubCategoryCell")

        let headerNib = UINib.init(nibName: "HeaderView", bundle: nil)
        tblViewCategory.register(headerNib, forHeaderFooterViewReuseIdentifier: "HeaderView")
    }


    @IBAction func DrawerMenutap(_ sender: Any) {

        self.OpenDrawerMenu()
    }


    func tableView(_ tableView: JExpandableTableView, numberOfRowsInSection section: Int, callback: @escaping (Int) -> Void) {

        let sectionInfo = self.tableViewData[section]
        callback(sectionInfo.cells.count)
    }

    func tableView(_ tableView: JExpandableTableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 150
    }

    func tableView(_ tableView: JExpandableTableView, heightForRowAtIndexPath indexPath: IndexPath) -> CGFloat {
        return 44
    }

    func tableView(_ tableView: JExpandableTableView, initialNumberOfRowsInSection section: Int) -> Int {

     //   let sectionInfo = self.tableViewData[section]
        return 0
    }

    func numberOfSections(in tableView: JExpandableTableView) -> Int {
        return tableViewData.count
    }

    func tableView(_ tableView: JExpandableTableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{

        let section = tableViewData[indexPath.section]
        let row = section.cells[indexPath.row]

        let cell = tableView.dequeueReusableCell(withIdentifier: "SubCategoryCell", for: indexPath) as! SubCategoryCell

        cell.contentView.backgroundColor = UIColor.white
        cell.lblSubCategoryName.text = row.SubcategoryName
        return cell
    }


    func tableView(_ tableView: JExpandableTableView, viewForHeaderInSection section: Int) -> UIView? {

        let section = self.tableViewData[section]
        let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: "HeaderView") as! HeaderView
        header.contentView.backgroundColor = UIColor.groupTableViewBackground
        header.CatName.text = section.CategoryName
        header.CatImgView.image = UIImage(named: "Category4")
        header.CatCount.text = section.CategoryCount
        return header
    }




}


//MARK: Table View Cell for Category

class CatCell: UITableViewCell {

    @IBOutlet weak var lblName: UILabel!
}

我的进一步要求是我想扩展单元格(子类别 2,子类别 2.1)以便在子类别(子类别的子类别)存在的情况下容纳它们。那么实现这一目标的方法应该是什么。

UITableView 的真正设计目的不是为了显示层次结构的两个以上级别,如部分和行。

如果您想显示两个以上的级别,可以使用所有不同类型的自定义解决方案,一种简单的方法是为子类别设计不同的单元格并相应地显示,如下图所示。

在上面的示例中,它是相同的单元格,但使用不同的背景颜色来指示子类别。

您可以通过为 SubCategory 2.1 创建自定义单元格并将其显示在每个部分的第一行来实现此目的。 然后,在 didSelectRow 方法中,如果选择了第一行,您将 SubCategory 2.1 的状态更新为折叠(或非折叠),重新加载该部分,并且在 numberOfRows 方法中您应该 return根据SubCategory 2.1的状态适当的行数。

我在 youtube 上看到了这个视频:

https://www.youtube.com/watch?v=VFtsSEYDNRU

它可能会帮助你实现你想要的。

但我认为您可以通过制作自定义 UIView 并将其放入您的单元格中来实现此目的,这样当您点击子类别时它会展开并显示您想要的更多详细信息。

希望对您有所帮助。

UITableView 的真正设计方式是显示两个级别、部分和行。

但要显示多于两个级别,您可以根据您的部分、子类别模型操作 increase/expand 或 decrease/collapse 的行。

所以 table 结构看起来像那样

 section_header_1
    subCategory_1.0
        subSubCategory_1.0.1
    subCategory_1.1
        subSubCategory_1.1.1
    subCategory_1.2
        subSubCategory_1.2.1

 section_header_2
    subCategory_2.0
        subSubCategory_2.0.1
    subCategory_2.1
        subSubCategory_2.1.1
    subCategory_2.2
        subSubCategory_2.2.1

对于 Header,您必须创建自己的自定义 header 行并将其作为每个部分的第一行。您可以将单元格设置为看起来像 header,并设置 tableView:didSelectRowAt 以手动展开或折叠它所在的部分、subCategory 或 SubSubCategory。第一行之后的行将是您的 subCategory 和 subSubCategory .

然后是 Section、SubCategory 和 SubSubCategory 的模型,用于存储对应于每个部分、子类别的 "expend" 值的布尔值。如果它只存储名称,则可以避免使用 SubSubCategory 模型,但这样做很容易理解。例如,用于保存 Section, SubCategory "expend" booleans.

的结构
public struct Section {
    var name: String
    var expand: Bool
    var subCategory:[SubCategory]

    public init(name: String, expand: Bool = false ,subCategory: [SubCategory]) {
        self.name = name
        self.expand = expand
        self.subCategory = subCategory
    }
}
public struct SubCategory {
    var name: String
    var expand: Bool
    var subSubCategory: SubSubCategory
    public init(name: String, expand: Bool = false, subSubCategory: SubSubCategory) {
        self.name = name
        self.expand = expand
        self.subSubCategory = subSubCategory
    }
}
public struct SubSubCategory {
    var name: String
    public init(name: String) {
        self.name = name
    }
}

创建 3 个自定义单元格,一个用于 Header,另一个用于 SubCategorySubSubCategory,并将其显示在每个部分的第一行 Header Cell 并在 展开或折叠 后显示相应的 SubCategorySubSubCategory 单元格。

毕竟你的代码应该是那样的。

import UIKit

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    @IBOutlet weak var tableView: UITableView!
    var sampleData: [Section] = [
        Section(name: "Category 1", expand: false,
                subCategory: [

                    SubCategory(name: "Category 1.1", expand: false, subSubCategory: SubSubCategory(name: "SubSubCategory 1.1.1")),

                    SubCategory(name: "Category 1.2", expand: false, subSubCategory: SubSubCategory(name: "SubSubCategory 1.2.1"))
            ]
        ),
        Section(name: "Category 2", expand: false,
                subCategory: [

                    SubCategory(name: "Category 2.1", expand: false, subSubCategory: SubSubCategory(name: "SubSubCategory 2.1.1")),

                    SubCategory(name: "Category 2.2", expand: false, subSubCategory: SubSubCategory(name: "SubSubCategory 2.2.1"))
            ]
        )
    ]

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    //
    // MARK: - View Controller DataSource and Delegate
    //

    func numberOfSections(in tableView: UITableView) -> Int {
        return sampleData.count
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        var expandCount = 0
        if sampleData[section].expand {
            // if header is expanded all subCategory will be also expanded
            expandCount = sampleData[section].subCategory.count
            for subCategory in sampleData[section].subCategory{
                //check for how many subSubCategory is expanded
                if subCategory.expand{
                    expandCount += 1
                }
            }
        }

        // returning the count of total expanded SubCategories and SubSubCategories
        // 1 is for header you can remove if you are using `viewForHeaderInSection`
        return 1 + expandCount
    }


    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        // Header cell
        if indexPath.row == 0 {
            let cell = tableView.dequeueReusableCell(withIdentifier: "header")!
            return cell
        }else{

            var countValue = 0
            var indexSubCategory = 0
            let sampleDataSection = sampleData[indexPath.section]

            // check for how many "subCategory" expanded or collapsed
            if sampleDataSection.expand{
                for (index, subCategory) in sampleDataSection.subCategory.enumerated(){

                    countValue += 1
                    if countValue >= indexPath.row{
                        indexSubCategory = index
                        break
                    }
                    // check for how many "subSubCategory" expanded or collapsed
                    if subCategory.expand{
                        if index == sampleDataSection.subCategory.count-1{
                            countValue += 2
                            indexSubCategory = index + 1
                        }else{
                            countValue += 1
                        }
                    }
                }

                // if countValue is grater then indexPath.row it will return "subSubCategory" cell
                // else/countValue = indexPath.row then return "subCategory" cell

                if countValue > indexPath.row{
                    // Cell subSubCategory
                    let cell = tableView.dequeueReusableCell(withIdentifier: "subSubCategory")!
                    cell.textLabel?.text = self.sampleData[indexPath.section].subCategory[indexSubCategory - 1].subSubCategory.name
                    return cell
                }else{
                    // Cell subCategory
                    let cell = tableView.dequeueReusableCell(withIdentifier: "subCategory")!
                    cell.textLabel?.text = self.sampleData[indexPath.section].subCategory[indexSubCategory].name
                    return cell
                }
            }

            else{
                // Cell subCategory
                let cell = tableView.dequeueReusableCell(withIdentifier: "subCategory")!
                cell.textLabel?.text = self.sampleData[indexPath.section].subCategory[indexPath.row].name
                return cell
            }
        }
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        // then header cell is selected switch between collapse or expand between "subCategory"
        if indexPath.row == 0{
            let expand = !sampleData[indexPath.section].expand

            //Toggle collapse
            sampleData[indexPath.section].expand = expand
            self.tableView.reloadSections([indexPath.section], with: .none)
        }else{
            var countValue = 0
            var indexSubCategory = 0
            let sampleDataSection = sampleData[indexPath.section]
            if sampleDataSection.expand{
                for (index, subCategory) in sampleDataSection.subCategory.enumerated(){

                    countValue += 1
                    if countValue >= indexPath.row{
                        indexSubCategory = index
                        break
                    }
                    if subCategory.expand{
                        if index == sampleDataSection.subCategory.count-1{
                            countValue += 2
                            indexSubCategory = index + 1
                        }else{
                            countValue += 1
                        }
                    }
                }
                // and if "subCategory" cell is selected switch between collapse or expand between "subSubCategory"
                if countValue == indexPath.row{
                    let subSubCategory = sampleData[indexPath.section].subCategory[indexSubCategory]
                    let expand = !subSubCategory.expand
                    sampleData[indexPath.section].subCategory[indexSubCategory].expand = expand
                    UIView.performWithoutAnimation {
                        self.tableView.reloadSections([indexPath.section], with: .none)
                        self.tableView.layoutIfNeeded()
                    }
                }
            }
        }
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableViewAutomaticDimension
    }

    func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
        return CGFloat.leastNormalMagnitude
    }

}

下载演示项目here