HSTableView

一个更简单、更优雅的 UITableView,更像是 SwiftUI 的风格,而不是 UIKit。行由对象管理,操作通过 Block 实现。

你的整个表格会被预先声明,不需要任何委托。

TableView 使用响应链方式来提供设置。任何设置都可以在行级别、节级别或表格级别进行设置。

这允许在表格级别进行简单配置,并在行级别进行轻松自定义。

Block 用于 tap 事件处理、delete 事件处理、样式设置等。

支持默认的(彩色)辅助视图。

HSTableView 适用于行数已知且有限的情况(尽管数量可能会改变)。它不支持无限滚动表格(对于这种情况,您必须使用 UITableView 和委托!)。

安装

使用 CocoaPods

pod 'HSTableView'

或使用 Swift Package Manager

简单示例

一个简单的表格,包含三行,并且每行都有点击事件处理。

    func populateTable()
    {
        table.startDataUpdate()

        self.table.addSection()
        //All the rows have the same accessory type, so define it at the table level
        table.info.accessoryType = .disclosureIndicator

        table += HSTVRowInfo(title:"Randoms") {
            (rowInfo) in
            print("Clicked on row 1")
        }

        table += HSTVRowInfo(title:"Blocks (first half)") {
            (rowInfo) in
            print("Clicked on row 2")
        }

        table += HSTVRowInfo(title:"Blocks (second half)") {
            (rowInfo) in
            print("Clicked on row 3")
        }

        self.table.applyDataUpdate()
    }

Demo table

使用继承进行自定义

每个单元格都通过响应链处理

HSTVRowInfo -> HSTVSectionInfo -> HSTVTableInfo

因此,例如,要获取行的标题颜色,表格首先检查 HSTVRowInfo 上是否设置了 titleColor。 如果该值为空,则检查 HSTVSectionInfo,如果该值也为空,则检查 HSTVTableInfo。

这意味着对于适用于整个表格或节的内容,您可以在顶层设置一次 - 并且仍然可以在每行级别覆盖特定值。

自定义显示逻辑

您可以使用标准的 setter(title、subtitle、style 等)自定义显示。

    var row = HSTVRowInfo(title:"MyTitle", subtitle:"My Subtitle")
    row.titleColor = .red
    row.leftImageName = "MyImageName"

    table += row

或者使用 afterCreate 或 beforeDisplay 处理程序。

   var row = HSTVRowInfo(title:"MyTitle", subtitle:"My Subtitle")
   row.styleAfterCreateHandler = {
       row,cell in

       cell.myCustomLabel.text = "TextForCustomLabel"
   }

   table += row

注意 - 如果您对多个单元格执行相同的自定义操作 - 您可以使用表格或节级别的处理程序,并从 customInfo 属性访问您需要的信息。

   table.info.styleAfterCreateHandler = {
       row,cell in

       cell.myCustomLabel.text = row.customInfo!.customLabelText
   }

自定义单元格

  1. 您可以通过设置 HSTVRowInfo.style 来使用标准的单元格格式。

  2. 您可以使用 HSTVRowInfo.nib 指定自定义 nib。

  3. 您可以通过子类化 HSTVRowInfo 并重写来创建自定义单元格。

    func makeNewCell(_ identifier: String, inheritedStyle: UITableViewCellStyle) -> UITableViewCell

简单的设置处理(对于设置表格)

我经常在我的应用程序中使用表格来设置 true/false 设置。 有一个自定义处理程序可以显示/隐藏复选标记,并在用户点击行时更新布尔 UserDefault。

	row.handleCheckmark(userDefault:"TestDefault",
                            checkedSubtitle: "Checked (user default true)",
                            uncheckedSubtitle: "UnChecked (user default false)")

过滤

您可以使用 filter 选项来动画显示和消失表格中的单元格。 当行被隐藏时,它的高度设置为 0,以便可以动画地消失。 在设计单元格时,您应该考虑这一点 - 如果单元格具有固定高度的视图,则动画会更快,这样在单元格向下动画时就不需要多次重新绘制。

例如 - 要根据搜索栏中的文本按标题过滤表格。

   func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {

       tableView.filter { (row) -> Bool in
           return row.title?.contains(string: searchText) ?? false
       }
   }

详细演示

Demo table

此函数完全定义了示例表格。

    func populateTable()
    {
        table.startDataUpdate()
        table.allowsSelectionDuringEditing=true

        // Provide defaults for all rows in the table
        // This will apply unless a value is set at a more specific level (section or row)
        table.info.subtitleColor = UIColor.lightGray
        table.info.subtitle="Table default subtitle"
        table.info.clickHandler = {row in
            //Default click handler prints the index path, updates the subtitle and redraws the row
            print("Table handler click: \(row.lastIndexPath)")
            row.subtitle="clicked at \(Date.init())"
            row.redrawCell(UITableViewRowAnimation.fade)
        };

        // Section
        // Add a section with a simple title
        //
        var section=self.table.addSection("Regular cells")
        // Provide some defaults for items in this section
        section.info.titleColor=UIColor.blue
        section.info.subtitleColor=UIColor.orange

        //First row has a simple click handler that reloads the table data
        //The number or rows is random - so you can see the effect of the reload
        var row=HSTVRowInfo(title:"Reload Table",subtitle: "Number of rows in first section is somewhat random")
        row.leftImageName="713-refresh-1"
        row.clickHandler = {
            [unowned self] (row) in
            self.populateTable()
        };
        table += row

        let numberOfRandoms=arc4random_uniform(6)
        //Random number of rows with the title 'Section One'
        //Odd rows get their subtitle from the table
        //Even rows have their own subtitle
        for i in 1...(2+numberOfRandoms) {
            row=HSTVRowInfo(title:"Section One: \(i)")
            if (i%2==0)
            {
                row.subtitle="subtitle \(Date.init())"
                row.clickHandler = {row in
                    print("Regular cell section click handler, \(i)")
                };
            }
            table += row
        }

        // Section
        // Simple swipe to delete row
        //
        self.table.addSection("Editable")
        row = HSTVRowInfo(title: "Swipe to delete")
        row.editingStyle=UITableViewCellEditingStyle.delete
        row.deleteHandler=row.simpleDeleteHandler
        table += row

        // Section
        // Row value is linked to the user default 'TestDefault'
        //
        self.table.addSection("Linked to default")
        row = HSTVRowInfo(title: "Linked to UserDefault 'TestDefault'")
        row.handleCheckmark(userDefault:"TestDefault",
                            checkedSubtitle: "Checked (user default true)",
                            uncheckedSubtitle: "UnChecked (user default false)")
        table += row

        //Row value is linked to the user default 'TestDefault', but checkmark shows when value is false
        row = HSTVRowInfo(title: "Linked to UserDefault 'TestOppositeDefault'")
        row.handleCheckmark(userDefault:"TestOppositeDefault",
                            checkedSubtitle: "Checked (user default false)",
                            uncheckedSubtitle: "UnChecked (user default true)",
                            checkmarkShowsForFalse: true)
        table += row

        // Section
        // Various accessory views
        // (including coloured disclosure indicators)
        section=self.table.addSection("Accessory views")
        section.info.subtitle=""

        row = HSTVRowInfo(title:"Chevron")
        row.accessoryType = .disclosureIndicator
        row.leftImageName="04-squiggle"
        row.tintColor=UIColor.orange
        row.tintChevronDisclosures = true
        table += row


        row = HSTVRowInfo(title:"Chevron")
        row.accessoryType = .disclosureIndicator
        row.tintColor=UIColor.orange
        table += row


        row = HSTVRowInfo(title:"Disclosure")
        row.accessoryType = .detailDisclosureButton
        row.leftImageName="04-squiggle"
        row.leftImageColor=UIColor.purple
        row.tintColor=UIColor.orange
        row.tintChevronDisclosures = true
        row.accessoryClickHandler = {
            row in
            print ("Disclosure accessory clicked")
        }
        table += row

        row = HSTVRowInfo(title:"Checkmark")
        row.accessoryType = .checkmark
        table += row

        row = HSTVRowInfo(title:"Info")
        row.accessoryType = .detailButton
        row.accessoryClickHandler = {
            row in
            print ("Info accessory clicked")
        }
        table += row

//         Section
//         Row loaded from prototype cell
        section = self.table.addSection("Cell Prototype")
        section.info.reuseIdentifier = "ProtoCell"


        for i in 1...2 {
            let row=HSTVRowInfo(title:"One: \(i)")
            if (i%2==0)
            {
                row.subtitle="subtitle"
            }
            table += row
        }


        // Section
        // Row loaded from custom xib
        //
        section = self.table.addSection("Custom Xib")
        section.info.subtitle="Section Override"
        let myNib = UINib(nibName: "MyTableViewCell", bundle: nil)
        section.info.nib=myNib
        section.info.estimatedRowHeight=150

        for i in 1...2 {
            let row=HSTVRowInfo(title:"One: \(i)")
            if (i%2==0)
            {
                row.subtitle="subtitle"
            }
            table += row
        }

        // Section
        // Nil title for section makes the header invisibile
        // styleAfterCreate handler used to set custom background and override label colours
        //
        section=self.table.addSection(nil)
        for i in 1...2 {
            let row=HSTVRowInfo(title:"Section with no header \(i)")
            table += row
        }

        //style after create handler in this section customises the row in code
        //setting a reuseTag makes sure that this cell is not re-used elsewhere
        section.info.styleAfterCreateHandler = {
            row,cell in

            //os caches imageNamed results
            var image=UIImage(named:"tableRowBackground.png")
            image=image?.stretchableImage(withLeftCapWidth: 30, topCapHeight: 2)

            cell.backgroundView=UIImageView.init(image: image)

            cell.textLabel?.textColor=UIColor.white
            cell.detailTextLabel?.textColor=UIColor.white
        }
        section.info.reuseTag="orange"

        self.table.applyDataUpdate()
    }